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