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