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