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