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