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