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