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