View Javadoc

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