View Javadoc

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