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