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