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