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