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