View Javadoc
1   /**
2    * Copyright 2004-2014 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.opensource.org/licenses/ecl2.php
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.*;
20  import com.thoughtworks.qdox.model.Type;
21  import com.thoughtworks.qdox.model.annotation.AnnotationValue;
22  import org.kuali.student.contract.model.*;
23  import org.slf4j.Logger;
24  import org.slf4j.LoggerFactory;
25  
26  import java.io.File;
27  import java.math.BigDecimal;
28  import java.util.*;
29  
30  /**
31   *
32   * @author nwright
33   */
34  public class ServiceContractModelQDoxLoader implements
35          ServiceContractModel {
36  	
37  	private static final Logger log = LoggerFactory.getLogger(ServiceContractModelQDoxLoader.class);
38  
39      private static final String LOCALE_KEY_LIST = "LocaleKeyList";
40      private static final String MESSAGE_GROUP_KEY_LIST = "MessageGroupKeyList";
41      private static final JavaClass STRING_JAVA_CLASS = new JavaClass(
42              "java.lang.String");
43      private List<String> sourceDirectories = null;
44      private List<Service> services = null;
45      private List<ServiceMethod> serviceMethods = null;
46      private Map<String, XmlType> xmlTypeMap = null;
47      private List<MessageStructure> messageStructures;
48      
49      public ServiceContractModelQDoxLoader(List<String> sourceDirectories) {
50          this.sourceDirectories = sourceDirectories;
51      }
52  
53      @Override
54      public List<ServiceMethod> getServiceMethods() {
55          if (this.serviceMethods == null) {
56              this.parse();
57          }
58          return this.serviceMethods;
59      }
60  
61      @Override
62      public List<String> getSourceNames() {
63          List<String> list = new ArrayList<String>(this.sourceDirectories.size());
64          for (String javaFile : this.sourceDirectories) {
65              list.add(javaFile);
66          }
67          return list;
68      }
69  
70      @Override
71      public List<Service> getServices() {
72          if (services == null) {
73              this.parse();
74          }
75          return services;
76      }
77  
78      @Override
79      public List<XmlType> getXmlTypes() {
80          if (xmlTypeMap == null) {
81              this.parse();
82          }
83          return new ArrayList<XmlType>(xmlTypeMap.values());
84      }
85  
86      @Override
87      public List<MessageStructure> getMessageStructures() {
88          if (messageStructures == null) {
89              this.parse();
90          }
91          return this.messageStructures;
92      }
93  
94      private void checkIfExists(String sourceDirectory) {
95          File file = new File(sourceDirectory);
96          if (!file.isDirectory()) {
97              throw new IllegalArgumentException(sourceDirectory + " is not a directory on disk");
98          }
99      }
100 
101     @SuppressWarnings("unchecked")
102 	private void parse() {
103 //  System.out.println ("ServiceContractModelQDoxLoader: Starting parse");
104         services = new ArrayList<Service>();
105         serviceMethods = new ArrayList<ServiceMethod>();
106         xmlTypeMap = new LinkedHashMap<String, XmlType>();
107         messageStructures = new ArrayList<MessageStructure>();
108         
109         DefaultDocletTagFactory dtf = new DefaultDocletTagFactory();
110         
111 		JavaDocBuilder builder = new JavaDocBuilder(dtf);
112         
113         for (String sourceDirectory : sourceDirectories) {
114             checkIfExists(sourceDirectory);
115             builder.addSourceTree(new File(sourceDirectory));
116         }
117         Set<JavaClass> mergedClasses = new LinkedHashSet<JavaClass>();
118         
119         for (JavaClass javaClass : builder.getClasses()) {
120             
121             if (!javaClass.getPackageName().contains("r1"))
122                 mergedClasses.add(javaClass);
123             else
124                 log.warn("excluding r1 class: " + javaClass.getFullyQualifiedName());
125             
126         }
127         
128         List<JavaClass>sortedClasses = new ArrayList<JavaClass>(mergedClasses);
129         
130         Collections.sort(sortedClasses);
131         
132         for (JavaClass javaClass : sortedClasses) {
133             if (!this.isServiceToProcess(javaClass)) {
134                 continue;
135             }
136 //   System.out.println ("processing service=" + javaClass.getName ());
137             Service service = new Service();
138             services.add(service);
139             service.setKey(calcServiceKey (javaClass));
140             service.setName(javaClass.getName());
141             service.setComments(this.calcComment(javaClass));
142             service.setUrl(this.calcServiceUrl(javaClass));
143             service.setVersion(this.calcVersion(javaClass));
144             service.setStatus("???");
145             service.setIncludedServices(calcIncludedServices(javaClass));
146             service.setImplProject(javaClass.getPackageName());
147 
148 //   for (DocletTag tag : javaClass.getTags ())
149 //   {
150 //    System.out.println ("ServiceContractModelQDoxLoader: Class: "
151 //                        + javaClass.getName () + " has tag=" + dump (
152 //      tag));
153 //   }
154             
155             JavaMethod[]  methods = getServiceMethods (javaClass);  
156             for (JavaMethod javaMethod : methods) {
157 
158                 ServiceMethod serviceMethod = new ServiceMethod();
159                 serviceMethods.add(serviceMethod);
160                 serviceMethod.setService(service.getKey());
161                 serviceMethod.setName(javaMethod.getName());
162                 serviceMethod.setDescription(calcMissing(javaMethod.getComment()));
163                 serviceMethod.setParameters(new ArrayList<ServiceMethodParameter>());
164                 serviceMethod.setImplNotes(calcImplementationNotes(javaMethod));
165                 serviceMethod.setDeprecated(isDeprecated(javaMethod));
166 //    for (DocletTag tag : javaMethod.getTags ())
167 //    {
168 //     System.out.println ("ServiceContractModelQDoxLoader: Method: "
169 //                         + service.getName () + "."
170 //                         + javaMethod.getName ()
171 //                         + " has tag=" + dump (tag));
172 //    }
173                 // parameters
174                 for (JavaParameter parameter : javaMethod.getParameters()) {
175                     ServiceMethodParameter param = new ServiceMethodParameter();
176                     serviceMethod.getParameters().add(param);
177                     param.setName(parameter.getName());
178                     param.setType(calcType(parameter.getType()));
179                     param.setDescription(calcMissing(
180                             calcParameterDescription(javaMethod,
181                             param.getName())));
182                     try {
183 						addXmlTypeAndMessageStructure(calcRealJavaClass(parameter.getType()),
184 						        serviceMethod.getService());
185 					} catch (Exception e) {
186 						String message= "failed to parameter message structure: " + serviceMethod.getService() + " : " + parameter.getType();
187 						
188 						log.error (message + " : " + e.getMessage());
189 						log.debug(message, e);
190 					}
191                 }
192                 // errors
193                 serviceMethod.setErrors(new ArrayList<ServiceMethodError>());
194                 for (Type exception : javaMethod.getExceptions()) {
195                     ServiceMethodError error = new ServiceMethodError();
196                     error.setType(this.calcType(exception.getJavaClass()));
197                     error.setDescription(calcMissing(
198                             calcExceptionDescription(javaMethod,
199                             error.getType())));
200                     error.setPackageName(exception.getJavaClass().getPackageName());
201                     error.setClassName(exception.getJavaClass().getName());
202                     serviceMethod.getErrors().add(error);
203                 }
204                 // return values
205                 ServiceMethodReturnValue rv = new ServiceMethodReturnValue();
206                 serviceMethod.setReturnValue(rv);
207                 Type returnType = null;
208                 try {
209                     returnType = javaMethod.getReturnType();
210                 } catch (NullPointerException ex) {
211                     log.error("Nullpointer getting return type: " + javaMethod.getCallSignature());
212                     returnType = null;
213                 }
214 
215                 rv.setType(calcType(returnType));
216                 rv.setDescription(calcMissing(this.calcReturnDescription(javaMethod)));
217                 if (returnType != null) {
218                     try {
219                     	
220                     	
221 						addXmlTypeAndMessageStructure(calcRealJavaClass(returnType),
222 						        serviceMethod.getService());
223 					} catch (Exception e) {
224 						String message = "failed to parse return type message structure: " + serviceMethod.getService() + " : " + returnType;
225 						
226 						log.error (message + " : " + e.getMessage());
227 						log.error(message, e);
228 					}
229                 }
230             }
231         }
232     }
233 
234     
235     private String calcServiceKey(JavaClass javaClass) {
236         String key = javaClass.getName();
237         if (key.endsWith ("Service")) {
238          key = key.substring(0, key.length() - "Service".length());
239         }
240         if (javaClass.getPackageName().startsWith("org.kuali.rice.")) {
241             log.warn("WARNING " + " changing servkey for the RICE services to include prefix "
242                     + " to disambiguate with Kuali Student StateService See Jira KSENROLL-2892");
243             key = "RICE." + key;
244         }
245         return key;
246     }
247     
248     private JavaMethod[] getServiceMethods(JavaClass javaClass) {
249 		
250     	Set<JavaMethod>methods = new LinkedHashSet<JavaMethod>();
251 		
252 		/*
253 		 * As inheritence is useful from a technical level but not as much from a business level
254 		 * This lets the union of the methods from all of the interfaces be listed in the contract.
255 		 */
256 		JavaClass[] interfaces = javaClass.getImplementedInterfaces();
257 		
258 		for (JavaClass intfc : interfaces) {
259 			
260 			if (!isAService(intfc)) {
261 				// only add the methods if this is not a service
262 				// e.g. extends ServiceBusinessLogic
263 				for (JavaMethod javaMethod : intfc.getMethods()) {
264 				
265 					methods.add(javaMethod);
266 				}
267 			}
268 			
269 		}
270 		
271 		// add the main service methods last incase we override any from the parent interfaces.
272 		// note the heirarchy is only guaranteed relative to the target service class (if there are two levels or more of 
273 		// heirarchy there is no guarantee the method ordering will be correct).
274 		for (JavaMethod javaMethod : javaClass.getMethods()) {
275 			
276 			methods.add(javaMethod);
277 		}
278 		
279 		return methods.toArray(new JavaMethod[] {});
280 	}
281 
282 	private boolean isServiceToProcess(JavaClass javaClass) {
283 //  System.out.println ("looking if javaClass is a service to process=" + javaClass.getName () + "=" + javaClass.getPackageName ());
284     	
285         if (!javaClass.getName().endsWith("Service")) {
286             return false;
287         }
288         if (javaClass.getPackageName().contains(".old.")) {
289 
290             return false;
291         }
292         if (javaClass.getPackageName().endsWith(".old")) {
293             return false;
294         }
295         for (Annotation annotation : javaClass.getAnnotations()) {
296 //   System.out.println ("looking for webservice tag=" + annotation.getType ().getJavaClass ().getName ());
297             if (annotation.getType().getJavaClass().getName().equals("WebService")) {
298 //    System.out.println ("Processing web service=" + javaClass.getPackageName ()
299 //                        + "." + javaClass.getName ());
300                 return true;
301             }
302         }
303         // This includes RICE's business object services even though they are not web services
304         // because often they are the only real service they have exposed and it helps to document
305         // them to see what the data really is like
306         if (javaClass.getName().endsWith("BoService")) {
307             return true;
308         }
309         // This includes KSA's internal services even though they are not web services
310         if (javaClass.getPackageName().startsWith("com.sigmasys.kuali.ksa.service")) {
311             return true;
312         }
313         if (javaClass.getPackageName().startsWith("org.kuali.mobility")) {
314             return true;
315         }
316 //  System.out.println ("skipping service because it is not a web service="
317 //                      + javaClass.getPackageName () + "." + javaClass.getName ());
318         return false;
319     }
320 
321     private List<String> calcIncludedServices(JavaClass javaClass) {
322         List<String> includedServices = new ArrayList<String>();
323         for (JavaClass interfaceClass : javaClass.getImplementedInterfaces()) {
324             if (isAService(interfaceClass)) {
325 //            System.out.println("ServiceContractModelQDoxLoader:" + javaClass.getName()
326 //                    + " implements " + interfaceClass.getName());
327                 includedServices.add(interfaceClass.getName());
328             }
329         }
330         return includedServices;
331     }
332 
333     private boolean isAService(JavaClass interfaceClass) {
334         if (interfaceClass.getName().endsWith("Service")) {
335             return true;
336         }
337         return false;
338     }
339 
340     private String calcParameterDescription(JavaMethod method,
341             String parameterName) {
342         for (DocletTag tag : method.getTags()) {
343             if (tag.getName().equals("param")) {
344                 if (tag.getValue().startsWith(parameterName + " ")) {
345                     return tag.getValue().substring(parameterName.length() + 1);
346                 }
347             }
348         }
349         return null;
350     }
351 
352     private String calcExceptionDescription(JavaMethod serviceMethod,
353             String exceptionType) {
354         for (DocletTag tag : serviceMethod.getTags()) {
355             if (tag.getName().equals("throws")) {
356                 if (tag.getValue().startsWith(exceptionType + " ")) {
357                     return tag.getValue().substring(exceptionType.length() + 1);
358                 }
359             }
360         }
361         return null;
362     }
363 
364     private String calcReturnDescription(JavaMethod serviceMethod) {
365         for (DocletTag tag : serviceMethod.getTags()) {
366             if (tag.getName().equals("return")) {
367                 return tag.getValue();
368             }
369         }
370         return null;
371     }
372 
373     private String calcServiceUrl(JavaClass serviceClass) {
374         for (DocletTag tag : serviceClass.getTags()) {
375             if (tag.getName().equals("See")) {
376                 return tag.getValue();
377             }
378         }
379         return null;
380     }
381 
382     private void addXmlTypeAndMessageStructure(JavaClass messageStructureJavaClass,
383             String serviceKey) {
384         String name = calcType(messageStructureJavaClass);
385         if (name.endsWith("CallbackService")) {
386             return;
387         }
388         XmlType xmlType = xmlTypeMap.get(name);
389         if (xmlType == null) {
390             xmlType = new XmlType();
391             xmlTypeMap.put(name, xmlType);
392             xmlType.setName(name);
393             xmlType.setDesc(this.calcMessageStructureDesc(messageStructureJavaClass));
394             xmlType.setDeprecated(isDeprecated (messageStructureJavaClass));
395             xmlType.setService(serviceKey);
396             xmlType.setVersion("IGNORE -- SAME AS SERVICE");
397             xmlType.setPrimitive(calcPrimitive(messageStructureJavaClass));
398             xmlType.setJavaPackage(calcJavaPackage(messageStructureJavaClass));
399             if (xmlType.getPrimitive().equals(XmlType.COMPLEX)) {
400                 addMessageStructure(messageStructureJavaClass, serviceKey);
401             }
402 
403         } else {
404             addServiceToList(xmlType, serviceKey);
405         }
406     }
407 
408     private boolean isDeprecated(JavaClass javaClass) {
409         for (Annotation annotation : javaClass.getAnnotations()) {
410             if (annotation.getType().getJavaClass().getName().equals(
411                     "Deprecated")) {
412                 return true;
413             }
414         }
415         return false;
416     }
417 
418     private String calcJavaPackage(JavaClass javaClass) {
419         String packageName = javaClass.getPackageName();
420         return packageName;
421     }
422 
423     private String calcMessageStructureDesc(JavaClass javaClass) {
424         {
425             String desc = javaClass.getComment();
426             if (desc != null) {
427                 if (!desc.isEmpty()) {
428                     return desc;
429                 }
430             }
431             JavaClass infcClass = this.getMatchingInfc(javaClass);
432             if (infcClass == null) {
433                 return null;
434             }
435             return infcClass.getComment();
436         }
437     }
438 
439     private JavaClass getMatchingInfc(JavaClass javaClass) {
440         // ks uses this pattern
441         String nameInfc = javaClass.getName();
442         if (nameInfc.endsWith("Info")) {
443             nameInfc = nameInfc.substring(0, nameInfc.length() - "Info".length())
444                     + "Infc";
445         }
446         String nameWithOutInfo = javaClass.getName();
447         // rice uses this pattern
448         if (nameWithOutInfo.endsWith("Info")) {
449             nameWithOutInfo = nameWithOutInfo.substring(0, nameWithOutInfo.length()
450                     - "Info".length());
451         }
452         for (JavaClass infc : javaClass.getImplementedInterfaces()) {
453             if (infc.getName().equals(nameInfc)) {
454 //                System.out.println("found matching interface " + infc.getName());
455                 return infc;
456             }
457             if (infc.getName().equals(nameWithOutInfo)) {
458                 return infc;
459             }
460         }
461         return null;
462     }
463 
464     private String calcPrimitive(JavaClass javaClass) {
465         if (this.isComplex(javaClass)) {
466             return XmlType.COMPLEX;
467         }
468         return "Primitive";
469     }
470 
471     private String initLower(String str) {
472         if (str == null) {
473             return null;
474         }
475         if (str.length() == 0) {
476             return str;
477         }
478         if (str.length() == 1) {
479             return str.toLowerCase();
480         }
481         return str.substring(0, 1).toLowerCase() + str.substring(1);
482     }
483 
484     private String initUpper(String str) {
485         if (str == null) {
486             return null;
487         }
488         if (str.length() == 0) {
489             return str;
490         }
491         if (str.length() == 1) {
492             return str.toUpperCase();
493         }
494         return str.substring(0, 1).toUpperCase() + str.substring(1);
495     }
496 
497     private Set<String> getShortNames(JavaClass messageStructureJavaClass) {
498         Set<String> fields = getFieldsUsingPropOrder(messageStructureJavaClass);
499         if (fields != null) {
500             return fields;
501         }
502         fields = new LinkedHashSet<String>();
503         for (JavaMethod method : messageStructureJavaClass.getMethods(true)) {
504             if (isSetterMethodToProcess(method, messageStructureJavaClass.getName())) {
505                 String shortName = this.calcShortNameFromSetter(method);
506                 fields.add(shortName);
507                 continue;
508             }
509             if (isGetterMethodToProcess(method, messageStructureJavaClass.getName())) {
510                 String shortName = this.calcShortNameFromGetter(method);
511                 fields.add(shortName);
512                 continue;
513             }
514         }
515         return fields;
516     }
517 
518     private Set<String> getFieldsUsingPropOrder(
519             JavaClass messageStructureJavaClass) {
520         for (Annotation annotation : messageStructureJavaClass.getAnnotations()) {
521             if (annotation.getType().getJavaClass().getName().equals("XmlType")) {
522                 AnnotationValue propOrderParam = annotation.getProperty("propOrder");
523                 if (propOrderParam == null) {
524                     continue;
525                 }
526                 Object propOrderValue = propOrderParam.getParameterValue();
527                 if (!(propOrderValue instanceof List)) {
528                     continue;
529                 }
530                 Set<String> fields = new LinkedHashSet<String>();
531                 for (Object value : (List<?>) propOrderValue) {
532                     if (value instanceof String) {
533                         String shortName = (String) value;
534                         shortName = this.stripQuotes(shortName);
535                         if (shortName.contains(".Elements.")) {
536                             String newShortName = getShortNameFromElements(shortName, messageStructureJavaClass);
537                             if (newShortName == null) {
538                                 continue;
539                             }
540                             shortName = newShortName;
541                         } else if (shortName.startsWith("CoreConstants.CommonElements.")) {
542                             String newShortName = getCoreConstants(shortName);
543                             if (newShortName == null) {
544                                 continue;
545                             }
546                             shortName = newShortName;
547                         }
548                         if (shortName.equals("_futureElements")) {
549                             continue;
550                         }
551                         shortName = this.initUpper(shortName);
552                         fields.add(shortName);
553                     }
554                 }
555                 return fields;
556             }
557         }
558         return null;
559     }
560 
561     private String getShortNameFromElements(String shortName, JavaClass messageStructureJavaClass) {
562         JavaClass elementsJavaClass = messageStructureJavaClass.getNestedClassByName("Elements");
563         if (elementsJavaClass == null) {
564             return null;
565         }
566         String fieldName = shortName.substring(shortName.indexOf(".Elements.") + ".Elements.".length());
567         JavaField field = elementsJavaClass.getFieldByName(fieldName);
568         String initExpr = field.getInitializationExpression();
569         return stripQuotes(initExpr);
570     }
571 
572     private String getCoreConstants(String shortName) {
573         if (shortName.endsWith("VERSION_NUMBER")) {
574             return "versionNumber";
575         }
576         if (shortName.endsWith("OBJECT_ID")) {
577             return "objectId";
578         }
579         if (shortName.endsWith("ACTIVE")) {
580             return "active";
581         }
582         if (shortName.endsWith("ACTIVE_FROM_DATE")) {
583             return "activeFromDate";
584         }
585         if (shortName.endsWith("ACTIVE_TO_DATE")) {
586             return "activeToDate";
587         }
588         if (shortName.endsWith("ATTRIBUTES")) {
589             return "attributes";
590         }
591         if (shortName.endsWith("FUTURE_ELEMENTS")) {
592             return "_futureElements";
593         }
594         throw new RuntimeException("Unknown shortName " + shortName);
595     }
596 
597     private boolean validateKualiStudent (JavaClass messageStructureJavaClass) {
598       if (messageStructureJavaClass.getPackageName().startsWith("org.kuali.student.contract.model.test.source")) {
599           return false;
600       } 
601       if (messageStructureJavaClass.getPackageName().startsWith("org.kuali.student.")) {
602           return true;
603       } 
604       return false;
605     }
606     
607     private void addMessageStructure(JavaClass messageStructureJavaClass,
608             String serviceKey) {
609         Map<String, JavaClass> subObjectsToAdd = new LinkedHashMap<String, JavaClass>();
610         boolean validateKualiStudent = this.validateKualiStudent(messageStructureJavaClass);
611         for (String shortName : this.getShortNames(messageStructureJavaClass)) {
612             JavaMethod setterMethod = findSetterMethod(messageStructureJavaClass,
613                     shortName);
614             JavaMethod getterMethod = findGetterMethod(messageStructureJavaClass,
615                     shortName);
616             if (getterMethod == null) {
617                 if (validateKualiStudent) {
618                     throw new IllegalArgumentException("shortName has no corresponding getter method: "
619                             + messageStructureJavaClass.getFullyQualifiedName()
620                             + "." + shortName);
621                 }
622             }
623             JavaField beanField = this.findField(messageStructureJavaClass,
624                     shortName, setterMethod);
625             if (beanField == null) {
626                 String accessorType = getAccessorType(getterMethod);
627                 if ("XmlAccessType.FIELD".equals(accessorType)) {
628                     throw new IllegalArgumentException("Setter method has no corresponding bean field: "
629                             + messageStructureJavaClass.getName()
630                             + "." + getterMethod.getName());
631                 }
632             }
633             // overide the shortName if the bean field has an XmlAttribute name=xxx
634             // this catches the key=id switch
635             if (beanField != null) {
636                 for (Annotation annotation : beanField.getAnnotations()) {
637                     if (annotation.getType().getJavaClass().getName().equals("XmlAttribute")) {
638                         Object nameValue = annotation.getNamedParameter("name");
639                         if (nameValue != null) {
640                             shortName = stripQuotes(nameValue.toString());
641                         }
642                     }
643                 }
644             }
645             shortName = initLower(shortName);
646             MessageStructure ms = new MessageStructure();
647             messageStructures.add(ms);
648             ms.setXmlObject(messageStructureJavaClass.getName());
649             ms.setShortName(shortName);
650 //            if (shortName.equalsIgnoreCase("signups")) {
651 //                System.out.println(".....................Found signups in " + ms.getXmlObject());
652 //            }
653             ms.setId(ms.getXmlObject() + "." + ms.getShortName());
654             ms.setName(calcMissing(calcName(messageStructureJavaClass, getterMethod, setterMethod,
655                     beanField, shortName)));
656             ms.setType(calcType(messageStructureJavaClass, getterMethod, setterMethod, beanField, shortName));
657             if (ms.getType().equals("Object")) {
658                 log.warn(ms.getId()
659                         + " has Object as it's type ==> Changing to String");
660                 ms.setType("String");
661             } else if (ms.getType().equals("ObjectList")) {
662                 log.warn(ms.getId()
663                         + " has a list of Objects as it's type ==> Changing to List of String");
664                 ms.setType("StringList");
665             }
666             ms.setXmlAttribute(this.calcXmlAttribute(beanField));
667             ms.setRequired(calcRequired(getterMethod, setterMethod, beanField));
668             ms.setReadOnly(calcReadOnly(getterMethod, setterMethod, beanField));
669             ms.setCardinality(this.calcCardinality(messageStructureJavaClass, getterMethod, setterMethod, beanField, shortName));
670             ms.setDescription(calcMissing(calcDescription(messageStructureJavaClass, getterMethod, setterMethod,
671                     beanField, shortName)));
672             ms.setImplNotes(calcImplementationNotes(getterMethod, setterMethod, beanField));
673             ms.setColumnName(calcImplementationColumn(getterMethod, setterMethod, beanField));
674             ms.setDeprecated(isDeprecated(getterMethod, setterMethod));
675             ms.setStatus("???");
676             ms.setLookup(calcLookup (messageStructureJavaClass, getterMethod, setterMethod,
677                     beanField, serviceKey, ms.getXmlObject(), shortName, ms.getType()));
678             ms.setPrimaryKey(calcPrimaryKey (messageStructureJavaClass, getterMethod, setterMethod,
679                     beanField, serviceKey, ms.getXmlObject(), shortName, ms.getType()));
680             ms.setOverriden(this.calcOverridden(messageStructureJavaClass, getterMethod));
681             JavaClass subObjToAdd = this.calcRealJavaClassOfGetterReturn(getterMethod);
682             if (subObjToAdd != null) {
683 //                if (!subObjToAdd.isEnum()) {
684                 if (!subObjToAdd.getName().equals("Object")) {
685                     if (!subObjToAdd.getName().equals("LocaleKeyList")) {
686                         if (!subObjToAdd.getName().equals("MessageGroupKeyList")) {
687                             String key = subObjToAdd.getName();
688                             subObjectsToAdd.put(key, subObjToAdd);
689 //                            if (key.equalsIgnoreCase("FeeManagementSignup")) {
690 //                                System.out.println(".....................Found FeeManagementSignup to add to subobjects to add key =" + key);
691 //                            }
692                         }
693                     }
694                 }
695 //                }
696             }
697         }
698 
699 //        System.out.println (".....................size =" + subObjectsToAdd.size() + " keys=" + subObjectsToAdd.keySet());
700         // now add all it's complex sub-objects if they haven't already been added
701         for (String key : subObjectsToAdd.keySet()) {
702             JavaClass subObjectToAdd = subObjectsToAdd.get(key);
703 //            if (key.equalsIgnoreCase("FeeManagementSignup")) {
704 //                System.out.println(".....................Found FeeManagementSignup to add to subobjects to add key =" + key);
705 //            }
706             XmlType xmlType = xmlTypeMap.get(calcType(subObjectToAdd));
707             if (xmlType == null) {
708                 try {
709 					addXmlTypeAndMessageStructure(subObjectToAdd, serviceKey);
710 				} catch (Exception e) {
711 					String message = "failed to parse subobject structure: " + subObjectToAdd + " : " + serviceKey;
712 					// log into message
713 					log.error (message + " : " + e.getMessage());
714 					// log into debug log
715 					log.debug(message, e);
716 				}
717             } else {
718                 addServiceToList(xmlType, serviceKey);
719             }
720         }
721         return;
722     }
723 
724     private String stripList (String type) {
725         if (type == null) {
726             return null;
727         }
728         if (type.endsWith("List")) {
729             return type.substring(0, type.length() - "List".length());
730         }
731         return type;
732     }
733     
734     
735     private boolean calcPrimaryKey (JavaClass mainClass, JavaMethod getterMethod,
736             JavaMethod setterMethod, JavaField beanField, String serviceKey, String xmlObject, String shortName, String type) {
737         if (!type.equalsIgnoreCase ("String")) {
738             return false;
739         }
740         if (shortName.equalsIgnoreCase ("Id")) {
741             return true;
742         }
743         if (shortName.equalsIgnoreCase ("Key")) {
744             return true;
745         }
746         // Special fix up for principal
747 //        log.warn(serviceKey + ":" + xmlObject + "." + shortName);
748         if (xmlObject.equalsIgnoreCase("Principal")) {
749             if (shortName.equalsIgnoreCase("principalId")) {
750                 return true;
751             }
752         }
753         return false;
754     }
755     
756 
757     private Lookup calcLookup (JavaClass mainClass, JavaMethod getterMethod,
758             JavaMethod setterMethod, JavaField beanField, String serviceKey, String xmlObject, String shortName, String type) {
759         type = this.stripList(type);
760         // all keys and Ids are represented as strings
761         if (!type.equalsIgnoreCase ("String")) {
762             return null;
763         }
764         Lookup lookup = LOOKUP_MAPPINGS.get(shortName);
765         if (lookup == null) {
766             if (this.endsWithIdOrKey(shortName)) {
767                 log.warn (serviceKey + ":" + xmlObject + "." + shortName + " ends with id or key but has no lookup defined");
768             } 
769         }
770         return lookup;
771     }
772     
773     private boolean endsWithIdOrKey (String shortName) {
774         if (shortName.equals ("Id")) {
775             return false;
776         }
777         if (shortName.equals ("Key")) {
778             return false;
779         }
780         if (shortName.endsWith ("Id")) {
781             return true;
782         }
783         if (shortName.endsWith ("Ids")) {
784             return true;
785         }
786         if (shortName.endsWith ("Key")) {
787             return true;
788         }
789         if (shortName.endsWith ("Keys")) {
790             return true;
791         }
792         return false;
793     }
794     
795     private static Map<String, Lookup> LOOKUP_MAPPINGS;
796     
797     {
798         // global ones where the name matches the object 
799         LOOKUP_MAPPINGS = new LinkedHashMap<String, Lookup> ();
800         LOOKUP_MAPPINGS.put("typeKey", new Lookup ("Type", "TypeInfo"));
801         LOOKUP_MAPPINGS.put("stateKey", new Lookup ("State", "StateInfo"));
802         LOOKUP_MAPPINGS.put("lifecycleKey", new Lookup ("State", "LifecycleInfo"));
803         LOOKUP_MAPPINGS.put("orgId", new Lookup ("Organization", "OrgInfo"));
804         LOOKUP_MAPPINGS.put("orgIds", new Lookup ("Organization", "OrgInfo"));
805         LOOKUP_MAPPINGS.put("organizationId", new Lookup ("Organization", "OrgInfo"));
806         LOOKUP_MAPPINGS.put("organizationIds", new Lookup ("Organization", "OrgInfo"));
807         LOOKUP_MAPPINGS.put("atpId", new Lookup ("Atp", "AtpInfo"));
808         LOOKUP_MAPPINGS.put("atpIds", new Lookup ("Atp", "AtpInfo"));
809         LOOKUP_MAPPINGS.put("termId", new Lookup ("AcademicCalendar", "TermInfo"));
810         LOOKUP_MAPPINGS.put("termIds", new Lookup ("AcademicCalendar", "TermInfo"));
811         LOOKUP_MAPPINGS.put("luiId", new Lookup ("Lui", "LuiInfo"));
812         LOOKUP_MAPPINGS.put("luiIds", new Lookup ("Lui", "LuiInfo"));
813         LOOKUP_MAPPINGS.put("cluId", new Lookup ("Clu", "CluInfo"));
814         LOOKUP_MAPPINGS.put("cluIds", new Lookup ("Clu", "CluInfo"));
815         LOOKUP_MAPPINGS.put("credentialProgramId", new Lookup ("Program", "CredentialProgramInfo"));
816         LOOKUP_MAPPINGS.put("credentialProgramIds", new Lookup ("Program", "CredentialProgramInfo"));
817         LOOKUP_MAPPINGS.put("credentialProgramId", new Lookup ("Program", "CredentialProgramInfo"));
818         LOOKUP_MAPPINGS.put("credentialProgramIds", new Lookup ("Program", "CredentialProgramInfo"));
819         LOOKUP_MAPPINGS.put("coreProgramId", new Lookup ("Program", "CoreProgramInfo"));
820         LOOKUP_MAPPINGS.put("coreProgramIds", new Lookup ("Program", "CoreProgramInfo"));
821         LOOKUP_MAPPINGS.put("resultScaleKey", new Lookup ("LRC", "ResultScaleInfo"));
822         LOOKUP_MAPPINGS.put("resultScaleKeys", new Lookup ("LRC", "ResultScaleInfo"));
823         LOOKUP_MAPPINGS.put("resultValuesGroupKey", new Lookup ("LRC", "ResultValuesGroupInfo"));
824         LOOKUP_MAPPINGS.put("resultValuesGroupKeys", new Lookup ("LRC", "ResultValuesGroupInfo"));
825         LOOKUP_MAPPINGS.put("resultValueKey", new Lookup ("LRC", "ResultValueInfo"));
826         LOOKUP_MAPPINGS.put("resultValueKeys", new Lookup ("LRC", "ResultValueInfo"));
827         LOOKUP_MAPPINGS.put("scheduleId", new Lookup ("Schedule", "ScheduleInfo"));
828         LOOKUP_MAPPINGS.put("scheduleIds", new Lookup ("Schedule", "ScheduleInfo"));
829         LOOKUP_MAPPINGS.put("courseId", new Lookup ("Course", "CourseInfo"));
830         LOOKUP_MAPPINGS.put("courseIds", new Lookup ("Course", "CourseInfo"));
831         LOOKUP_MAPPINGS.put("formatId", new Lookup ("Course", "FormatInfo"));
832         LOOKUP_MAPPINGS.put("formatIds", new Lookup ("Course", "FormatInfo"));
833         LOOKUP_MAPPINGS.put("activityId", new Lookup ("Course", "ActivityInfo"));
834         LOOKUP_MAPPINGS.put("activityIds", new Lookup ("Course", "ActivityInfo"));
835         LOOKUP_MAPPINGS.put("courseOfferingId", new Lookup ("CourseOffering", "CourseOfferingInfo"));
836         LOOKUP_MAPPINGS.put("courseOfferingIds", new Lookup ("CourseOffering", "CourseOfferingInfo"));
837         LOOKUP_MAPPINGS.put("formatOfferingId", new Lookup ("CourseOffering", "FormatOfferingInfo"));
838         LOOKUP_MAPPINGS.put("formatOfferingIds", new Lookup ("CourseOffering", "FormatOfferingInfo"));
839         LOOKUP_MAPPINGS.put("activityOfferingId", new Lookup ("CourseOffering", "ActivityOfferingInfo"));
840         LOOKUP_MAPPINGS.put("activityOfferingIds", new Lookup ("CourseOffering", "ActivityOfferingInfo"));
841         LOOKUP_MAPPINGS.put("socRolloverResultId", new Lookup ("CourseOfferingSet", "SorRolloverResultInfo"));
842         LOOKUP_MAPPINGS.put("socRolloverResultIds", new Lookup ("CourseOfferingSet", "SorRolloverResultInfo"));
843         LOOKUP_MAPPINGS.put("socRolloverResultItemId", new Lookup ("CourseOfferingSet", "SorRolloverResultItemInfo"));
844         LOOKUP_MAPPINGS.put("socRolloverResultItemIds", new Lookup ("CourseOfferingSet", "SorRolloverResultItemInfo"));
845         LOOKUP_MAPPINGS.put("buildingId", new Lookup ("Room", "BuildingInfo"));
846         LOOKUP_MAPPINGS.put("buildingIds", new Lookup ("Room", "BuildingInfo"));
847         LOOKUP_MAPPINGS.put("roomId", new Lookup ("Room", "RoomInfo"));
848         LOOKUP_MAPPINGS.put("roomIds", new Lookup ("Room", "RoomInfo"));
849         LOOKUP_MAPPINGS.put("populationId", new Lookup ("Population", "PopulationInfo"));
850         LOOKUP_MAPPINGS.put("populationIds", new Lookup ("Population", "PopulationInfo"));
851         
852         
853         // COMMON RICE IDENTITY SERVICE
854         LOOKUP_MAPPINGS.put("principalId", new Lookup ("rice.kim.Identity", "Principal"));
855         LOOKUP_MAPPINGS.put("principalIds", new Lookup ("rice.kim.Identity", "Principal"));
856         // TODO: fix these Ids that currently maps to principal instead of the entity id
857         LOOKUP_MAPPINGS.put("personId", new Lookup ("rice.kim.Identity", "Principal"));
858         LOOKUP_MAPPINGS.put("personIds", new Lookup ("rice.kim.Identity", "Principal"));
859         LOOKUP_MAPPINGS.put("instructorId", new Lookup ("rice.kim.Identity", "Principal"));
860         LOOKUP_MAPPINGS.put("instructorIds", new Lookup ("rice.kim.Identity", "Principal"));
861         LOOKUP_MAPPINGS.put("studentId", new Lookup ("rice.kim.Identity", "Principal"));
862         LOOKUP_MAPPINGS.put("studentIds", new Lookup ("rice.kim.Identity", "Principal"));
863         
864         // Common objects 
865         // TimeAmount
866         LOOKUP_MAPPINGS.put("atpDurationTypeKey", new Lookup ("Type", "TypeInfo")); 
867         LOOKUP_MAPPINGS.put("currencyTypeKey", new Lookup ("Type", "TypeInfo"));        
868         // Context
869         LOOKUP_MAPPINGS.put("authenticatedPrincipalId", new Lookup ("rice.kim.Identity", "Principal"));
870         // meta
871         LOOKUP_MAPPINGS.put("createId", new Lookup ("rice.kim.Identity", "Principal"));
872         LOOKUP_MAPPINGS.put("updateId", new Lookup ("rice.kim.Identity", "Principal"));
873         LOOKUP_MAPPINGS.put("agendaId", new Lookup ("rice.krms.Agenda", "Agenda"));
874         LOOKUP_MAPPINGS.put("agendaIds", new Lookup ("rice.krms.Agenda", "Agenda"));
875         LOOKUP_MAPPINGS.put("", new Lookup ("", ""));
876         LOOKUP_MAPPINGS.put("", new Lookup ("", ""));
877         LOOKUP_MAPPINGS.put("", new Lookup ("", ""));
878         LOOKUP_MAPPINGS.put("", new Lookup ("", ""));
879         LOOKUP_MAPPINGS.put("", new Lookup ("", ""));
880         LOOKUP_MAPPINGS.put("", new Lookup ("", ""));
881         LOOKUP_MAPPINGS.put("", new Lookup ("", ""));
882         
883         
884         // TODO: replace or augment this special list of ones with annotations in the contract itself
885         // program service
886         LOOKUP_MAPPINGS.put("unitsContentOwner", new Lookup ("Organization", "OrgInfo"));
887         LOOKUP_MAPPINGS.put("unitsDeployment", new Lookup ("Organization", "OrgInfo"));
888         LOOKUP_MAPPINGS.put("unitsStudentOversight", new Lookup ("Organization", "OrgInfo"));
889         LOOKUP_MAPPINGS.put("unitsFinancialResources", new Lookup ("Organization", "OrgInfo"));
890         LOOKUP_MAPPINGS.put("unitsFinancialControl", new Lookup ("Organization", "OrgInfo"));
891         LOOKUP_MAPPINGS.put("divisionsContentOwner", new Lookup ("Organization", "OrgInfo"));
892         LOOKUP_MAPPINGS.put("divisionsDeployment", new Lookup ("Organization", "OrgInfo"));
893         LOOKUP_MAPPINGS.put("divisionsStudentOversight", new Lookup ("Organization", "OrgInfo"));
894         LOOKUP_MAPPINGS.put("divisionsFinancialResources", new Lookup ("Organization", "OrgInfo"));
895         LOOKUP_MAPPINGS.put("divisionsFinancialControl", new Lookup ("Organization", "OrgInfo"));
896         LOOKUP_MAPPINGS.put("startTerm", new Lookup ("AcademicCalendar", "TermInfo"));
897         LOOKUP_MAPPINGS.put("endTerm", new Lookup ("AcademicCalendar", "TermInfo"));
898         LOOKUP_MAPPINGS.put("endProgramEntryTerm", new Lookup ("AcademicCalendar", "TermInfo"));
899         LOOKUP_MAPPINGS.put("resultOptions", new Lookup ("LRC", "ResultValuesGroupInfo"));
900         LOOKUP_MAPPINGS.put("programRequirements", new Lookup ("Program", "ProgramRequirementInfo"));
901         // share by program and course
902         LOOKUP_MAPPINGS.put("parentRelType", new Lookup ("Type", "TypeInfo"));
903         LOOKUP_MAPPINGS.put("parentLoRelationid", new Lookup ("LearningObjective", "LoInfo"));
904         
905         // type service
906         LOOKUP_MAPPINGS.put("ownerTypeKey", new Lookup ("Type", "TypeInfo"));
907         LOOKUP_MAPPINGS.put("relatedTypeKey", new Lookup ("Type", "TypeInfo"));
908         
909         // State service (there are no special purpose ones) 
910         
911         // LRC service (there are no special purpose ones)
912         
913         // atp
914         LOOKUP_MAPPINGS.put("adminOrgId", new Lookup ("Organization", "OrgInfo"));
915         LOOKUP_MAPPINGS.put("relatedAtpId", new Lookup ("Atp", "AtpInfo"));
916         LOOKUP_MAPPINGS.put("relativeAnchorMilestoneId", new Lookup ("Atp", "MilestoneInfo"));
917         
918         // Lui
919         LOOKUP_MAPPINGS.put("relatedLuiTypes", new Lookup ("Type", "TypeInfo"));
920         LOOKUP_MAPPINGS.put("relatedLuiId", new Lookup ("Lui", "LuiInfo"));
921         
922         // Course Offering
923         LOOKUP_MAPPINGS.put("", new Lookup ("", ""));
924         LOOKUP_MAPPINGS.put("", new Lookup ("", ""));
925         
926         // TODO: finish the services
927         LOOKUP_MAPPINGS.put("unitsDeploymentOrgIds", new Lookup ("Organization", "OrgInfo"));
928         LOOKUP_MAPPINGS.put("unitsContentOwnerOrgIds", new Lookup ("Organization", "OrgInfo"));
929         LOOKUP_MAPPINGS.put("unitsContentOwnerId", new Lookup ("Organization", "OrgInfo"));
930         LOOKUP_MAPPINGS.put("jointOfferingIds", new Lookup ("CourseOffering", "CourseOfferingInfo"));
931         LOOKUP_MAPPINGS.put("gradingOptionId", new Lookup ("LRC", "ResultValuesGroupInfo"));
932         LOOKUP_MAPPINGS.put("creditOptionId", new Lookup ("LRC", "ResultValuesGroupInfo"));
933         LOOKUP_MAPPINGS.put("waitlistLevelTypeKey", new Lookup ("Type", "TypeInfo"));
934         LOOKUP_MAPPINGS.put("waitlistTypeKey", new Lookup ("Type", "TypeInfo"));
935         LOOKUP_MAPPINGS.put("activityOfferingTypeKeys", new Lookup ("Type", "TypeInfo"));
936         LOOKUP_MAPPINGS.put("gradeRosterLevelTypeKey", new Lookup ("Type", "TypeInfo"));
937         LOOKUP_MAPPINGS.put("finalExamLevelTypeKey", new Lookup ("Type", "TypeInfo"));
938         LOOKUP_MAPPINGS.put("schedulingStateKey", new Lookup ("State", "StateInfo"));
939         LOOKUP_MAPPINGS.put("gradingOptionKeys", new Lookup ("LRC", "ResultValuesGroupInfo"));
940         LOOKUP_MAPPINGS.put("creditOptionId", new Lookup ("LRC", "ResultValuesGroupInfo"));
941         LOOKUP_MAPPINGS.put("gradingOptionKeys", new Lookup ("", ""));
942         LOOKUP_MAPPINGS.put("", new Lookup ("", ""));
943         LOOKUP_MAPPINGS.put("", new Lookup ("", ""));
944         LOOKUP_MAPPINGS.put("", new Lookup ("", ""));
945         LOOKUP_MAPPINGS.put("", new Lookup ("", ""));
946         LOOKUP_MAPPINGS.put("", new Lookup ("", ""));
947         LOOKUP_MAPPINGS.put("", new Lookup ("", ""));
948         LOOKUP_MAPPINGS.put("", new Lookup ("", ""));
949         LOOKUP_MAPPINGS.put("", new Lookup ("", ""));
950         LOOKUP_MAPPINGS.put("", new Lookup ("", ""));
951         LOOKUP_MAPPINGS.put("", new Lookup ("", ""));
952         LOOKUP_MAPPINGS.put("", new Lookup ("", ""));
953         
954     }
955     
956     private boolean calcOverridden(JavaClass mainClass, JavaMethod getterMethod) {
957         if (getterMethod == null) {
958             return false;
959         }
960         JavaMethod infcGetter = null;
961         if (getterMethod.getParentClass().isInterface()) {
962             infcGetter = getterMethod;
963         }
964         if (infcGetter == null) {
965             infcGetter = findInterfaceMethod(mainClass, getterMethod, false);
966         }
967         if (infcGetter == null) {
968             return false;
969         }
970         Annotation annotation = this.getAnnotation(infcGetter, null, null, "Override");
971         if (annotation != null) {
972             return true;
973         }
974         return false;
975     }
976 
977     private String calcComment(JavaClass javaClass) {
978         return this.calcComment(javaClass.getComment());
979     }
980 
981     private String calcComment(String comment) {
982         return this.parseCommentVersion(comment)[0];
983     }
984 
985     private String calcVersion(JavaClass javaClass) {
986         DocletTag tag = javaClass.getTagByName("version", true);
987         if (tag != null) {
988             return tag.getValue();
989         }
990         return this.calcVersion(javaClass.getComment());
991     }
992 
993     private String calcVersion(String comment) {
994         return this.parseCommentVersion(comment)[1];
995     }
996 
997     private String[] parseCommentVersion(String commentVersion) {
998         String[] parsed = new String[2];
999         if (commentVersion == null) {
1000             return parsed;
1001         }
1002         commentVersion = commentVersion.trim();
1003         int i = commentVersion.toLowerCase().indexOf("\nversion:");
1004         if (i == -1) {
1005             parsed[0] = commentVersion;
1006             return parsed;
1007         }
1008         parsed[1] = commentVersion.substring(i + "\nversion:".length()).trim();
1009         parsed[0] = commentVersion.substring(0, i).trim();
1010 
1011         return parsed;
1012     }
1013 
1014     private Annotation getAnnotation(JavaMethod getterMethod,
1015             JavaMethod setterMethod, JavaField beanField, String type) {
1016         if (beanField != null) {
1017 
1018             for (Annotation annotation : beanField.getAnnotations()) {
1019                 if (annotation.getType().getJavaClass().getName().equals(type)) {
1020                     return annotation;
1021                 }
1022             }
1023         }
1024         if (getterMethod != null) {
1025 
1026             for (Annotation annotation : getterMethod.getAnnotations()) {
1027                 if (annotation.getType().getJavaClass().getName().equals(type)) {
1028                     return annotation;
1029                 }
1030             }
1031         }
1032         if (setterMethod != null) {
1033 
1034             for (Annotation annotation : setterMethod.getAnnotations()) {
1035                 if (annotation.getType().getJavaClass().getName().equals(type)) {
1036                     return annotation;
1037                 }
1038             }
1039         }
1040         return null;
1041     }
1042 
1043     private String calcRequired(JavaMethod getterMethod,
1044             JavaMethod setterMethod, JavaField beanField) {
1045         Annotation annotation = this.getAnnotation(getterMethod, setterMethod, beanField, "XmlElement");
1046         if (annotation == null) {
1047             annotation = this.getAnnotation(getterMethod, setterMethod, beanField, "XmlAttribute");
1048         }
1049         if (annotation != null) {
1050             Object required = annotation.getNamedParameter("required");
1051             if (required != null) {
1052                 if (required.toString().equalsIgnoreCase("true")) {
1053                     return "Required";
1054                 }
1055             }
1056         }
1057         if (getterMethod != null) {
1058             DocletTag tag = getterMethod.getTagByName("required", true);
1059             if (tag != null) {
1060                 if (tag.getValue() == null) {
1061                     return "Required";
1062                 }
1063                 String required = "Required " + tag.getValue();
1064                 return required.trim();
1065             }
1066         }
1067         return null;
1068     }
1069 
1070     private String calcReadOnly(JavaMethod getterMethod,
1071             JavaMethod setterMethod, JavaField beanField) {
1072         if (getterMethod != null) {
1073             DocletTag tag = getterMethod.getTagByName("readOnly", true);
1074             if (tag != null) {
1075                 if (tag.getValue() == null) {
1076                     return "Read only";
1077                 }
1078                 String readOnly = "Read only " + tag.getValue();
1079                 return readOnly.trim();
1080             }
1081         }
1082         return null;
1083     }
1084 
1085     private String calcImplementationNotes(JavaMethod serviceMethod) {
1086         StringBuilder bldr = new StringBuilder();
1087         String newLine = "";
1088         for (DocletTag tag : serviceMethod.getTagsByName("impl", true)) {
1089             bldr.append(newLine);
1090             newLine = "\n";
1091             String value = tag.getValue();
1092             bldr.append(value);
1093         }
1094         if (hasOverride(serviceMethod)) {
1095             boolean matchJustOnName = true;
1096             JavaMethod overriddenMethod = findInterfaceMethod(serviceMethod.getParentClass(), serviceMethod, matchJustOnName);
1097             if (overriddenMethod == null) {
1098                 // do it again so we can debug
1099                 findInterfaceMethod(serviceMethod.getParentClass(), serviceMethod, true);
1100                 throw new NullPointerException("could not find overridden method or method that has @Override annotation " + serviceMethod.getCallSignature());
1101             }
1102             bldr.append(newLine);
1103             newLine = "\n";
1104             bldr.append("Overridden method should be implemented in helper: ");
1105             bldr.append(overriddenMethod.getParentClass().getName());
1106         }
1107         if (bldr.length() == 0) {
1108             return null;
1109         }
1110         return bldr.toString();
1111     }
1112 
1113     private boolean hasOverride(JavaMethod serviceMethod) {
1114         for (Annotation annotation : serviceMethod.getAnnotations()) {
1115             if (annotation.getType().getJavaClass().getName().equals(
1116                     "Override")) {
1117                 return true;
1118             }
1119         }
1120         return false;
1121     }
1122 
1123     private boolean isDeprecated(JavaMethod serviceMethod ) {
1124         for (Annotation annotation : serviceMethod.getAnnotations()) {
1125             if (annotation.getType().getJavaClass().getName().equals(
1126                     "Deprecated")) {
1127                 return true;
1128             }
1129         }
1130         return false;
1131     }
1132 
1133     private boolean isDeprecated(JavaMethod getterMethod, JavaMethod setterMethod) {
1134         if (getterMethod != null) {
1135             return this.isDeprecated(getterMethod);
1136         }
1137         if (setterMethod != null) {
1138             return this.isDeprecated(setterMethod);
1139         }
1140         return false;
1141     }
1142 
1143     private String calcImplementationNotes(JavaMethod getterMethod,
1144             JavaMethod setterMethod, JavaField beanField) {
1145         if (getterMethod != null) {
1146             DocletTag tag = getterMethod.getTagByName("impl", true);
1147             if (tag != null) {
1148                 return tag.getValue();
1149             }
1150         }
1151         return null;
1152     }
1153     
1154     private String calcImplementationColumn (JavaMethod getterMethod,
1155             JavaMethod setterMethod, JavaField beanField) {
1156         if (getterMethod != null) {
1157             DocletTag tag = getterMethod.getTagByName("implColumn", true);
1158             if (tag != null) {
1159                 return tag.getValue();
1160             }
1161         }
1162         return null;
1163     }
1164 
1165     private String calcNameFromShortName(String shortName) {
1166         StringBuilder bldr = new StringBuilder(shortName.length() + 3);
1167         char c = shortName.charAt(0);
1168         bldr.append(Character.toUpperCase(c));
1169         boolean lastWasUpper = true;
1170         for (int i = 1; i < shortName.length(); i++) {
1171             c = shortName.charAt(i);
1172             if (Character.isUpperCase(c)) {
1173                 if (!lastWasUpper) {
1174                     bldr.append(" ");
1175                 }
1176             } else {
1177                 lastWasUpper = false;
1178             }
1179             bldr.append(c);
1180         }
1181         return bldr.toString();
1182     }
1183 
1184     private String calcName(JavaClass mainClass, JavaMethod getterMethod,
1185             JavaMethod setterMethod, JavaField beanField, String shortName) {
1186         String name = this.calcNameFromTag(getterMethod, setterMethod, beanField);
1187         if (name != null) {
1188             return name;
1189         }
1190         name = this.calcNameFromNameEmbeddedInDescription(mainClass, getterMethod, setterMethod, beanField, shortName);
1191         if (name != null) {
1192             return name;
1193         }
1194         return this.calcNameFromShortName(shortName);
1195     }
1196 
1197     private String calcNameFromTag(JavaMethod getterMethod,
1198             JavaMethod setterMethod, JavaField beanField) {
1199         if (getterMethod != null) {
1200             DocletTag tag = getterMethod.getTagByName("name", true);
1201             if (tag != null) {
1202                 return tag.getValue();
1203             }
1204         }
1205         return null;
1206     }
1207 
1208     private String calcNameFromNameEmbeddedInDescription(JavaClass mainClass, JavaMethod getterMethod,
1209             JavaMethod setterMethod, JavaField beanField, String shortName) {
1210         String nameDesc = this.calcMethodComment(mainClass, getterMethod, setterMethod,
1211                 beanField, shortName);
1212         String[] parsed = parseNameDesc(nameDesc);
1213         return parsed[0];
1214     }
1215 
1216     private String[] parseNameDesc(String nameDesc) {
1217         String[] parsed = new String[2];
1218         if (nameDesc == null) {
1219             return parsed;
1220         }
1221         nameDesc = nameDesc.trim();
1222         if (!nameDesc.startsWith("Name:")) {
1223             parsed[1] = nameDesc;
1224             return parsed;
1225         }
1226         nameDesc = nameDesc.substring("Name:".length()).trim();
1227         int i = nameDesc.indexOf("\n");
1228         if (i == -1) {
1229             parsed[0] = nameDesc.trim();
1230             return parsed;
1231         }
1232         parsed[0] = nameDesc.substring(0, i).trim();
1233         parsed[1] = nameDesc.substring(i).trim();
1234         return parsed;
1235     }
1236 
1237     private String calcDescription(JavaClass mainClass, JavaMethod getterMethod,
1238             JavaMethod setterMethod, JavaField beanField, String shortName) {
1239         String nameDesc = this.calcMethodComment(mainClass, getterMethod, setterMethod,
1240                 beanField, shortName);
1241         String[] parsed = parseNameDesc(nameDesc);
1242         return parsed[1];
1243     }
1244  
1245     private String calcMethodComment(JavaClass mainClass, JavaMethod getterMethod,
1246             JavaMethod setterMethod,
1247             JavaField beanField,
1248             String shortName) {
1249         String desc = null;
1250         if (getterMethod != null) {
1251             desc = getterMethod.getComment();
1252             if (isCommentNotEmpty(desc)) {
1253                 return desc;
1254             }
1255 //            System.out.println("Searching for superclass to find description for field " + shortName);
1256             JavaClass jc = mainClass;
1257             while (true) {
1258                 JavaClass superJc = jc.getSuperJavaClass();
1259                 if (superJc == null) {
1260                     break;
1261                 }
1262                 JavaMethod parentGetterMethod = this.findGetterMethod(superJc, shortName);
1263                 if (parentGetterMethod != null) {
1264                     desc = parentGetterMethod.getComment();
1265                     if (isCommentNotEmpty(desc)) {
1266                         return desc;
1267                     }
1268                 }
1269                 jc = superJc;
1270             }
1271         }
1272         if (setterMethod != null) {
1273             desc = setterMethod.getComment();
1274             if (isCommentNotEmpty(desc)) {
1275                 return desc;
1276             }
1277         }
1278         if (beanField != null) {
1279             desc = beanField.getComment();
1280             if (isCommentNotEmpty(desc)) {
1281                 return desc;
1282             }
1283         }
1284         desc = calcMethodCommentRecursively(mainClass, getterMethod);
1285         if (isCommentNotEmpty(desc)) {
1286             return desc;
1287         }
1288         desc = calcMethodCommentRecursively(mainClass, setterMethod);
1289         if (isCommentNotEmpty(desc)) {
1290             return desc;
1291         }
1292         return null;
1293     }
1294 
1295     private String calcMethodCommentRecursively(JavaClass mainClass, JavaMethod method) {
1296         if (method == null) {
1297             return null;
1298         }
1299         String desc = method.getComment();
1300         if (isCommentNotEmpty(desc)) {
1301             return desc;
1302         }
1303         JavaMethod infcMethod = findInterfaceMethod(mainClass, method, false);
1304         if (infcMethod != null) {
1305             desc = infcMethod.getComment();
1306             if (isCommentNotEmpty(desc)) {
1307                 return desc;
1308             }
1309         }
1310         JavaMethod superMethod = findSuperMethod(method);
1311         if (superMethod != null) {
1312             desc = superMethod.getComment();
1313             if (isCommentNotEmpty(desc)) {
1314                 return desc;
1315             }
1316         }
1317         return null;
1318     }
1319 
1320     private JavaMethod findSuperMethod(JavaMethod method) {
1321 //        System.out.println("Searching for super method for "
1322 //                + method.getParentClass().getName() + "."
1323 //                + method.getCallSignature());
1324         for (JavaMethod superMethod : method.getParentClass().getMethods(true)) {
1325             if (method.equals(superMethod)) {
1326                 continue;
1327             }
1328             if (method.getCallSignature().equals(superMethod.getCallSignature())) {
1329                 return superMethod;
1330             }
1331         }
1332         return null;
1333     }
1334 
1335     private JavaMethod findInterfaceMethod(JavaClass mainClass, JavaMethod method, boolean matchJustOnName) {
1336         String callSig = method.getCallSignature();
1337         if (matchJustOnName) {
1338             callSig = method.getName();
1339         }
1340         JavaClass classToSearch = mainClass;
1341 //        log ("Searching mainClass " + classToSearch.getName() + " for " + callSig, callSig);
1342         while (true) {
1343             for (JavaClass infcClass : classToSearch.getImplementedInterfaces()) {
1344                 JavaMethod meth = this.findMethodOnInterfaceRecursively(infcClass, callSig, matchJustOnName);
1345                 if (meth != null) {
1346 //                    recursionCntr = 0;
1347                     return meth;
1348                 }
1349             }
1350             JavaClass superClass = classToSearch.getSuperJavaClass();
1351             if (superClass == null) {
1352 //                recursionCntr = 0;                
1353 //                log ("Did not find " + callSig + " on " + mainClass, callSig); 
1354                 return null;
1355             }
1356             classToSearch = superClass;
1357 //            log ("Searching superClass " + classToSearch.getName() + " for " + callSig, callSig);                
1358         }
1359     }
1360 
1361 //    private void log (String message, String callSig) {
1362 //        if (callSig.equalsIgnoreCase("getTypeKey()")) {
1363 //            for (int i = 0; i < this.recursionCntr; i++) {
1364 //                System.out.print (" ");
1365 //            }
1366 //            System.out.println (message);
1367 //        }
1368 //    }
1369 //    private int recursionCntr = 0;
1370     private JavaMethod findMethodOnInterfaceRecursively(JavaClass infcClass, String callSig, boolean matchJustOnName) {
1371 //        recursionCntr++;
1372 //        log ("Searching interface " + infcClass.getName() + " for " + callSig, callSig);
1373         for (JavaMethod infcMethod : infcClass.getMethods()) {
1374             if (callSig.equals(infcMethod.getCallSignature())) {
1375 //                log (callSig + " found on " + infcClass.getName() + "!!!!!!!!!!!!!!!!", callSig); 
1376 //                recursionCntr--;
1377                 return infcMethod;
1378             }
1379             if (matchJustOnName) {
1380                 if (callSig.equals(infcMethod.getName())) {
1381                     return infcMethod;
1382                 }
1383             }
1384         }
1385         for (JavaClass subInfc : infcClass.getImplementedInterfaces()) {
1386 //            log ("Searching  sub-interface " + subInfc.getName() + " for " + callSig, callSig);
1387             JavaMethod infcMethod = findMethodOnInterfaceRecursively(subInfc, callSig, matchJustOnName);
1388             if (infcMethod != null) {
1389 //                recursionCntr--;
1390                 return infcMethod;
1391             }
1392         }
1393 //        log (callSig + " not found on " + infcClass.getName(), callSig);
1394 //        this.recursionCntr--;
1395         return null;
1396     }
1397 
1398     private boolean isCommentNotEmpty(String desc) {
1399         if (desc == null) {
1400             return false;
1401         }
1402         if (desc.trim().isEmpty()) {
1403             return false;
1404         }
1405         if (desc.contains("@inheritDoc")) {
1406             return false;
1407         }
1408         return true;
1409     }
1410 
1411     private String getAccessorType(JavaMethod method) {
1412         String accessorType = getAccessorType(method.getAnnotations());
1413         if (accessorType != null) {
1414             return accessorType;
1415         }
1416         accessorType = getAccessorType(method.getParentClass().getAnnotations());
1417         return accessorType;
1418     }
1419 
1420     private String getAccessorType(Annotation[] annotations) {
1421         for (Annotation annotation : annotations) {
1422             if (annotation.getType().getJavaClass().getName().equals(
1423                     "XmlAccessorType")) {
1424 //    System.out.println ("Looking for XmlAccessorType annotation = "
1425 //                        + annotation.getParameterValue ());
1426                 return annotation.getParameterValue().toString();
1427             }
1428         }
1429         return null;
1430     }
1431 
1432     private String stripQuotes(String str) {
1433         if (str.startsWith("\"")) {
1434             str = str.substring(1);
1435         }
1436         if (str.endsWith("\"")) {
1437             str = str.substring(0, str.length() - 1);
1438         }
1439         return str;
1440     }
1441 
1442     private String calcMissing(String str) {
1443         if (str == null) {
1444             return "???";
1445         }
1446         if (str.trim().isEmpty()) {
1447             return "???";
1448         }
1449         return str;
1450     }
1451 
1452     private void addServiceToList(XmlType xmlType, String serviceKey) {
1453         if (!xmlType.getService().contains(serviceKey)) {
1454             xmlType.setService(xmlType.getService() + ", " + serviceKey);
1455         }
1456     }
1457 
1458     private String calcXmlAttribute(JavaField beanField) {
1459         if (beanField == null) {
1460             // TODO: worry about checking for this annotation on the method for non-field based AccessorTypes
1461             return "No";
1462         }
1463         for (Annotation annotation : beanField.getAnnotations()) {
1464             if (annotation.getType().getJavaClass().getName().equals("XmlAttribute")) {
1465                 return "Yes";
1466             }
1467         }
1468         return "No";
1469     }
1470 
1471     private JavaField findField(JavaClass javaClass, String shortName,
1472             JavaMethod setterMethod) {
1473         JavaField field = findField(javaClass, shortName);
1474         if (field != null) {
1475             return field;
1476         }
1477         if (setterMethod != null) {
1478             if (setterMethod.getParameters().length > 0) {
1479                 String paramName = setterMethod.getParameters()[0].getName();
1480                 if (paramName.equalsIgnoreCase(shortName)) {
1481                     return null;
1482                 }
1483                 return findField(javaClass, paramName);
1484             }
1485         }
1486         return null;
1487     }
1488 
1489     private JavaField findField(JavaClass javaClass, String name) {
1490         if (name == null) {
1491             return null;
1492         }
1493         for (JavaField field : javaClass.getFields()) {
1494             if (field.getName().equalsIgnoreCase(name)) {
1495                 return field;
1496             }
1497             // TODO: check for shortNames that already start with is so we don't check for isIsEnrollable
1498             if (field.getName().equals("is" + name)) {
1499                 return field;
1500             }
1501         }
1502         JavaClass superClass = javaClass.getSuperJavaClass();
1503         if (superClass == null) {
1504             return null;
1505         }
1506         return findField(superClass, name);
1507     }
1508 
1509     private JavaMethod findGetterMethod(JavaClass msClass, String shortName) {
1510         for (JavaMethod method : msClass.getMethods(true)) {
1511             String methodName = method.getName();
1512             if (methodName.equalsIgnoreCase("get" + shortName)) {
1513                 return method;
1514             }
1515             if (methodName.toLowerCase().startsWith("is")) {
1516                 if (methodName.equalsIgnoreCase("is" + shortName)) {
1517                     return method;
1518                 }
1519                 // shortName already has "is" in it
1520                 if (methodName.equalsIgnoreCase(shortName)) {
1521                     return method;
1522                 }
1523             }
1524             // TODO: followup on KimEntityResidencyInfo.getInState
1525             if (methodName.equalsIgnoreCase("getInState") && shortName.equalsIgnoreCase(
1526                     "InStateFlag")) {
1527                 return method;
1528             }
1529         }
1530         return null;
1531     }
1532 
1533     private JavaMethod findSetterMethod(JavaClass msClass, String shortName) {
1534         for (JavaMethod method : msClass.getMethods(true)) {
1535             if (method.getName().equals("set" + shortName)) {
1536                 return method;
1537             }
1538             // TODO: check for shortNames that already start with is so we don't check for isIsEnrollable
1539             if (method.getName().equals("setIs" + shortName)) {
1540                 return method;
1541             }
1542             // TODO: followup on KimEntityResidencyInfo.getInState
1543             if (method.getName().equals("setInStateFlag") && shortName.equals(
1544                     "InState")) {
1545                 return method;
1546             }
1547         }
1548         return null;
1549     }
1550     private static final String[] SETTER_METHODS_TO_SKIP = {
1551         // Somebody put "convenience" methods on the validation result info
1552         "ValidationResultInfo.setWarning",
1553         "ValidationResultInfo.setError",
1554         // not on original wiki but still defined as a method but not backed by a field so not in wsdl
1555         "CredentialProgramInfo.setDiplomaTitle",
1556         // synonym for the official of setCredentialType
1557         "CredentialProgramInfo.setType",
1558         // not on original wiki but still defined as a method but not backed by a field so not in wsdl
1559         "CredentialProgramInfo.setHegisCode",
1560         "CredentialProgramInfo.setCip2000Code",
1561         "CredentialProgramInfo.setCip2010Code",
1562         "CredentialProgramInfo.setSelectiveEnrollmentCode",
1563         "CoreProgramInfo.setDiplomaTitle",
1564         // synonym for the official of setCredentialType
1565         //  "CoreProgramInfo.setType",
1566         // not on original wiki but still defined as a method but not backed by a field so not in wsdl
1567         "CoreProgramInfo.setHegisCode",
1568         "CoreProgramInfo.setCip2000Code",
1569         "CoreProgramInfo.setCip2010Code",
1570         "CoreProgramInfo.setSelectiveEnrollmentCode",
1571         "WhenConstraint.setValue"
1572     };
1573     private static final String[] GETTER_METHODS_TO_SKIP = {
1574         // Somebody put "convenience" methods on the validation result info
1575         "ValidationResultInfo.getWarning",
1576         "ValidationResultInfo.getError",
1577         // not on original wiki but still defined as a method but not backed by a field so not in wsdl
1578         "CredentialProgramInfo.getDiplomaTitle",
1579         // synonym for the official of setCredentialType
1580         "CredentialProgramInfo.getType",
1581         // not on original wiki but still defined as a method but not backed by a field so not in wsdl
1582         "CredentialProgramInfo.getHegisCode",
1583         "CredentialProgramInfo.getCip2000Code",
1584         "CredentialProgramInfo.getCip2010Code",
1585         "CredentialProgramInfo.getSelectiveEnrollmentCode",
1586         "CoreProgramInfo.getDiplomaTitle",
1587         // synonym for the official of setCredentialType
1588         //  "CoreProgramInfo.setType",
1589         // not on original wiki but still defined as a method but not backed by a field so not in wsdl
1590         "CoreProgramInfo.getHegisCode",
1591         "CoreProgramInfo.getCip2000Code",
1592         "CoreProgramInfo.getCip2010Code",
1593         "CoreProgramInfo.getSelectiveEnrollmentCode",
1594         "WhenConstraint.getValue"
1595     };
1596 
1597     private boolean isSetterMethodToProcess(JavaMethod method, String className) {
1598         if (!method.getName().startsWith("set")) {
1599             return false;
1600         }
1601         if (method.getParameters().length != 1) {
1602             return false;
1603         }
1604         if (method.isPrivate()) {
1605             return false;
1606         }
1607         if (method.isProtected()) {
1608             return false;
1609         }
1610         if (method.isStatic()) {
1611             return false;
1612         }
1613         if (method.getParentClass().getPackageName().startsWith("java")) {
1614             return false;
1615         }
1616         String fullName = className + "." + method.getName();
1617         for (String skip : SETTER_METHODS_TO_SKIP) {
1618             if (skip.equals(fullName)) {
1619                 return false;
1620             }
1621         }
1622 //  if (method.getParentClass ().isInterface ())
1623 //  {
1624 //   return false;
1625 //  }
1626         for (Annotation annotation : method.getAnnotations()) {
1627             if (annotation.getType().getJavaClass().getName().equals("XmlTransient")) {
1628                 return false;
1629             }
1630         }
1631         return true;
1632     }
1633 
1634     private boolean isGetterMethodToProcess(JavaMethod method, String className) {
1635         if (!method.getName().startsWith("get")) {
1636             if (!method.getName().startsWith("is")) {
1637                 return false;
1638             }
1639         }
1640         if (method.getParameters().length != 0) {
1641             return false;
1642         }
1643         if (method.isPrivate()) {
1644             return false;
1645         }
1646         if (method.isProtected()) {
1647             return false;
1648         }
1649         if (method.isStatic()) {
1650             return false;
1651         }
1652         if (method.getParentClass().getPackageName().startsWith("java")) {
1653             return false;
1654         }
1655         String fullName = className + "." + method.getName();
1656         for (String skip : GETTER_METHODS_TO_SKIP) {
1657             if (skip.equals(fullName)) {
1658                 return false;
1659             }
1660         }
1661 //  if (method.getParentClass ().isInterface ())
1662 //  {
1663 //   return false;
1664 //  }
1665         for (Annotation annotation : method.getAnnotations()) {
1666             if (annotation.getType().getJavaClass().getName().equals("XmlTransient")) {
1667                 return false;
1668             }
1669         }
1670         return true;
1671     }
1672 
1673     private String calcShortNameFromSetter(JavaMethod method) {
1674         return method.getName().substring(3);
1675     }
1676 
1677     private String calcShortNameFromGetter(JavaMethod method) {
1678         if (method.getName().startsWith("get")) {
1679             return method.getName().substring(3);
1680         }
1681         if (method.getName().startsWith("is")) {
1682             return method.getName().substring(2);
1683         }
1684         throw new IllegalArgumentException(method.getName()
1685                 + " does not start with is or get");
1686     }
1687 
1688     private String calcCardinality(JavaClass mainClass, JavaMethod getterMethod,
1689             JavaMethod setterMethod, JavaField beanField, String shortName) {
1690         if (isReturnACollection(mainClass, getterMethod, setterMethod, beanField, shortName)) {
1691             return "Many";
1692         }
1693         return "One";
1694     }
1695 
1696     private boolean isReturnACollection(JavaClass mainClass, JavaMethod getterMethod,
1697             JavaMethod setterMethod, JavaField beanField, String shortName) {
1698         if (getterMethod != null) {
1699             return isCollection(getterMethod.getReturnType());
1700         }
1701         if (beanField != null) {
1702             return isCollection(beanField.getType());
1703         }
1704         // TODO: check setterMethod
1705         return false;
1706     }
1707 
1708     private boolean isCollection(Type type) {
1709         JavaClass javaClass = type.getJavaClass();
1710         return this.isCollection(javaClass);
1711     }
1712 
1713     private boolean isCollection(JavaClass javaClass) {
1714         if (javaClass.getName().equals("LocalKeyList")) {
1715             return true;
1716         }
1717         if (javaClass.getName().equals("MessageGroupKeyList")) {
1718             return true;
1719         }
1720         if (javaClass.getName().equals(List.class.getSimpleName())) {
1721             return true;
1722         }
1723         if (javaClass.getName().equals(ArrayList.class.getSimpleName())) {
1724             return true;
1725         }
1726         if (javaClass.getName().equals(Collection.class.getSimpleName())) {
1727             return true;
1728         }
1729         if (javaClass.getName().equals(Set.class.getSimpleName())) {
1730             return true;
1731         }
1732         return false;
1733     }
1734 
1735     private String calcType(JavaClass mainClass, JavaMethod getterMethod,
1736             JavaMethod setterMethod, JavaField beanField, String shortName) {
1737         if (getterMethod != null) {
1738             return calcTypeOfGetterMethodReturn(getterMethod);
1739         }
1740         if (beanField != null) {
1741             Type type = beanField.getType();
1742             return calcType(type);
1743         }
1744         // TODO: calc type based on the setterMethod
1745         return null;
1746     }
1747 
1748     private String calcTypeOfGetterMethodReturn(JavaMethod getterMethod) {
1749         Type type = getterMethod.getReturnType();
1750         return calcType(type);
1751     }
1752 
1753     private String calcType(Type type) {
1754         if (type == null) {
1755             return "void";
1756         }
1757         if (isCollection(type.getJavaClass())) {
1758             return calcType(calcRealJavaClass(type)) + "List";
1759         }
1760         return calcType(calcRealJavaClass(type));
1761     }
1762 
1763     private Annotation findJavaAnnotation(String name, JavaClass clazz) {
1764     	
1765     	Annotation[] annotations = clazz.getAnnotations();
1766     	
1767     	for (Annotation annotation : annotations) {
1768 	        
1769     		if (annotation.getType().getJavaClass().getName().equals(name)) {
1770     			return annotation;
1771     		}
1772         }
1773     	return null;
1774     }
1775     private String calcType(JavaClass javaClass) {
1776     	
1777         if (javaClass.isEnum()) {
1778             
1779             return "Enum";
1780         	
1781 //			if (!JavaClassAnnotationUtils.doesAnnotationExist(
1782 //			        XmlEnum.class.getSimpleName(), javaClass)) {
1783 //				// a rice or other dependency without the @XmlEnum annotation
1784 //				// present
1785 //				if (javaClass.getName().equals("WriteAccess")) {
1786 //					// rice CommonLookupParam
1787 //					return "String";
1788 //				} else if (javaClass.getName().equals("Widget")) {
1789 //					// rice CommonLookupParam
1790 //					return "String";
1791 //				} else if (javaClass.getName().equals("Usage")) {
1792 //					// rice
1793 //					return "String";
1794 //				} else {
1795 //					// this allows the types to be manually specified 
1796 //					// using the full package.classname format.
1797 //					return javaClass.getFullyQualifiedName();
1798 //				}
1799 //
1800 //			}
1801 //    		
1802 //    		Class<?>annotationSpecifiedType = JavaClassAnnotationUtils.extractXmlEnumValue(javaClass);
1803 //    		
1804 //        	return annotationSpecifiedType.getSimpleName();
1805 //           
1806         }
1807         // this is messed up instead of list of strings it is an object with a list of strings
1808         if (javaClass.getName().equals(LOCALE_KEY_LIST)) {
1809             return "StringList";
1810         }
1811         if (javaClass.getName().equals(MESSAGE_GROUP_KEY_LIST)) {
1812             return "StringList";
1813         }
1814         // TODO: figure out why rice stuff translates like this junk?
1815         if (javaClass.getName().equals("java$util$Map")) {
1816             return "Map<String, String>";
1817         }
1818         if (javaClass.getName().equals("Map")) {
1819             // TODO: make sure it is in fact a String,String map
1820             return "Map<String, String>";
1821         }
1822         return javaClass.getName();
1823     }
1824 
1825     private JavaClass calcRealJavaClassOfGetterReturn(JavaMethod getterMethod) {
1826         if (getterMethod == null) {
1827             return null;
1828         }
1829         Type type = getterMethod.getReturnType();
1830         return this.calcRealJavaClass(type);
1831     }
1832 
1833     private JavaClass calcRealJavaClass(Type type) {
1834         if (type == null) {
1835             return null;
1836         }
1837         JavaClass javaClass = type.getJavaClass();
1838         if (javaClass.getName().equals(LOCALE_KEY_LIST)) {
1839             return STRING_JAVA_CLASS;
1840         }
1841         if (javaClass.getName().equals(MESSAGE_GROUP_KEY_LIST)) {
1842             return STRING_JAVA_CLASS;
1843         }
1844         if (!this.isCollection(javaClass)) {
1845             return javaClass;
1846         }
1847 
1848 //  for (Type t : type.getActualTypeArguments ())
1849 //  {
1850 //   System.out.println ("ServiceContractModelQDoxLoader: type arguments = "
1851 //                       + t.toString ());
1852 //  }
1853 
1854         Type[]collectionTypeArguments = type.getActualTypeArguments();
1855         
1856         if (collectionTypeArguments == null)
1857         	return new JavaClass (Object.class.getName());
1858         else
1859         	return collectionTypeArguments[0].getJavaClass();
1860     }
1861 
1862     private boolean isComplex(JavaClass javaClass) {
1863         if (javaClass.getName().equals ("void")) {
1864             return false;
1865         }
1866         if (javaClass.isEnum()) {
1867             return false;
1868         }
1869         if (javaClass.getName().equals(String.class.getSimpleName())) {
1870             return false;
1871         }
1872         if (javaClass.getName().equals(Integer.class.getSimpleName())) {
1873             return false;
1874         }
1875         if (javaClass.getName().equals(Date.class.getSimpleName())) {
1876             return false;
1877         }
1878         if (javaClass.getName().equals(Long.class.getSimpleName())) {
1879             return false;
1880         }
1881         if (javaClass.getName().equals(Boolean.class.getSimpleName())) {
1882             return false;
1883         }
1884         if (javaClass.getName().equals(Double.class.getSimpleName())) {
1885             return false;
1886         }
1887         if (javaClass.getName().equals(Float.class.getSimpleName())) {
1888             return false;
1889         }
1890         if (javaClass.getName().equals(int.class.getSimpleName())) {
1891             return false;
1892         }
1893         if (javaClass.getName().equals(long.class.getSimpleName())) {
1894             return false;
1895         }
1896         if (javaClass.getName().equals(boolean.class.getSimpleName())) {
1897             return false;
1898         }
1899         if (javaClass.getName().equals(double.class.getSimpleName())) {
1900             return false;
1901         }
1902         if (javaClass.getName().equals(float.class.getSimpleName())) {
1903             return false;
1904         }
1905         if (javaClass.getName().equals(Map.class.getSimpleName())) {
1906             return false;
1907         }
1908 
1909         if (javaClass.getName().equals(String.class.getName())) {
1910             return false;
1911         }
1912         if (javaClass.getName().equals(Integer.class.getName())) {
1913             return false;
1914         }
1915         if (javaClass.getName().equals(Date.class.getName())) {
1916             return false;
1917         }
1918         if (javaClass.getName().equals(Long.class.getName())) {
1919             return false;
1920         }
1921         if (javaClass.getName().equals(Boolean.class.getName())) {
1922             return false;
1923         }
1924         if (javaClass.getName().equals(Double.class.getName())) {
1925             return false;
1926         }
1927         if (javaClass.getName().equals(Float.class.getName())) {
1928             return false;
1929         }
1930         if (javaClass.getName().equals(int.class.getName())) {
1931             return false;
1932         }
1933         if (javaClass.getName().equals(long.class.getName())) {
1934             return false;
1935         }
1936         if (javaClass.getName().equals(boolean.class.getName())) {
1937             return false;
1938         }
1939         if (javaClass.getName().equals(double.class.getName())) {
1940             return false;
1941         }
1942         if (javaClass.getName().equals(float.class.getName())) {
1943             return false;
1944         }
1945         if (javaClass.getName().equals(BigDecimal.class.getSimpleName())) {
1946             return false;
1947         }
1948         if (javaClass.getName().equals(Map.class.getName())) {
1949             return false;
1950         }
1951         if (javaClass.getName().equals(LOCALE_KEY_LIST)) {
1952             return false;
1953         }
1954         if (javaClass.getName().equals(MESSAGE_GROUP_KEY_LIST)) {
1955             return false;
1956         }
1957         if (javaClass.getName().equals("java$util$Map")) {
1958             return false;
1959         }
1960         return true;
1961     }
1962 
1963     @Override
1964     public String toString() {
1965         return "ServiceContractModelQDoxLoader{" +
1966                 "sourceDirectories=" + sourceDirectories +
1967                 ", services=" + services +
1968                 ", serviceMethods=" + serviceMethods +
1969                 ", xmlTypeMap=" + xmlTypeMap +
1970                 ", messageStructures=" + messageStructures+
1971                 '}';
1972     }
1973 }