View Javadoc

1   /*
2    * Copyright 2010 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may	obtain a copy of the License at
7    *
8    * 	http://www.osedu.org/licenses/ECL-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.student.contract.model.impl;
17  
18  import java.io.File;
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.Collections;
22  import java.util.Date;
23  import java.util.LinkedHashMap;
24  import java.util.LinkedHashSet;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Set;
28  
29  import org.kuali.student.contract.model.MessageStructure;
30  import org.kuali.student.contract.model.Service;
31  import org.kuali.student.contract.model.ServiceContractModel;
32  import org.kuali.student.contract.model.ServiceMethod;
33  import org.kuali.student.contract.model.ServiceMethodError;
34  import org.kuali.student.contract.model.ServiceMethodParameter;
35  import org.kuali.student.contract.model.ServiceMethodReturnValue;
36  import org.kuali.student.contract.model.XmlType;
37  import org.slf4j.Logger;
38  import org.slf4j.LoggerFactory;
39  
40  import com.thoughtworks.qdox.JavaDocBuilder;
41  import com.thoughtworks.qdox.model.Annotation;
42  import com.thoughtworks.qdox.model.DefaultDocletTagFactory;
43  import com.thoughtworks.qdox.model.DocletTag;
44  import com.thoughtworks.qdox.model.JavaClass;
45  import com.thoughtworks.qdox.model.JavaField;
46  import com.thoughtworks.qdox.model.JavaMethod;
47  import com.thoughtworks.qdox.model.JavaParameter;
48  import com.thoughtworks.qdox.model.Type;
49  import com.thoughtworks.qdox.model.annotation.AnnotationValue;
50  
51  /**
52   *
53   * @author nwright
54   */
55  public class ServiceContractModelQDoxLoader implements
56          ServiceContractModel {
57  	
58  	private static final Logger log = LoggerFactory.getLogger(ServiceContractModelQDoxLoader.class);
59  
60      private static final String LOCALE_KEY_LIST = "LocaleKeyList";
61      private static final String MESSAGE_GROUP_KEY_LIST = "MessageGroupKeyList";
62      private static final JavaClass STRING_JAVA_CLASS = new JavaClass(
63              "java.lang.String");
64      private List<String> sourceDirectories = null;
65      private List<Service> services = null;
66      private List<ServiceMethod> serviceMethods = null;
67      private Map<String, XmlType> xmlTypeMap = null;
68      private List<MessageStructure> messageStructures;
69      private boolean validateKualiStudent = true;
70  
71      public ServiceContractModelQDoxLoader(List<String> sourceDirectories) {
72          this.sourceDirectories = sourceDirectories;
73      }
74  
75      public ServiceContractModelQDoxLoader(List<String> sourceDirectories, boolean validateKualiStudent) {
76          this.sourceDirectories = sourceDirectories;
77          this.setValidateKualiStudent(validateKualiStudent);
78      }
79  
80      public boolean isValidateKualiStudent() {
81          return validateKualiStudent;
82      }
83  
84      public void setValidateKualiStudent(boolean validateKualiStudent) {
85          this.validateKualiStudent = validateKualiStudent;
86      }
87  
88      @Override
89      public List<ServiceMethod> getServiceMethods() {
90          if (this.serviceMethods == null) {
91              this.parse();
92          }
93          return this.serviceMethods;
94      }
95  
96      @Override
97      public List<String> getSourceNames() {
98          List<String> list = new ArrayList<String>(this.sourceDirectories.size());
99          for (String javaFile : this.sourceDirectories) {
100             list.add(javaFile);
101         }
102         return list;
103     }
104 
105     @Override
106     public List<Service> getServices() {
107         if (services == null) {
108             this.parse();
109         }
110         return services;
111     }
112 
113     @Override
114     public List<XmlType> getXmlTypes() {
115         if (xmlTypeMap == null) {
116             this.parse();
117         }
118         return new ArrayList<XmlType>(xmlTypeMap.values());
119     }
120 
121     @Override
122     public List<MessageStructure> getMessageStructures() {
123         if (messageStructures == null) {
124             this.parse();
125         }
126         return this.messageStructures;
127     }
128 
129     private void checkIfExists(String sourceDirectory) {
130         File file = new File(sourceDirectory);
131         if (!file.isDirectory()) {
132             throw new IllegalArgumentException(sourceDirectory + " is not a directory on disk");
133         }
134     }
135 
136     @SuppressWarnings("unchecked")
137 	private void parse() {
138 //  System.out.println ("ServiceContractModelQDoxLoader: Starting parse");
139         services = new ArrayList<Service>();
140         serviceMethods = new ArrayList<ServiceMethod>();
141         xmlTypeMap = new LinkedHashMap<String, XmlType>();
142         messageStructures = new ArrayList<MessageStructure>();
143         DefaultDocletTagFactory dtf = new DefaultDocletTagFactory();
144         JavaDocBuilder builder = new JavaDocBuilder(dtf);
145         for (String sourceDirectory : sourceDirectories) {
146             checkIfExists(sourceDirectory);
147             builder.addSourceTree(new File(sourceDirectory));
148         }
149         Set<JavaClass> mergedClasses = new LinkedHashSet<JavaClass>();
150         
151         for (JavaClass javaClass : builder.getClasses()) {
152             
153             if (!javaClass.getPackageName().contains("r1"))
154                 mergedClasses.add(javaClass);
155             else
156                 log.warn("excluding r1 class: " + javaClass.getFullyQualifiedName());
157             
158         }
159         
160         List<JavaClass>sortedClasses = new ArrayList<JavaClass>(mergedClasses);
161         
162         Collections.sort(sortedClasses);
163         
164         for (JavaClass javaClass : sortedClasses) {
165             if (!this.isServiceToProcess(javaClass)) {
166                 continue;
167             }
168 //   System.out.println ("processing service=" + javaClass.getName ());
169             Service service = new Service();
170             services.add(service);
171             service.setKey(javaClass.getName().substring(0, javaClass.getName().length()
172                     - "Service".length()));
173             service.setName(javaClass.getName());
174             service.setComments(this.calcComment(javaClass));
175             service.setUrl(this.calcServiceUrl(javaClass));
176             service.setVersion(this.calcVersion(javaClass));
177             service.setStatus("???");
178             service.setIncludedServices(calcIncludedServices(javaClass));
179             service.setImplProject(javaClass.getPackageName());
180 
181 //   for (DocletTag tag : javaClass.getTags ())
182 //   {
183 //    System.out.println ("ServiceContractModelQDoxLoader: Class: "
184 //                        + javaClass.getName () + " has tag=" + dump (
185 //      tag));
186 //   }
187             
188             JavaMethod[]  methods = getServiceMethods (javaClass);  
189             for (JavaMethod javaMethod : methods) {
190 
191                 ServiceMethod serviceMethod = new ServiceMethod();
192                 serviceMethods.add(serviceMethod);
193                 serviceMethod.setService(service.getKey());
194                 serviceMethod.setName(javaMethod.getName());
195                 serviceMethod.setDescription(calcMissing(javaMethod.getComment()));
196                 serviceMethod.setParameters(new ArrayList<ServiceMethodParameter>());
197                 serviceMethod.setImplNotes(calcImplementationNotes(javaMethod));
198                 serviceMethod.setDeprecated(isDeprecated(javaMethod));
199 //    for (DocletTag tag : javaMethod.getTags ())
200 //    {
201 //     System.out.println ("ServiceContractModelQDoxLoader: Method: "
202 //                         + service.getName () + "."
203 //                         + javaMethod.getName ()
204 //                         + " has tag=" + dump (tag));
205 //    }
206                 // parameters
207                 for (JavaParameter parameter : javaMethod.getParameters()) {
208                     ServiceMethodParameter param = new ServiceMethodParameter();
209                     serviceMethod.getParameters().add(param);
210                     param.setName(parameter.getName());
211                     param.setType(calcType(parameter.getType()));
212                     param.setDescription(calcMissing(
213                             calcParameterDescription(javaMethod,
214                             param.getName())));
215                     try {
216 						addXmlTypeAndMessageStructure(calcRealJavaClass(parameter.getType()),
217 						        serviceMethod.getService());
218 					} catch (Exception e) {
219 						String message= "failed to parameter message structure: " + serviceMethod.getService() + " : " + parameter.getType();
220 						
221 						log.error (message + " : " + e.getMessage());
222 						log.debug(message, e);
223 					}
224                 }
225                 // errors
226                 serviceMethod.setErrors(new ArrayList<ServiceMethodError>());
227                 for (Type exception : javaMethod.getExceptions()) {
228                     ServiceMethodError error = new ServiceMethodError();
229                     error.setType(this.calcType(exception.getJavaClass()));
230                     error.setDescription(calcMissing(
231                             calcExceptionDescription(javaMethod,
232                             error.getType())));
233                     error.setPackageName(exception.getJavaClass().getPackageName());
234                     error.setClassName(exception.getJavaClass().getName());
235                     serviceMethod.getErrors().add(error);
236                 }
237                 // return values
238                 ServiceMethodReturnValue rv = new ServiceMethodReturnValue();
239                 serviceMethod.setReturnValue(rv);
240                 Type returnType = null;
241                 try {
242                     returnType = javaMethod.getReturnType();
243                 } catch (NullPointerException ex) {
244                     System.out.println("Nullpinter getting return type: " + javaMethod.getCallSignature());
245                     returnType = null;
246                 }
247 
248                 rv.setType(calcType(returnType));
249                 rv.setDescription(calcMissing(this.calcReturnDescription(javaMethod)));
250                 if (returnType != null) {
251                     try {
252                     	
253                     	
254 						addXmlTypeAndMessageStructure(calcRealJavaClass(returnType),
255 						        serviceMethod.getService());
256 					} catch (Exception e) {
257 						String message = "failed to parse return type message structure: " + serviceMethod.getService() + " : " + returnType;
258 						
259 						log.error (message + " : " + e.getMessage());
260 						log.debug(message, e);
261 					}
262                 }
263             }
264         }
265     }
266 
267     private JavaMethod[] getServiceMethods(JavaClass javaClass) {
268 		
269     	Set<JavaMethod>methods = new LinkedHashSet<JavaMethod>();
270 		
271 		/*
272 		 * As inheritence is useful from a technical level but not as much from a business level
273 		 * This lets the union of the methods from all of the interfaces be listed in the contract.
274 		 */
275 		JavaClass[] interfaces = javaClass.getImplementedInterfaces();
276 		
277 		for (JavaClass intfc : interfaces) {
278 			
279 			if (!isAService(intfc)) {
280 				// only add the methods if this is not a service
281 				// e.g. extends ServiceBusinessLogic
282 				for (JavaMethod javaMethod : intfc.getMethods()) {
283 				
284 					methods.add(javaMethod);
285 				}
286 			}
287 			
288 		}
289 		
290 		// add the main service methods last incase we override any from the parent interfaces.
291 		// note the heirarchy is only guaranteed relative to the target service class (if there are two levels or more of 
292 		// heirarchy there is no guarantee the method ordering will be correct).
293 		for (JavaMethod javaMethod : javaClass.getMethods()) {
294 			
295 			methods.add(javaMethod);
296 		}
297 		
298 		return methods.toArray(new JavaMethod[] {});
299 	}
300 
301 	private boolean isServiceToProcess(JavaClass javaClass) {
302 //  System.out.println ("looking if javaClass is a service to process=" + javaClass.getName () + "=" + javaClass.getPackageName ());
303     	
304         if (!javaClass.getName().endsWith("Service")) {
305             return false;
306         }
307         if (javaClass.getPackageName().contains(".old.")) {
308 
309             return false;
310         }
311         if (javaClass.getPackageName().endsWith(".old")) {
312             return false;
313         }
314         for (Annotation annotation : javaClass.getAnnotations()) {
315 //   System.out.println ("looking for webservice tag=" + annotation.getType ().getJavaClass ().getName ());
316             if (annotation.getType().getJavaClass().getName().equals("WebService")) {
317 //    System.out.println ("Processing web service=" + javaClass.getPackageName ()
318 //                        + "." + javaClass.getName ());
319                 return true;
320             }
321         }
322         // This includes RICE's business object services even though they are not web services
323         // because often they are the only real service they have exposed and it helps to document
324         // them to see what the data really is like
325         if (javaClass.getName().endsWith("BoService")) {
326             return true;
327         }
328 //  System.out.println ("skipping service because it is not a web service="
329 //                      + javaClass.getPackageName () + "." + javaClass.getName ());
330         return false;
331     }
332 
333     private List<String> calcIncludedServices(JavaClass javaClass) {
334         List<String> includedServices = new ArrayList<String>();
335         for (JavaClass interfaceClass : javaClass.getImplementedInterfaces()) {
336             if (isAService(interfaceClass)) {
337 //            System.out.println("ServiceContractModelQDoxLoader:" + javaClass.getName()
338 //                    + " implements " + interfaceClass.getName());
339                 includedServices.add(interfaceClass.getName());
340             }
341         }
342         return includedServices;
343     }
344 
345     private boolean isAService(JavaClass interfaceClass) {
346         if (interfaceClass.getName().endsWith("Service")) {
347             return true;
348         }
349         return false;
350     }
351 
352     private String calcParameterDescription(JavaMethod method,
353             String parameterName) {
354         for (DocletTag tag : method.getTags()) {
355             if (tag.getName().equals("param")) {
356                 if (tag.getValue().startsWith(parameterName + " ")) {
357                     return tag.getValue().substring(parameterName.length() + 1);
358                 }
359             }
360         }
361         return null;
362     }
363 
364     private String calcExceptionDescription(JavaMethod serviceMethod,
365             String exceptionType) {
366         for (DocletTag tag : serviceMethod.getTags()) {
367             if (tag.getName().equals("throws")) {
368                 if (tag.getValue().startsWith(exceptionType + " ")) {
369                     return tag.getValue().substring(exceptionType.length() + 1);
370                 }
371             }
372         }
373         return null;
374     }
375 
376     private String calcReturnDescription(JavaMethod serviceMethod) {
377         for (DocletTag tag : serviceMethod.getTags()) {
378             if (tag.getName().equals("return")) {
379                 return tag.getValue();
380             }
381         }
382         return null;
383     }
384 
385     private String calcServiceUrl(JavaClass serviceClass) {
386         for (DocletTag tag : serviceClass.getTags()) {
387             if (tag.getName().equals("See")) {
388                 return tag.getValue();
389             }
390         }
391         return null;
392     }
393 
394     private void addXmlTypeAndMessageStructure(JavaClass messageStructureJavaClass,
395             String serviceKey) {
396         String name = calcType(messageStructureJavaClass);
397         XmlType xmlType = xmlTypeMap.get(name);
398         if (xmlType == null) {
399             xmlType = new XmlType();
400             xmlTypeMap.put(name, xmlType);
401             xmlType.setName(name);
402             xmlType.setDesc(this.calcMessageStructureDesc(messageStructureJavaClass));
403             xmlType.setDeprecated(isDeprecated (messageStructureJavaClass));
404             xmlType.setService(serviceKey);
405             xmlType.setVersion("IGNORE -- SAME AS SERVICE");
406             xmlType.setPrimitive(calcPrimitive(messageStructureJavaClass));
407             xmlType.setJavaPackage(calcJavaPackage(messageStructureJavaClass));
408             if (xmlType.getPrimitive().equals(XmlType.COMPLEX)) {
409                 addMessageStructure(messageStructureJavaClass, serviceKey);
410             }
411 
412         } else {
413             addServiceToList(xmlType, serviceKey);
414         }
415     }
416 
417     private boolean isDeprecated(JavaClass javaClass) {
418         for (Annotation annotation : javaClass.getAnnotations()) {
419             if (annotation.getType().getJavaClass().getName().equals(
420                     "Deprecated")) {
421                 return true;
422             }
423         }
424         return false;
425     }
426 
427     private String calcJavaPackage(JavaClass javaClass) {
428         String packageName = javaClass.getPackageName();
429         return packageName;
430     }
431 
432     private String calcMessageStructureDesc(JavaClass javaClass) {
433         {
434             String desc = javaClass.getComment();
435             if (desc != null) {
436                 if (!desc.isEmpty()) {
437                     return desc;
438                 }
439             }
440             JavaClass infcClass = this.getMatchingInfc(javaClass);
441             if (infcClass == null) {
442                 return null;
443             }
444             return infcClass.getComment();
445         }
446     }
447 
448     private JavaClass getMatchingInfc(JavaClass javaClass) {
449         // ks uses this pattern
450         String nameInfc = javaClass.getName();
451         if (nameInfc.endsWith("Info")) {
452             nameInfc = nameInfc.substring(0, nameInfc.length() - "Info".length())
453                     + "Infc";
454         }
455         String nameWithOutInfo = javaClass.getName();
456         // rice uses this pattern
457         if (nameWithOutInfo.endsWith("Info")) {
458             nameWithOutInfo = nameWithOutInfo.substring(0, nameWithOutInfo.length()
459                     - "Info".length());
460         }
461         for (JavaClass infc : javaClass.getImplementedInterfaces()) {
462             if (infc.getName().equals(nameInfc)) {
463 //                System.out.println("found matching interface " + infc.getName());
464                 return infc;
465             }
466             if (infc.getName().equals(nameWithOutInfo)) {
467                 return infc;
468             }
469         }
470         return null;
471     }
472 
473     private String calcPrimitive(JavaClass javaClass) {
474         if (this.isComplex(javaClass)) {
475             return XmlType.COMPLEX;
476         }
477         return "Primitive";
478     }
479 
480     private String initLower(String str) {
481         if (str == null) {
482             return null;
483         }
484         if (str.length() == 0) {
485             return str;
486         }
487         if (str.length() == 1) {
488             return str.toLowerCase();
489         }
490         return str.substring(0, 1).toLowerCase() + str.substring(1);
491     }
492 
493     private String initUpper(String str) {
494         if (str == null) {
495             return null;
496         }
497         if (str.length() == 0) {
498             return str;
499         }
500         if (str.length() == 1) {
501             return str.toUpperCase();
502         }
503         return str.substring(0, 1).toUpperCase() + str.substring(1);
504     }
505 
506     private Set<String> getShortNames(JavaClass messageStructureJavaClass) {
507         Set<String> fields = getFieldsUsingPropOrder(messageStructureJavaClass);
508         if (fields != null) {
509             return fields;
510         }
511         fields = new LinkedHashSet<String>();
512         for (JavaMethod method : messageStructureJavaClass.getMethods(true)) {
513             if (isSetterMethodToProcess(method, messageStructureJavaClass.getName())) {
514                 String shortName = this.calcShortNameFromSetter(method);
515                 fields.add(shortName);
516                 continue;
517             }
518             if (isGetterMethodToProcess(method, messageStructureJavaClass.getName())) {
519                 String shortName = this.calcShortNameFromGetter(method);
520                 fields.add(shortName);
521                 continue;
522             }
523         }
524         return fields;
525     }
526 
527     private Set<String> getFieldsUsingPropOrder(
528             JavaClass messageStructureJavaClass) {
529         for (Annotation annotation : messageStructureJavaClass.getAnnotations()) {
530             if (annotation.getType().getJavaClass().getName().equals("XmlType")) {
531                 AnnotationValue propOrderParam = annotation.getProperty("propOrder");
532                 if (propOrderParam == null) {
533                     continue;
534                 }
535                 Object propOrderValue = propOrderParam.getParameterValue();
536                 if (!(propOrderValue instanceof List)) {
537                     continue;
538                 }
539                 Set<String> fields = new LinkedHashSet<String>();
540                 for (Object value : (List<?>) propOrderValue) {
541                     if (value instanceof String) {
542                         String shortName = (String) value;
543                         shortName = this.stripQuotes(shortName);
544                         if (shortName.contains(".Elements.")) {
545                             String newShortName = getShortNameFromElements(shortName, messageStructureJavaClass);
546                             if (newShortName == null) {
547                                 continue;
548                             }
549                             shortName = newShortName;
550                         } else if (shortName.startsWith("CoreConstants.CommonElements.")) {
551                             String newShortName = getCoreConstants(shortName);
552                             if (newShortName == null) {
553                                 continue;
554                             }
555                             shortName = newShortName;
556                         }
557                         if (shortName.equals("_futureElements")) {
558                             continue;
559                         }
560                         shortName = this.initUpper(shortName);
561                         fields.add(shortName);
562                     }
563                 }
564                 return fields;
565             }
566         }
567         return null;
568     }
569 
570     private String getShortNameFromElements(String shortName, JavaClass messageStructureJavaClass) {
571         JavaClass elementsJavaClass = messageStructureJavaClass.getNestedClassByName("Elements");
572         if (elementsJavaClass == null) {
573             return null;
574         }
575         String fieldName = shortName.substring(shortName.indexOf(".Elements.") + ".Elements.".length());
576         JavaField field = elementsJavaClass.getFieldByName(fieldName);
577         String initExpr = field.getInitializationExpression();
578         return stripQuotes(initExpr);
579     }
580 
581     private String getCoreConstants(String shortName) {
582         if (shortName.endsWith("VERSION_NUMBER")) {
583             return "versionNumber";
584         }
585         if (shortName.endsWith("OBJECT_ID")) {
586             return "objectId";
587         }
588         if (shortName.endsWith("ACTIVE")) {
589             return "active";
590         }
591         if (shortName.endsWith("ACTIVE_FROM_DATE")) {
592             return "activeFromDate";
593         }
594         if (shortName.endsWith("ACTIVE_TO_DATE")) {
595             return "activeToDate";
596         }
597         if (shortName.endsWith("ATTRIBUTES")) {
598             return "attributes";
599         }
600         if (shortName.endsWith("FUTURE_ELEMENTS")) {
601             return "_futureElements";
602         }
603         throw new RuntimeException("Unknown shortName " + shortName);
604     }
605 
606     private void addMessageStructure(JavaClass messageStructureJavaClass,
607             String serviceKey) {
608         Set<JavaClass> subObjectsToAdd = new LinkedHashSet<JavaClass>();
609         for (String shortName : this.getShortNames(messageStructureJavaClass)) {
610             JavaMethod setterMethod = findSetterMethod(messageStructureJavaClass,
611                     shortName);
612             JavaMethod getterMethod = findGetterMethod(messageStructureJavaClass,
613                     shortName);
614             if (getterMethod == null) {
615                 if (this.validateKualiStudent) {
616                     throw new IllegalArgumentException("shortName has no corresponding getter method: "
617                             + messageStructureJavaClass.getFullyQualifiedName()
618                             + "." + shortName);
619                 }
620             }
621             JavaField beanField = this.findField(messageStructureJavaClass,
622                     shortName, setterMethod);
623             if (beanField == null) {
624                 String accessorType = getAccessorType(getterMethod);
625                 if ("XmlAccessType.FIELD".equals(accessorType)) {
626                     throw new IllegalArgumentException("Setter method has no corresponding bean field: "
627                             + messageStructureJavaClass.getName()
628                             + "." + getterMethod.getName());
629                 }
630             }
631             // overide the shortName if the bean field has an XmlAttribute name=xxx
632             // this catches the key=id switch
633             if (beanField != null) {
634                 for (Annotation annotation : beanField.getAnnotations()) {
635                     if (annotation.getType().getJavaClass().getName().equals("XmlAttribute")) {
636                         Object nameValue = annotation.getNamedParameter("name");
637                         if (nameValue != null) {
638                             shortName = stripQuotes(nameValue.toString());
639                         }
640                     }
641                 }
642             }
643             shortName = initLower(shortName);
644             MessageStructure ms = new MessageStructure();
645             messageStructures.add(ms);
646             ms.setXmlObject(messageStructureJavaClass.getName());
647             ms.setShortName(shortName);
648             ms.setId(ms.getXmlObject() + "." + ms.getShortName());
649             ms.setName(calcMissing(calcName(messageStructureJavaClass, getterMethod, setterMethod,
650                     beanField, shortName)));
651             ms.setType(calcType(messageStructureJavaClass, getterMethod, setterMethod, beanField, shortName));
652             if (ms.getType().equals("Object")) {
653                 System.out.println("WARNING " + ms.getId()
654                         + " has Object as it's type ==> Changing to String");
655                 ms.setType("String");
656             } else if (ms.getType().equals("ObjectList")) {
657                 System.out.println(
658                         "WARNING " + ms.getId()
659                         + " has a list of Objects as it's type ==> Changing to List of String");
660                 ms.setType("StringList");
661             }
662             ms.setXmlAttribute(this.calcXmlAttribute(beanField));
663             ms.setRequired(calcRequired(getterMethod, setterMethod, beanField));
664             ms.setReadOnly(calcReadOnly(getterMethod, setterMethod, beanField));
665             ms.setCardinality(this.calcCardinality(messageStructureJavaClass, getterMethod, setterMethod, beanField, shortName));
666             ms.setDescription(calcMissing(calcDescription(messageStructureJavaClass, getterMethod, setterMethod,
667                     beanField)));
668             ms.setImplNotes(calcImplementationNotes(getterMethod, setterMethod, beanField));
669             ms.setDeprecated(isDeprecated(getterMethod));
670             ms.setStatus("???");
671 //            if (ms.getId().equals("AcademicCalendarInfo.typeKey")) {
672 //                System.out.println("debug from here");
673 //            }
674             ms.setOverriden(this.calcOverridden(messageStructureJavaClass, getterMethod));
675             JavaClass subObjToAdd = this.calcRealJavaClassOfGetterReturn(getterMethod);
676             if (subObjToAdd != null) {
677 //                if (!subObjToAdd.isEnum()) {
678                 if (!subObjToAdd.getName().equals("Object")) {
679                     if (!subObjToAdd.getName().equals("LocaleKeyList")) {
680                         if (!subObjToAdd.getName().equals("MessageGroupKeyList")) {
681                             subObjectsToAdd.add(subObjToAdd);
682                         }
683                     }
684                 }
685 //                }
686             }
687         }
688         // now add all it's complex sub-objects if they haven't already been added
689         for (JavaClass subObjectToAdd : subObjectsToAdd) {
690             XmlType xmlType = xmlTypeMap.get(calcType(subObjectToAdd));
691             if (xmlType == null) {
692                 try {
693 					addXmlTypeAndMessageStructure(subObjectToAdd, serviceKey);
694 				} catch (Exception e) {
695 					String message = "failed to parse subobject structure: " + subObjectToAdd + " : " + serviceKey;
696 					// log into message
697 					log.error (message + " : " + e.getMessage());
698 					// log into debug log
699 					log.debug(message, e);
700 				}
701             } else {
702                 addServiceToList(xmlType, serviceKey);
703             }
704         }
705         return;
706     }
707 
708     private boolean calcOverridden(JavaClass mainClass, JavaMethod getterMethod) {
709         if (getterMethod == null) {
710             return false;
711         }
712         JavaMethod infcGetter = null;
713         if (getterMethod.getParentClass().isInterface()) {
714             infcGetter = getterMethod;
715         }
716         if (infcGetter == null) {
717             infcGetter = findInterfaceMethod(mainClass, getterMethod, false);
718         }
719         if (infcGetter == null) {
720             return false;
721         }
722         Annotation annotation = this.getAnnotation(infcGetter, null, null, "Override");
723         if (annotation != null) {
724             return true;
725         }
726         return false;
727     }
728 
729     private String calcComment(JavaClass javaClass) {
730         return this.calcComment(javaClass.getComment());
731     }
732 
733     private String calcComment(String comment) {
734         return this.parseCommentVersion(comment)[0];
735     }
736 
737     private String calcVersion(JavaClass javaClass) {
738         DocletTag tag = javaClass.getTagByName("version", true);
739         if (tag != null) {
740             return tag.getValue();
741         }
742         return this.calcVersion(javaClass.getComment());
743     }
744 
745     private String calcVersion(String comment) {
746         return this.parseCommentVersion(comment)[1];
747     }
748 
749     private String[] parseCommentVersion(String commentVersion) {
750         String[] parsed = new String[2];
751         if (commentVersion == null) {
752             return parsed;
753         }
754         commentVersion = commentVersion.trim();
755         int i = commentVersion.toLowerCase().indexOf("\nversion:");
756         if (i == -1) {
757             parsed[0] = commentVersion;
758             return parsed;
759         }
760         parsed[1] = commentVersion.substring(i + "\nversion:".length()).trim();
761         parsed[0] = commentVersion.substring(0, i).trim();
762 
763         return parsed;
764     }
765 
766     private Annotation getAnnotation(JavaMethod getterMethod,
767             JavaMethod setterMethod, JavaField beanField, String type) {
768         if (beanField != null) {
769 
770             for (Annotation annotation : beanField.getAnnotations()) {
771                 if (annotation.getType().getJavaClass().getName().equals(type)) {
772                     return annotation;
773                 }
774             }
775         }
776         if (getterMethod != null) {
777 
778             for (Annotation annotation : getterMethod.getAnnotations()) {
779                 if (annotation.getType().getJavaClass().getName().equals(type)) {
780                     return annotation;
781                 }
782             }
783         }
784         if (setterMethod != null) {
785 
786             for (Annotation annotation : setterMethod.getAnnotations()) {
787                 if (annotation.getType().getJavaClass().getName().equals(type)) {
788                     return annotation;
789                 }
790             }
791         }
792         return null;
793     }
794 
795     private String calcRequired(JavaMethod getterMethod,
796             JavaMethod setterMethod, JavaField beanField) {
797         Annotation annotation = this.getAnnotation(getterMethod, setterMethod, beanField, "XmlElement");
798         if (annotation == null) {
799             annotation = this.getAnnotation(getterMethod, setterMethod, beanField, "XmlAttribute");
800         }
801         if (annotation != null) {
802             Object required = annotation.getNamedParameter("required");
803             if (required != null) {
804                 if (required.toString().equalsIgnoreCase("true")) {
805                     return "Required";
806                 }
807             }
808         }
809         if (getterMethod != null) {
810             DocletTag tag = getterMethod.getTagByName("required", true);
811             if (tag != null) {
812                 if (tag.getValue() == null) {
813                     return "Required";
814                 }
815                 String required = "Required " + tag.getValue();
816                 return required.trim();
817             }
818         }
819         return null;
820     }
821 
822     private String calcReadOnly(JavaMethod getterMethod,
823             JavaMethod setterMethod, JavaField beanField) {
824         if (getterMethod != null) {
825             DocletTag tag = getterMethod.getTagByName("readOnly", true);
826             if (tag != null) {
827                 if (tag.getValue() == null) {
828                     return "Read only";
829                 }
830                 String readOnly = "Read only " + tag.getValue();
831                 return readOnly.trim();
832             }
833         }
834         return null;
835     }
836 
837     private String calcImplementationNotes(JavaMethod serviceMethod) {
838         StringBuilder bldr = new StringBuilder();
839         String newLine = "";
840         for (DocletTag tag : serviceMethod.getTagsByName("impl", true)) {
841             bldr.append(newLine);
842             newLine = "\n";
843             String value = tag.getValue();
844             bldr.append(value);
845         }
846         if (hasOverride(serviceMethod)) {
847             boolean matchJustOnName = true;
848             JavaMethod overriddenMethod = findInterfaceMethod(serviceMethod.getParentClass(), serviceMethod, matchJustOnName);
849             if (overriddenMethod == null) {
850                 // do it again so we can debug
851                 findInterfaceMethod(serviceMethod.getParentClass(), serviceMethod, true);
852                 throw new NullPointerException("could not find overridden method or method that has @Override annotation " + serviceMethod.getCallSignature());
853             }
854             bldr.append(newLine);
855             newLine = "\n";
856             bldr.append("Overridden method should be implemented in helper: ");
857             bldr.append(overriddenMethod.getParentClass().getName());
858         }
859         if (bldr.length() == 0) {
860             return null;
861         }
862         return bldr.toString();
863     }
864 
865     private boolean hasOverride(JavaMethod serviceMethod) {
866         for (Annotation annotation : serviceMethod.getAnnotations()) {
867             if (annotation.getType().getJavaClass().getName().equals(
868                     "Override")) {
869                 return true;
870             }
871         }
872         return false;
873     }
874 
875     private boolean isDeprecated(JavaMethod serviceMethod) {
876         for (Annotation annotation : serviceMethod.getAnnotations()) {
877             if (annotation.getType().getJavaClass().getName().equals(
878                     "Deprecated")) {
879                 return true;
880             }
881         }
882         return false;
883     }
884 
885     private String calcImplementationNotes(JavaMethod getterMethod,
886             JavaMethod setterMethod, JavaField beanField) {
887         if (getterMethod != null) {
888             DocletTag tag = getterMethod.getTagByName("impl", true);
889             if (tag != null) {
890                 return tag.getValue();
891             }
892         }
893         return null;
894     }
895 
896     private String calcNameFromShortName(String shortName) {
897         StringBuilder bldr = new StringBuilder(shortName.length() + 3);
898         char c = shortName.charAt(0);
899         bldr.append(Character.toUpperCase(c));
900         boolean lastWasUpper = true;
901         for (int i = 1; i < shortName.length(); i++) {
902             c = shortName.charAt(i);
903             if (Character.isUpperCase(c)) {
904                 if (!lastWasUpper) {
905                     bldr.append(" ");
906                 }
907             } else {
908                 lastWasUpper = false;
909             }
910             bldr.append(c);
911         }
912         return bldr.toString();
913     }
914 
915     private String calcName(JavaClass mainClass, JavaMethod getterMethod,
916             JavaMethod setterMethod, JavaField beanField, String shortName) {
917         String name = this.calcNameFromTag(getterMethod, setterMethod, beanField);
918         if (name != null) {
919             return name;
920         }
921         name = this.calcNameFromNameEmbeddedInDescription(mainClass, getterMethod, setterMethod, beanField);
922         if (name != null) {
923             return name;
924         }
925         return this.calcNameFromShortName(shortName);
926     }
927 
928     private String calcNameFromTag(JavaMethod getterMethod,
929             JavaMethod setterMethod, JavaField beanField) {
930         if (getterMethod != null) {
931             DocletTag tag = getterMethod.getTagByName("name", true);
932             if (tag != null) {
933                 return tag.getValue();
934             }
935         }
936         return null;
937     }
938 
939     private String calcNameFromNameEmbeddedInDescription(JavaClass mainClass, JavaMethod getterMethod,
940             JavaMethod setterMethod, JavaField beanField) {
941         String nameDesc = this.calcMethodComment(mainClass, getterMethod, setterMethod,
942                 beanField);
943         String[] parsed = parseNameDesc(nameDesc);
944         return parsed[0];
945     }
946 
947     private String[] parseNameDesc(String nameDesc) {
948         String[] parsed = new String[2];
949         if (nameDesc == null) {
950             return parsed;
951         }
952         nameDesc = nameDesc.trim();
953         if (!nameDesc.startsWith("Name:")) {
954             parsed[1] = nameDesc;
955             return parsed;
956         }
957         nameDesc = nameDesc.substring("Name:".length()).trim();
958         int i = nameDesc.indexOf("\n");
959         if (i == -1) {
960             parsed[0] = nameDesc.trim();
961             return parsed;
962         }
963         parsed[0] = nameDesc.substring(0, i).trim();
964         parsed[1] = nameDesc.substring(i).trim();
965         return parsed;
966     }
967 
968     private String calcDescription(JavaClass mainClass, JavaMethod getterMethod,
969             JavaMethod setterMethod, JavaField beanField) {
970         String nameDesc = this.calcMethodComment(mainClass, getterMethod, setterMethod,
971                 beanField);
972         String[] parsed = parseNameDesc(nameDesc);
973         return parsed[1];
974     }
975 
976     private String calcMethodComment(JavaClass mainClass, JavaMethod getterMethod,
977             JavaMethod setterMethod,
978             JavaField beanField) {
979         String desc = null;
980         if (getterMethod != null) {
981             desc = getterMethod.getComment();
982             if (isCommentNotEmpty(desc)) {
983                 return desc;
984             }
985         }
986         if (setterMethod != null) {
987             desc = setterMethod.getComment();
988             if (isCommentNotEmpty(desc)) {
989                 return desc;
990             }
991         }
992         if (beanField != null) {
993             desc = beanField.getComment();
994             if (isCommentNotEmpty(desc)) {
995                 return desc;
996             }
997         }
998         desc = calcMethodCommentRecursively(mainClass, getterMethod);
999         if (isCommentNotEmpty(desc)) {
1000             return desc;
1001         }
1002         desc = calcMethodCommentRecursively(mainClass, setterMethod);
1003         if (isCommentNotEmpty(desc)) {
1004             return desc;
1005         }
1006         return null;
1007     }
1008 
1009     private String calcMethodCommentRecursively(JavaClass mainClass, JavaMethod method) {
1010         if (method == null) {
1011             return null;
1012         }
1013         String desc = method.getComment();
1014         if (isCommentNotEmpty(desc)) {
1015             return desc;
1016         }
1017         JavaMethod infcMethod = findInterfaceMethod(mainClass, method, false);
1018         if (infcMethod != null) {
1019             desc = infcMethod.getComment();
1020             if (isCommentNotEmpty(desc)) {
1021                 return desc;
1022             }
1023         }
1024         JavaMethod superMethod = findSuperMethod(method);
1025         if (superMethod != null) {
1026             desc = superMethod.getComment();
1027             if (isCommentNotEmpty(desc)) {
1028                 return desc;
1029             }
1030         }
1031         return null;
1032     }
1033 
1034     private JavaMethod findSuperMethod(JavaMethod method) {
1035 //        System.out.println("Searching for super method for "
1036 //                + method.getParentClass().getName() + "."
1037 //                + method.getCallSignature());
1038         for (JavaMethod superMethod : method.getParentClass().getMethods(true)) {
1039             if (method.equals(superMethod)) {
1040                 continue;
1041             }
1042             if (method.getCallSignature().equals(superMethod.getCallSignature())) {
1043                 return superMethod;
1044             }
1045         }
1046         return null;
1047     }
1048 
1049     private JavaMethod findInterfaceMethod(JavaClass mainClass, JavaMethod method, boolean matchJustOnName) {
1050         String callSig = method.getCallSignature();
1051         if (matchJustOnName) {
1052             callSig = method.getName();
1053         }
1054         JavaClass classToSearch = mainClass;
1055 //        log ("Searching mainClass " + classToSearch.getName() + " for " + callSig, callSig);
1056         while (true) {
1057             for (JavaClass infcClass : classToSearch.getImplementedInterfaces()) {
1058                 JavaMethod meth = this.findMethodOnInterfaceRecursively(infcClass, callSig, matchJustOnName);
1059                 if (meth != null) {
1060 //                    recursionCntr = 0;
1061                     return meth;
1062                 }
1063             }
1064             JavaClass superClass = classToSearch.getSuperJavaClass();
1065             if (superClass == null) {
1066 //                recursionCntr = 0;                
1067 //                log ("Did not find " + callSig + " on " + mainClass, callSig); 
1068                 return null;
1069             }
1070             classToSearch = superClass;
1071 //            log ("Searching superClass " + classToSearch.getName() + " for " + callSig, callSig);                
1072         }
1073     }
1074 
1075 //    private void log (String message, String callSig) {
1076 //        if (callSig.equalsIgnoreCase("getTypeKey()")) {
1077 //            for (int i = 0; i < this.recursionCntr; i++) {
1078 //                System.out.print (" ");
1079 //            }
1080 //            System.out.println (message);
1081 //        }
1082 //    }
1083 //    private int recursionCntr = 0;
1084     private JavaMethod findMethodOnInterfaceRecursively(JavaClass infcClass, String callSig, boolean matchJustOnName) {
1085 //        recursionCntr++;
1086 //        log ("Searching interface " + infcClass.getName() + " for " + callSig, callSig);
1087         for (JavaMethod infcMethod : infcClass.getMethods()) {
1088             if (callSig.equals(infcMethod.getCallSignature())) {
1089 //                log (callSig + " found on " + infcClass.getName() + "!!!!!!!!!!!!!!!!", callSig); 
1090 //                recursionCntr--;
1091                 return infcMethod;
1092             }
1093             if (matchJustOnName) {
1094                 if (callSig.equals(infcMethod.getName())) {
1095                     return infcMethod;
1096                 }
1097             }
1098         }
1099         for (JavaClass subInfc : infcClass.getImplementedInterfaces()) {
1100 //            log ("Searching  sub-interface " + subInfc.getName() + " for " + callSig, callSig);
1101             JavaMethod infcMethod = findMethodOnInterfaceRecursively(subInfc, callSig, matchJustOnName);
1102             if (infcMethod != null) {
1103 //                recursionCntr--;
1104                 return infcMethod;
1105             }
1106         }
1107 //        log (callSig + " not found on " + infcClass.getName(), callSig);
1108 //        this.recursionCntr--;
1109         return null;
1110     }
1111 
1112     private boolean isCommentNotEmpty(String desc) {
1113         if (desc == null) {
1114             return false;
1115         }
1116         if (desc.trim().isEmpty()) {
1117             return false;
1118         }
1119         if (desc.contains("@inheritDoc")) {
1120             return false;
1121         }
1122         return true;
1123     }
1124 
1125     private String getAccessorType(JavaMethod method) {
1126         String accessorType = getAccessorType(method.getAnnotations());
1127         if (accessorType != null) {
1128             return accessorType;
1129         }
1130         accessorType = getAccessorType(method.getParentClass().getAnnotations());
1131         return accessorType;
1132     }
1133 
1134     private String getAccessorType(Annotation[] annotations) {
1135         for (Annotation annotation : annotations) {
1136             if (annotation.getType().getJavaClass().getName().equals(
1137                     "XmlAccessorType")) {
1138 //    System.out.println ("Looking for XmlAccessorType annotation = "
1139 //                        + annotation.getParameterValue ());
1140                 return annotation.getParameterValue().toString();
1141             }
1142         }
1143         return null;
1144     }
1145 
1146     private String stripQuotes(String str) {
1147         if (str.startsWith("\"")) {
1148             str = str.substring(1);
1149         }
1150         if (str.endsWith("\"")) {
1151             str = str.substring(0, str.length() - 1);
1152         }
1153         return str;
1154     }
1155 
1156     private String calcMissing(String str) {
1157         if (str == null) {
1158             return "???";
1159         }
1160         if (str.trim().isEmpty()) {
1161             return "???";
1162         }
1163         return str;
1164     }
1165 
1166     private void addServiceToList(XmlType xmlType, String serviceKey) {
1167         if (!xmlType.getService().contains(serviceKey)) {
1168             xmlType.setService(xmlType.getService() + ", " + serviceKey);
1169         }
1170     }
1171 
1172     private String calcXmlAttribute(JavaField beanField) {
1173         if (beanField == null) {
1174             // TODO: worry about checking for this annotation on the method for non-field based AccessorTypes
1175             return "No";
1176         }
1177         for (Annotation annotation : beanField.getAnnotations()) {
1178             if (annotation.getType().getJavaClass().getName().equals("XmlAttribute")) {
1179                 return "Yes";
1180             }
1181         }
1182         return "No";
1183     }
1184 
1185     private JavaField findField(JavaClass javaClass, String shortName,
1186             JavaMethod setterMethod) {
1187         JavaField field = findField(javaClass, shortName);
1188         if (field != null) {
1189             return field;
1190         }
1191         if (setterMethod != null) {
1192             String paramName = setterMethod.getParameters()[0].getName();
1193             if (paramName.equalsIgnoreCase(shortName)) {
1194                 return null;
1195             }
1196             return findField(javaClass, paramName);
1197         }
1198         return null;
1199     }
1200 
1201     private JavaField findField(JavaClass javaClass, String name) {
1202         if (name == null) {
1203             return null;
1204         }
1205         for (JavaField field : javaClass.getFields()) {
1206             if (field.getName().equalsIgnoreCase(name)) {
1207                 return field;
1208             }
1209             // TODO: check for shortNames that already start with is so we don't check for isIsEnrollable
1210             if (field.getName().equals("is" + name)) {
1211                 return field;
1212             }
1213         }
1214         JavaClass superClass = javaClass.getSuperJavaClass();
1215         if (superClass == null) {
1216             return null;
1217         }
1218         return findField(superClass, name);
1219     }
1220 
1221     private JavaMethod findGetterMethod(JavaClass msClass, String shortName) {
1222         for (JavaMethod method : msClass.getMethods(true)) {
1223             if (method.getName().equalsIgnoreCase("get" + shortName)) {
1224                 return method;
1225             }
1226             if (method.getName().toLowerCase().startsWith("is")) {
1227                 if (method.getName().equalsIgnoreCase("is" + shortName)) {
1228                     return method;
1229                 }
1230                 // shortName already has "is" in it
1231                 if (method.getName().equalsIgnoreCase(shortName)) {
1232                     return method;
1233                 }
1234             }
1235             // TODO: followup on KimEntityResidencyInfo.getInState
1236             if (method.getName().equalsIgnoreCase("getInState") && shortName.equalsIgnoreCase(
1237                     "InStateFlag")) {
1238                 return method;
1239             }
1240         }
1241         return null;
1242     }
1243 
1244     private JavaMethod findSetterMethod(JavaClass msClass, String shortName) {
1245         for (JavaMethod method : msClass.getMethods(true)) {
1246             if (method.getName().equals("set" + shortName)) {
1247                 return method;
1248             }
1249             // TODO: check for shortNames that already start with is so we don't check for isIsEnrollable
1250             if (method.getName().equals("setIs" + shortName)) {
1251                 return method;
1252             }
1253             // TODO: followup on KimEntityResidencyInfo.getInState
1254             if (method.getName().equals("setInStateFlag") && shortName.equals(
1255                     "InState")) {
1256                 return method;
1257             }
1258         }
1259         return null;
1260     }
1261     private static final String[] SETTER_METHODS_TO_SKIP = {
1262         // Somebody put "convenience" methods on the validation result info
1263         "ValidationResultInfo.setWarning",
1264         "ValidationResultInfo.setError",
1265         // not on original wiki but still defined as a method but not backed by a field so not in wsdl
1266         "CredentialProgramInfo.setDiplomaTitle",
1267         // synonym for the official of setCredentialType
1268         "CredentialProgramInfo.setType",
1269         // not on original wiki but still defined as a method but not backed by a field so not in wsdl
1270         "CredentialProgramInfo.setHegisCode",
1271         "CredentialProgramInfo.setCip2000Code",
1272         "CredentialProgramInfo.setCip2010Code",
1273         "CredentialProgramInfo.setSelectiveEnrollmentCode",
1274         "CoreProgramInfo.setDiplomaTitle",
1275         // synonym for the official of setCredentialType
1276         //  "CoreProgramInfo.setType",
1277         // not on original wiki but still defined as a method but not backed by a field so not in wsdl
1278         "CoreProgramInfo.setHegisCode",
1279         "CoreProgramInfo.setCip2000Code",
1280         "CoreProgramInfo.setCip2010Code",
1281         "CoreProgramInfo.setSelectiveEnrollmentCode",
1282         "WhenConstraint.setValue"
1283     };
1284     private static final String[] GETTER_METHODS_TO_SKIP = {
1285         // Somebody put "convenience" methods on the validation result info
1286         "ValidationResultInfo.getWarning",
1287         "ValidationResultInfo.getError",
1288         // not on original wiki but still defined as a method but not backed by a field so not in wsdl
1289         "CredentialProgramInfo.getDiplomaTitle",
1290         // synonym for the official of setCredentialType
1291         "CredentialProgramInfo.getType",
1292         // not on original wiki but still defined as a method but not backed by a field so not in wsdl
1293         "CredentialProgramInfo.getHegisCode",
1294         "CredentialProgramInfo.getCip2000Code",
1295         "CredentialProgramInfo.getCip2010Code",
1296         "CredentialProgramInfo.getSelectiveEnrollmentCode",
1297         "CoreProgramInfo.getDiplomaTitle",
1298         // synonym for the official of setCredentialType
1299         //  "CoreProgramInfo.setType",
1300         // not on original wiki but still defined as a method but not backed by a field so not in wsdl
1301         "CoreProgramInfo.getHegisCode",
1302         "CoreProgramInfo.getCip2000Code",
1303         "CoreProgramInfo.getCip2010Code",
1304         "CoreProgramInfo.getSelectiveEnrollmentCode",
1305         "WhenConstraint.getValue"
1306     };
1307 
1308     private boolean isSetterMethodToProcess(JavaMethod method, String className) {
1309         if (!method.getName().startsWith("set")) {
1310             return false;
1311         }
1312         if (method.getParameters().length != 1) {
1313             return false;
1314         }
1315         if (method.isPrivate()) {
1316             return false;
1317         }
1318         if (method.isProtected()) {
1319             return false;
1320         }
1321         if (method.isStatic()) {
1322             return false;
1323         }
1324         if (method.getParentClass().getPackageName().startsWith("java")) {
1325             return false;
1326         }
1327         String fullName = className + "." + method.getName();
1328         for (String skip : SETTER_METHODS_TO_SKIP) {
1329             if (skip.equals(fullName)) {
1330                 return false;
1331             }
1332         }
1333 //  if (method.getParentClass ().isInterface ())
1334 //  {
1335 //   return false;
1336 //  }
1337         for (Annotation annotation : method.getAnnotations()) {
1338             if (annotation.getType().getJavaClass().getName().equals("XmlTransient")) {
1339                 return false;
1340             }
1341         }
1342         return true;
1343     }
1344 
1345     private boolean isGetterMethodToProcess(JavaMethod method, String className) {
1346         if (!method.getName().startsWith("get")) {
1347             if (!method.getName().startsWith("is")) {
1348                 return false;
1349             }
1350         }
1351         if (method.getParameters().length != 0) {
1352             return false;
1353         }
1354         if (method.isPrivate()) {
1355             return false;
1356         }
1357         if (method.isProtected()) {
1358             return false;
1359         }
1360         if (method.isStatic()) {
1361             return false;
1362         }
1363         if (method.getParentClass().getPackageName().startsWith("java")) {
1364             return false;
1365         }
1366         String fullName = className + "." + method.getName();
1367         for (String skip : GETTER_METHODS_TO_SKIP) {
1368             if (skip.equals(fullName)) {
1369                 return false;
1370             }
1371         }
1372 //  if (method.getParentClass ().isInterface ())
1373 //  {
1374 //   return false;
1375 //  }
1376         for (Annotation annotation : method.getAnnotations()) {
1377             if (annotation.getType().getJavaClass().getName().equals("XmlTransient")) {
1378                 return false;
1379             }
1380         }
1381         return true;
1382     }
1383 
1384     private String calcShortNameFromSetter(JavaMethod method) {
1385         return method.getName().substring(3);
1386     }
1387 
1388     private String calcShortNameFromGetter(JavaMethod method) {
1389         if (method.getName().startsWith("get")) {
1390             return method.getName().substring(3);
1391         }
1392         if (method.getName().startsWith("is")) {
1393             return method.getName().substring(2);
1394         }
1395         throw new IllegalArgumentException(method.getName()
1396                 + " does not start with is or get");
1397     }
1398 
1399     private String calcCardinality(JavaClass mainClass, JavaMethod getterMethod,
1400             JavaMethod setterMethod, JavaField beanField, String shortName) {
1401         if (isReturnACollection(mainClass, getterMethod, setterMethod, beanField, shortName)) {
1402             return "Many";
1403         }
1404         return "One";
1405     }
1406 
1407     private boolean isReturnACollection(JavaClass mainClass, JavaMethod getterMethod,
1408             JavaMethod setterMethod, JavaField beanField, String shortName) {
1409         if (getterMethod != null) {
1410             return isCollection(getterMethod.getReturnType());
1411         }
1412         if (beanField != null) {
1413             return isCollection(beanField.getType());
1414         }
1415         // TODO: check setterMethod
1416         return false;
1417     }
1418 
1419     private boolean isCollection(Type type) {
1420         JavaClass javaClass = type.getJavaClass();
1421         return this.isCollection(javaClass);
1422     }
1423 
1424     private boolean isCollection(JavaClass javaClass) {
1425         if (javaClass.getName().equals("LocalKeyList")) {
1426             return true;
1427         }
1428         if (javaClass.getName().equals("MessageGroupKeyList")) {
1429             return true;
1430         }
1431         if (javaClass.getName().equals(List.class.getSimpleName())) {
1432             return true;
1433         }
1434         if (javaClass.getName().equals(ArrayList.class.getSimpleName())) {
1435             return true;
1436         }
1437         if (javaClass.getName().equals(Collection.class.getSimpleName())) {
1438             return true;
1439         }
1440         if (javaClass.getName().equals(Set.class.getSimpleName())) {
1441             return true;
1442         }
1443         return false;
1444     }
1445 
1446     private String calcType(JavaClass mainClass, JavaMethod getterMethod,
1447             JavaMethod setterMethod, JavaField beanField, String shortName) {
1448         if (getterMethod != null) {
1449             return calcTypeOfGetterMethodReturn(getterMethod);
1450         }
1451         if (beanField != null) {
1452             Type type = beanField.getType();
1453             return calcType(type);
1454         }
1455         // TODO: calc type based on the setterMethod
1456         return null;
1457     }
1458 
1459     private String calcTypeOfGetterMethodReturn(JavaMethod getterMethod) {
1460         Type type = getterMethod.getReturnType();
1461         return calcType(type);
1462     }
1463 
1464     private String calcType(Type type) {
1465         if (type == null) {
1466             return "void";
1467         }
1468         if (isCollection(type.getJavaClass())) {
1469             return calcType(calcRealJavaClass(type)) + "List";
1470         }
1471         return calcType(calcRealJavaClass(type));
1472     }
1473 
1474     private String calcType(JavaClass javaClass) {
1475         if (javaClass.isEnum()) {
1476             // TODO: instead of hand mapping this take it based on the class in the @XmlEnum(String.class) tag
1477             if (javaClass.getName().equals("ErrorLevel")) {
1478                 return "Integer";
1479             }
1480             if (javaClass.getName().equals("StatementOperatorTypeKey")) {
1481                 return "String";
1482             }
1483             if (javaClass.getName().equals("WriteAccess")) {
1484                 return "String";
1485             }
1486             if (javaClass.getName().equals("Widget")) {
1487                 return "String";
1488             }
1489             if (javaClass.getName().equals("DataType")) {
1490                 return "String";
1491             }
1492             if (javaClass.getName().equals("SortDirection")) {
1493                 return "String";
1494             }
1495             if (javaClass.getName().equals("Usage")) {
1496                 return "String";
1497             }
1498             if (javaClass.getName().equals("StatementOperator")) {
1499                 return "String";
1500             }
1501         }
1502         // this is messed up instead of list of strings it is an object with a list of strings
1503         if (javaClass.getName().equals(LOCALE_KEY_LIST)) {
1504             return "StringList";
1505         }
1506         if (javaClass.getName().equals(MESSAGE_GROUP_KEY_LIST)) {
1507             return "StringList";
1508         }
1509         // TODO: figure out why rice stuff translates like this junk?
1510         if (javaClass.getName().equals("java$util$Map")) {
1511             return "Map<String, String>";
1512         }
1513         if (javaClass.getName().equals("Map")) {
1514             // TODO: make sure it is in fact a String,String map
1515             return "Map<String, String>";
1516         }
1517         return javaClass.getName();
1518     }
1519 
1520     private JavaClass calcRealJavaClassOfGetterReturn(JavaMethod getterMethod) {
1521         if (getterMethod == null) {
1522             return null;
1523         }
1524         Type type = getterMethod.getReturnType();
1525         return this.calcRealJavaClass(type);
1526     }
1527 
1528     private JavaClass calcRealJavaClass(Type type) {
1529         if (type == null) {
1530             return null;
1531         }
1532         JavaClass javaClass = type.getJavaClass();
1533         if (javaClass.getName().equals(LOCALE_KEY_LIST)) {
1534             return STRING_JAVA_CLASS;
1535         }
1536         if (javaClass.getName().equals(MESSAGE_GROUP_KEY_LIST)) {
1537             return STRING_JAVA_CLASS;
1538         }
1539         if (!this.isCollection(javaClass)) {
1540             return javaClass;
1541         }
1542 
1543 //  for (Type t : type.getActualTypeArguments ())
1544 //  {
1545 //   System.out.println ("ServiceContractModelQDoxLoader: type arguments = "
1546 //                       + t.toString ());
1547 //  }
1548 
1549         Type[]collectionTypeArguments = type.getActualTypeArguments();
1550         
1551         if (collectionTypeArguments == null)
1552         	return new JavaClass (Object.class.getName());
1553         else
1554         	return collectionTypeArguments[0].getJavaClass();
1555     }
1556 
1557     private boolean isComplex(JavaClass javaClass) {
1558         if (javaClass.isEnum()) {
1559             return false;
1560         }
1561         if (javaClass.getName().equals(String.class.getSimpleName())) {
1562             return false;
1563         }
1564         if (javaClass.getName().equals(Integer.class.getSimpleName())) {
1565             return false;
1566         }
1567         if (javaClass.getName().equals(Date.class.getSimpleName())) {
1568             return false;
1569         }
1570         if (javaClass.getName().equals(Long.class.getSimpleName())) {
1571             return false;
1572         }
1573         if (javaClass.getName().equals(Boolean.class.getSimpleName())) {
1574             return false;
1575         }
1576         if (javaClass.getName().equals(Double.class.getSimpleName())) {
1577             return false;
1578         }
1579         if (javaClass.getName().equals(Float.class.getSimpleName())) {
1580             return false;
1581         }
1582         if (javaClass.getName().equals(int.class.getSimpleName())) {
1583             return false;
1584         }
1585         if (javaClass.getName().equals(long.class.getSimpleName())) {
1586             return false;
1587         }
1588         if (javaClass.getName().equals(boolean.class.getSimpleName())) {
1589             return false;
1590         }
1591         if (javaClass.getName().equals(double.class.getSimpleName())) {
1592             return false;
1593         }
1594         if (javaClass.getName().equals(float.class.getSimpleName())) {
1595             return false;
1596         }
1597         if (javaClass.getName().equals(Map.class.getSimpleName())) {
1598             return false;
1599         }
1600 
1601         if (javaClass.getName().equals(String.class.getName())) {
1602             return false;
1603         }
1604         if (javaClass.getName().equals(Integer.class.getName())) {
1605             return false;
1606         }
1607         if (javaClass.getName().equals(Date.class.getName())) {
1608             return false;
1609         }
1610         if (javaClass.getName().equals(Long.class.getName())) {
1611             return false;
1612         }
1613         if (javaClass.getName().equals(Boolean.class.getName())) {
1614             return false;
1615         }
1616         if (javaClass.getName().equals(Double.class.getName())) {
1617             return false;
1618         }
1619         if (javaClass.getName().equals(Float.class.getName())) {
1620             return false;
1621         }
1622         if (javaClass.getName().equals(int.class.getName())) {
1623             return false;
1624         }
1625         if (javaClass.getName().equals(long.class.getName())) {
1626             return false;
1627         }
1628         if (javaClass.getName().equals(boolean.class.getName())) {
1629             return false;
1630         }
1631         if (javaClass.getName().equals(double.class.getName())) {
1632             return false;
1633         }
1634         if (javaClass.getName().equals(float.class.getName())) {
1635             return false;
1636         }
1637         if (javaClass.getName().equals(Map.class.getName())) {
1638             return false;
1639         }
1640         if (javaClass.getName().equals(LOCALE_KEY_LIST)) {
1641             return false;
1642         }
1643         if (javaClass.getName().equals(MESSAGE_GROUP_KEY_LIST)) {
1644             return false;
1645         }
1646         if (javaClass.getName().equals("java$util$Map")) {
1647             return false;
1648         }
1649         return true;
1650     }
1651 }