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