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