001    /*
002     * Copyright 2010 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may      obtain a copy of the License at
007     *
008     *      http://www.osedu.org/licenses/ECL-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.student.contract.model.impl;
017    
018    import java.io.File;
019    import java.util.ArrayList;
020    import java.util.Collection;
021    import java.util.Collections;
022    import java.util.Date;
023    import java.util.LinkedHashMap;
024    import java.util.LinkedHashSet;
025    import java.util.List;
026    import java.util.Map;
027    import java.util.Set;
028    
029    import org.kuali.student.contract.model.MessageStructure;
030    import org.kuali.student.contract.model.Service;
031    import org.kuali.student.contract.model.ServiceContractModel;
032    import org.kuali.student.contract.model.ServiceMethod;
033    import org.kuali.student.contract.model.ServiceMethodError;
034    import org.kuali.student.contract.model.ServiceMethodParameter;
035    import org.kuali.student.contract.model.ServiceMethodReturnValue;
036    import org.kuali.student.contract.model.XmlType;
037    import org.slf4j.Logger;
038    import org.slf4j.LoggerFactory;
039    
040    import com.thoughtworks.qdox.JavaDocBuilder;
041    import com.thoughtworks.qdox.model.Annotation;
042    import com.thoughtworks.qdox.model.DefaultDocletTagFactory;
043    import com.thoughtworks.qdox.model.DocletTag;
044    import com.thoughtworks.qdox.model.JavaClass;
045    import com.thoughtworks.qdox.model.JavaField;
046    import com.thoughtworks.qdox.model.JavaMethod;
047    import com.thoughtworks.qdox.model.JavaParameter;
048    import com.thoughtworks.qdox.model.Type;
049    import com.thoughtworks.qdox.model.annotation.AnnotationValue;
050    import org.kuali.student.contract.model.Lookup;
051    
052    /**
053     *
054     * @author nwright
055     */
056    public class ServiceContractModelQDoxLoader implements
057            ServiceContractModel {
058            
059            private static final Logger log = LoggerFactory.getLogger(ServiceContractModelQDoxLoader.class);
060    
061        private static final String LOCALE_KEY_LIST = "LocaleKeyList";
062        private static final String MESSAGE_GROUP_KEY_LIST = "MessageGroupKeyList";
063        private static final JavaClass STRING_JAVA_CLASS = new JavaClass(
064                "java.lang.String");
065        private List<String> sourceDirectories = null;
066        private List<Service> services = null;
067        private List<ServiceMethod> serviceMethods = null;
068        private Map<String, XmlType> xmlTypeMap = null;
069        private List<MessageStructure> messageStructures;
070        private boolean validateKualiStudent = true;
071    
072        public ServiceContractModelQDoxLoader(List<String> sourceDirectories) {
073            this.sourceDirectories = sourceDirectories;
074        }
075    
076        public ServiceContractModelQDoxLoader(List<String> sourceDirectories, boolean validateKualiStudent) {
077            this.sourceDirectories = sourceDirectories;
078            this.setValidateKualiStudent(validateKualiStudent);
079        }
080    
081        public boolean isValidateKualiStudent() {
082            return validateKualiStudent;
083        }
084    
085        public void setValidateKualiStudent(boolean validateKualiStudent) {
086            this.validateKualiStudent = validateKualiStudent;
087        }
088    
089        @Override
090        public List<ServiceMethod> getServiceMethods() {
091            if (this.serviceMethods == null) {
092                this.parse();
093            }
094            return this.serviceMethods;
095        }
096    
097        @Override
098        public List<String> getSourceNames() {
099            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    }