001 /* 002 * Copyright 2010 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.osedu.org/licenses/ECL-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.kuali.student.contract.model.impl; 017 018 import com.thoughtworks.qdox.JavaDocBuilder; 019 import com.thoughtworks.qdox.model.Annotation; 020 import com.thoughtworks.qdox.model.DefaultDocletTagFactory; 021 import com.thoughtworks.qdox.model.DocletTag; 022 import com.thoughtworks.qdox.model.JavaClass; 023 import com.thoughtworks.qdox.model.JavaField; 024 import com.thoughtworks.qdox.model.JavaMethod; 025 import com.thoughtworks.qdox.model.JavaParameter; 026 import com.thoughtworks.qdox.model.Type; 027 import com.thoughtworks.qdox.model.annotation.AnnotationValue; 028 import java.io.File; 029 import java.util.ArrayList; 030 import java.util.Arrays; 031 import java.util.Collection; 032 import java.util.Collections; 033 import java.util.Date; 034 import java.util.HashSet; 035 import java.util.LinkedHashMap; 036 import java.util.LinkedHashSet; 037 import java.util.List; 038 import java.util.Map; 039 import java.util.Set; 040 041 import javassist.compiler.Javac; 042 043 import org.kuali.student.contract.model.MessageStructure; 044 import org.kuali.student.contract.model.Service; 045 import org.kuali.student.contract.model.ServiceContractModel; 046 import org.kuali.student.contract.model.ServiceMethod; 047 import org.kuali.student.contract.model.ServiceMethodError; 048 import org.kuali.student.contract.model.ServiceMethodParameter; 049 import org.kuali.student.contract.model.ServiceMethodReturnValue; 050 import org.kuali.student.contract.model.XmlType; 051 052 /** 053 * 054 * @author nwright 055 */ 056 public class ServiceContractModelQDoxLoader implements 057 ServiceContractModel { 058 059 private static final String LOCALE_KEY_LIST = "LocaleKeyList"; 060 private static final String MESSAGE_GROUP_KEY_LIST = "MessageGroupKeyList"; 061 private static final JavaClass STRING_JAVA_CLASS = new JavaClass( 062 "java.lang.String"); 063 private List<String> sourceDirectories = null; 064 private List<Service> services = null; 065 private List<ServiceMethod> serviceMethods = null; 066 private Map<String, XmlType> xmlTypeMap = null; 067 private List<MessageStructure> messageStructures; 068 private boolean validateKualiStudent = true; 069 070 public ServiceContractModelQDoxLoader(List<String> sourceDirectories) { 071 this.sourceDirectories = sourceDirectories; 072 } 073 074 public ServiceContractModelQDoxLoader(List<String> sourceDirectories, boolean validateKualiStudent) { 075 this.sourceDirectories = sourceDirectories; 076 this.setValidateKualiStudent(validateKualiStudent); 077 } 078 079 public boolean isValidateKualiStudent() { 080 return validateKualiStudent; 081 } 082 083 public void setValidateKualiStudent(boolean validateKualiStudent) { 084 this.validateKualiStudent = validateKualiStudent; 085 } 086 087 @Override 088 public List<ServiceMethod> getServiceMethods() { 089 if (this.serviceMethods == null) { 090 this.parse(); 091 } 092 return this.serviceMethods; 093 } 094 095 @Override 096 public List<String> getSourceNames() { 097 List<String> list = new ArrayList(this.sourceDirectories.size()); 098 for (String javaFile : this.sourceDirectories) { 099 list.add(javaFile); 100 } 101 return list; 102 } 103 104 @Override 105 public List<Service> getServices() { 106 if (services == null) { 107 this.parse(); 108 } 109 return services; 110 } 111 112 @Override 113 public List<XmlType> getXmlTypes() { 114 if (xmlTypeMap == null) { 115 this.parse(); 116 } 117 return new ArrayList(xmlTypeMap.values()); 118 } 119 120 @Override 121 public List<MessageStructure> getMessageStructures() { 122 if (messageStructures == null) { 123 this.parse(); 124 } 125 return this.messageStructures; 126 } 127 128 private String dump(DocletTag tag) { 129 if (tag == null) { 130 return null; 131 } 132 StringBuilder bldr = new StringBuilder(); 133 bldr.append(tag.getName()); 134 bldr.append("="); 135 if (tag.getNamedParameterMap() == null 136 || tag.getNamedParameterMap().isEmpty()) { 137 bldr.append(tag.getValue()); 138 } else { 139 for (Object key : tag.getNamedParameterMap().keySet()) { 140 Object value = tag.getNamedParameterMap().get(key); 141 bldr.append("("); 142 bldr.append(key); 143 bldr.append("="); 144 bldr.append(value); 145 bldr.append(")"); 146 } 147 } 148 return bldr.toString(); 149 } 150 151 private void checkIfExists(String sourceDirectory) { 152 File file = new File(sourceDirectory); 153 if (!file.isDirectory()) { 154 throw new IllegalArgumentException(sourceDirectory + " is not a directory on disk"); 155 } 156 } 157 158 private void parse() { 159 // System.out.println ("ServiceContractModelQDoxLoader: Starting parse"); 160 services = new ArrayList(); 161 serviceMethods = new ArrayList(); 162 xmlTypeMap = new LinkedHashMap(); 163 messageStructures = new ArrayList(); 164 DefaultDocletTagFactory dtf = new DefaultDocletTagFactory(); 165 JavaDocBuilder builder = new JavaDocBuilder(dtf); 166 for (String sourceDirectory : sourceDirectories) { 167 checkIfExists(sourceDirectory); 168 builder.addSourceTree(new File(sourceDirectory)); 169 } 170 List<JavaClass> sortedClasses = Arrays.asList(builder.getClasses()); 171 Collections.sort(sortedClasses); 172 for (JavaClass javaClass : sortedClasses) { 173 if (!this.isServiceToProcess(javaClass)) { 174 continue; 175 } 176 // System.out.println ("processing service=" + javaClass.getName ()); 177 Service service = new Service(); 178 services.add(service); 179 service.setKey(javaClass.getName().substring(0, javaClass.getName().length() 180 - "Service".length())); 181 service.setName(javaClass.getName()); 182 service.setComments(this.calcComment(javaClass)); 183 service.setUrl(this.calcServiceUrl(javaClass)); 184 service.setVersion(this.calcVersion(javaClass)); 185 service.setStatus("???"); 186 service.setIncludedServices(calcIncludedServices(javaClass)); 187 service.setImplProject(javaClass.getPackageName()); 188 189 // for (DocletTag tag : javaClass.getTags ()) 190 // { 191 // System.out.println ("ServiceContractModelQDoxLoader: Class: " 192 // + javaClass.getName () + " has tag=" + dump ( 193 // tag)); 194 // } 195 196 JavaMethod[] methods = getServiceMethods (javaClass); 197 for (JavaMethod javaMethod : methods) { 198 199 ServiceMethod serviceMethod = new ServiceMethod(); 200 serviceMethods.add(serviceMethod); 201 serviceMethod.setService(service.getKey()); 202 serviceMethod.setName(javaMethod.getName()); 203 serviceMethod.setDescription(calcMissing(javaMethod.getComment())); 204 serviceMethod.setParameters(new ArrayList()); 205 serviceMethod.setImplNotes(calcImplementationNotes(javaMethod)); 206 serviceMethod.setDeprecated(isDeprecated(javaMethod)); 207 // for (DocletTag tag : javaMethod.getTags ()) 208 // { 209 // System.out.println ("ServiceContractModelQDoxLoader: Method: " 210 // + service.getName () + "." 211 // + javaMethod.getName () 212 // + " has tag=" + dump (tag)); 213 // } 214 // parameters 215 for (JavaParameter parameter : javaMethod.getParameters()) { 216 ServiceMethodParameter param = new ServiceMethodParameter(); 217 serviceMethod.getParameters().add(param); 218 param.setName(parameter.getName()); 219 param.setType(calcType(parameter.getType())); 220 param.setDescription(calcMissing( 221 calcParameterDescription(javaMethod, 222 param.getName()))); 223 addXmlTypeAndMessageStructure(calcRealJavaClass(parameter.getType()), 224 serviceMethod.getService()); 225 } 226 // errors 227 serviceMethod.setErrors(new ArrayList()); 228 for (Type exception : javaMethod.getExceptions()) { 229 ServiceMethodError error = new ServiceMethodError(); 230 error.setType(this.calcType(exception.getJavaClass())); 231 error.setDescription(calcMissing( 232 calcExceptionDescription(javaMethod, 233 error.getType()))); 234 error.setPackageName(exception.getJavaClass().getPackageName()); 235 error.setClassName(exception.getJavaClass().getName()); 236 serviceMethod.getErrors().add(error); 237 } 238 // return values 239 ServiceMethodReturnValue rv = new ServiceMethodReturnValue(); 240 serviceMethod.setReturnValue(rv); 241 Type returnType = null; 242 try { 243 returnType = javaMethod.getReturnType(); 244 } catch (NullPointerException ex) { 245 System.out.println("Nullpinter getting return type: " + javaMethod.getCallSignature()); 246 returnType = null; 247 } 248 249 rv.setType(calcType(returnType)); 250 rv.setDescription(calcMissing(this.calcReturnDescription(javaMethod))); 251 if (returnType != null) { 252 addXmlTypeAndMessageStructure(calcRealJavaClass(returnType), 253 serviceMethod.getService()); 254 } 255 } 256 } 257 } 258 259 private JavaMethod[] getServiceMethods(JavaClass javaClass) { 260 261 Set<JavaMethod>methods = new LinkedHashSet<JavaMethod>(); 262 263 /* 264 * As inheritence is useful from a technical level but not as much from a business level 265 * This lets the union of the methods from all of the interfaces be listed in the contract. 266 */ 267 JavaClass[] interfaces = javaClass.getImplementedInterfaces(); 268 269 for (JavaClass intfc : interfaces) { 270 271 if (!isAService(intfc)) { 272 // only add the methods if this is not a service 273 // e.g. extends ServiceBusinessLogic 274 for (JavaMethod javaMethod : intfc.getMethods()) { 275 276 methods.add(javaMethod); 277 } 278 } 279 280 } 281 282 // add the main service methods last incase we override any from the parent interfaces. 283 // note the heirarchy is only guaranteed relative to the target service class (if there are two levels or more of 284 // heirarchy there is no guarantee the method ordering will be correct). 285 for (JavaMethod javaMethod : javaClass.getMethods()) { 286 287 methods.add(javaMethod); 288 } 289 290 return methods.toArray(new JavaMethod[] {}); 291 } 292 293 private boolean isServiceToProcess(JavaClass javaClass) { 294 // System.out.println ("looking if javaClass is a service to process=" + javaClass.getName () + "=" + javaClass.getPackageName ()); 295 296 if (!javaClass.getName().endsWith("Service")) { 297 return false; 298 } 299 if (javaClass.getPackageName().contains(".old.")) { 300 301 return false; 302 } 303 if (javaClass.getPackageName().endsWith(".old")) { 304 return false; 305 } 306 for (Annotation annotation : javaClass.getAnnotations()) { 307 // System.out.println ("looking for webservice tag=" + annotation.getType ().getJavaClass ().getName ()); 308 if (annotation.getType().getJavaClass().getName().equals("WebService")) { 309 // System.out.println ("Processing web service=" + javaClass.getPackageName () 310 // + "." + javaClass.getName ()); 311 return true; 312 } 313 } 314 // This includes RICE's business object services even though they are not web services 315 // because often they are the only real service they have exposed and it helps to document 316 // them to see what the data really is like 317 if (javaClass.getName().endsWith("BoService")) { 318 return true; 319 } 320 // System.out.println ("skipping service because it is not a web service=" 321 // + javaClass.getPackageName () + "." + javaClass.getName ()); 322 return false; 323 } 324 325 private List<String> calcIncludedServices(JavaClass javaClass) { 326 List<String> includedServices = new ArrayList<String>(); 327 for (JavaClass interfaceClass : javaClass.getImplementedInterfaces()) { 328 if (isAService(interfaceClass)) { 329 // System.out.println("ServiceContractModelQDoxLoader:" + javaClass.getName() 330 // + " implements " + interfaceClass.getName()); 331 includedServices.add(interfaceClass.getName()); 332 } 333 } 334 return includedServices; 335 } 336 337 private boolean isAService(JavaClass interfaceClass) { 338 if (interfaceClass.getName().endsWith("Service")) { 339 return true; 340 } 341 return false; 342 } 343 344 private String calcParameterDescription(JavaMethod method, 345 String parameterName) { 346 for (DocletTag tag : method.getTags()) { 347 if (tag.getName().equals("param")) { 348 if (tag.getValue().startsWith(parameterName + " ")) { 349 return tag.getValue().substring(parameterName.length() + 1); 350 } 351 } 352 } 353 return null; 354 } 355 356 private String calcExceptionDescription(JavaMethod serviceMethod, 357 String exceptionType) { 358 for (DocletTag tag : serviceMethod.getTags()) { 359 if (tag.getName().equals("throws")) { 360 if (tag.getValue().startsWith(exceptionType + " ")) { 361 return tag.getValue().substring(exceptionType.length() + 1); 362 } 363 } 364 } 365 return null; 366 } 367 368 private String calcReturnDescription(JavaMethod serviceMethod) { 369 for (DocletTag tag : serviceMethod.getTags()) { 370 if (tag.getName().equals("return")) { 371 return tag.getValue(); 372 } 373 } 374 return null; 375 } 376 377 private String calcServiceUrl(JavaClass serviceClass) { 378 for (DocletTag tag : serviceClass.getTags()) { 379 if (tag.getName().equals("See")) { 380 return tag.getValue(); 381 } 382 } 383 return null; 384 } 385 386 private void addXmlTypeAndMessageStructure(JavaClass messageStructureJavaClass, 387 String serviceKey) { 388 String name = calcType(messageStructureJavaClass); 389 XmlType xmlType = xmlTypeMap.get(name); 390 if (xmlType == null) { 391 xmlType = new XmlType(); 392 xmlTypeMap.put(name, xmlType); 393 xmlType.setName(name); 394 xmlType.setDesc(this.calcMessageStructureDesc(messageStructureJavaClass)); 395 xmlType.setDeprecated(isDeprecated (messageStructureJavaClass)); 396 xmlType.setService(serviceKey); 397 xmlType.setVersion("IGNORE -- SAME AS SERVICE"); 398 xmlType.setPrimitive(calcPrimitive(messageStructureJavaClass)); 399 xmlType.setJavaPackage(calcJavaPackage(messageStructureJavaClass)); 400 if (xmlType.getPrimitive().equals(XmlType.COMPLEX)) { 401 addMessageStructure(messageStructureJavaClass, serviceKey); 402 } 403 404 } else { 405 addServiceToList(xmlType, serviceKey); 406 } 407 } 408 409 private boolean isDeprecated(JavaClass javaClass) { 410 for (Annotation annotation : javaClass.getAnnotations()) { 411 if (annotation.getType().getJavaClass().getName().equals( 412 "Deprecated")) { 413 return true; 414 } 415 } 416 return false; 417 } 418 419 private String calcJavaPackage(JavaClass javaClass) { 420 String packageName = javaClass.getPackageName(); 421 return packageName; 422 } 423 424 private String calcMessageStructureDesc(JavaClass javaClass) { 425 { 426 String desc = javaClass.getComment(); 427 if (desc != null) { 428 if (!desc.isEmpty()) { 429 return desc; 430 } 431 } 432 JavaClass infcClass = this.getMatchingInfc(javaClass); 433 if (infcClass == null) { 434 return null; 435 } 436 return infcClass.getComment(); 437 } 438 } 439 440 private JavaClass getMatchingInfc(JavaClass javaClass) { 441 // ks uses this pattern 442 String nameInfc = javaClass.getName(); 443 if (nameInfc.endsWith("Info")) { 444 nameInfc = nameInfc.substring(0, nameInfc.length() - "Info".length()) 445 + "Infc"; 446 } 447 String nameWithOutInfo = javaClass.getName(); 448 // rice uses this pattern 449 if (nameWithOutInfo.endsWith("Info")) { 450 nameWithOutInfo = nameWithOutInfo.substring(0, nameWithOutInfo.length() 451 - "Info".length()); 452 } 453 for (JavaClass infc : javaClass.getImplementedInterfaces()) { 454 if (infc.getName().equals(nameInfc)) { 455 // System.out.println("found matching interface " + infc.getName()); 456 return infc; 457 } 458 if (infc.getName().equals(nameWithOutInfo)) { 459 return infc; 460 } 461 } 462 return null; 463 } 464 465 private String calcPrimitive(JavaClass javaClass) { 466 if (this.isComplex(javaClass)) { 467 return XmlType.COMPLEX; 468 } 469 return "Primitive"; 470 } 471 472 private String initLower(String str) { 473 if (str == null) { 474 return null; 475 } 476 if (str.length() == 0) { 477 return str; 478 } 479 if (str.length() == 1) { 480 return str.toLowerCase(); 481 } 482 return str.substring(0, 1).toLowerCase() + str.substring(1); 483 } 484 485 private String initUpper(String str) { 486 if (str == null) { 487 return null; 488 } 489 if (str.length() == 0) { 490 return str; 491 } 492 if (str.length() == 1) { 493 return str.toUpperCase(); 494 } 495 return str.substring(0, 1).toUpperCase() + str.substring(1); 496 } 497 498 private Set<String> getShortNames(JavaClass messageStructureJavaClass) { 499 Set<String> fields = getFieldsUsingPropOrder(messageStructureJavaClass); 500 if (fields != null) { 501 return fields; 502 } 503 fields = new LinkedHashSet(); 504 for (JavaMethod method : messageStructureJavaClass.getMethods(true)) { 505 if (isSetterMethodToProcess(method, messageStructureJavaClass.getName())) { 506 String shortName = this.calcShortNameFromSetter(method); 507 fields.add(shortName); 508 continue; 509 } 510 if (isGetterMethodToProcess(method, messageStructureJavaClass.getName())) { 511 String shortName = this.calcShortNameFromGetter(method); 512 fields.add(shortName); 513 continue; 514 } 515 } 516 return fields; 517 } 518 519 private Set<String> getFieldsUsingPropOrder( 520 JavaClass messageStructureJavaClass) { 521 for (Annotation annotation : messageStructureJavaClass.getAnnotations()) { 522 if (annotation.getType().getJavaClass().getName().equals("XmlType")) { 523 AnnotationValue propOrderParam = annotation.getProperty("propOrder"); 524 if (propOrderParam == null) { 525 continue; 526 } 527 Object propOrderValue = propOrderParam.getParameterValue(); 528 if (!(propOrderValue instanceof List)) { 529 continue; 530 } 531 Set<String> fields = new LinkedHashSet(); 532 for (Object value : (List) propOrderValue) { 533 if (value instanceof String) { 534 String shortName = (String) value; 535 shortName = this.stripQuotes(shortName); 536 if (shortName.contains(".Elements.")) { 537 String newShortName = getShortNameFromElements(shortName, messageStructureJavaClass); 538 if (newShortName == null) { 539 continue; 540 } 541 shortName = newShortName; 542 } else if (shortName.startsWith("CoreConstants.CommonElements.")) { 543 String newShortName = getCoreConstants(shortName); 544 if (newShortName == null) { 545 continue; 546 } 547 shortName = newShortName; 548 } 549 if (shortName.equals("_futureElements")) { 550 continue; 551 } 552 shortName = this.initUpper(shortName); 553 fields.add(shortName); 554 } 555 } 556 return fields; 557 } 558 } 559 return null; 560 } 561 562 private String getShortNameFromElements(String shortName, JavaClass messageStructureJavaClass) { 563 JavaClass elementsJavaClass = messageStructureJavaClass.getNestedClassByName("Elements"); 564 if (elementsJavaClass == null) { 565 return null; 566 } 567 String fieldName = shortName.substring(shortName.indexOf(".Elements.") + ".Elements.".length()); 568 JavaField field = elementsJavaClass.getFieldByName(fieldName); 569 String initExpr = field.getInitializationExpression(); 570 return stripQuotes(initExpr); 571 } 572 573 private String getCoreConstants(String shortName) { 574 if (shortName.endsWith("VERSION_NUMBER")) { 575 return "versionNumber"; 576 } 577 if (shortName.endsWith("OBJECT_ID")) { 578 return "objectId"; 579 } 580 if (shortName.endsWith("ACTIVE")) { 581 return "active"; 582 } 583 if (shortName.endsWith("ACTIVE_FROM_DATE")) { 584 return "activeFromDate"; 585 } 586 if (shortName.endsWith("ACTIVE_TO_DATE")) { 587 return "activeToDate"; 588 } 589 if (shortName.endsWith("ATTRIBUTES")) { 590 return "attributes"; 591 } 592 if (shortName.endsWith("FUTURE_ELEMENTS")) { 593 return "_futureElements"; 594 } 595 throw new RuntimeException("Unknown shortName " + shortName); 596 } 597 598 private void addMessageStructure(JavaClass messageStructureJavaClass, 599 String serviceKey) { 600 Set<JavaClass> subObjectsToAdd = new LinkedHashSet(); 601 for (String shortName : this.getShortNames(messageStructureJavaClass)) { 602 JavaMethod setterMethod = findSetterMethod(messageStructureJavaClass, 603 shortName); 604 JavaMethod getterMethod = findGetterMethod(messageStructureJavaClass, 605 shortName); 606 if (getterMethod == null) { 607 if (this.validateKualiStudent) { 608 throw new IllegalArgumentException("shortName has no corresponding getter method: " 609 + messageStructureJavaClass.getFullyQualifiedName() 610 + "." + shortName); 611 } 612 } 613 JavaField beanField = this.findField(messageStructureJavaClass, 614 shortName, setterMethod); 615 if (beanField == null) { 616 String accessorType = getAccessorType(getterMethod); 617 if ("XmlAccessType.FIELD".equals(accessorType)) { 618 throw new IllegalArgumentException("Setter method has no corresponding bean field: " 619 + messageStructureJavaClass.getName() 620 + "." + getterMethod.getName()); 621 } 622 } 623 // overide the shortName if the bean field has an XmlAttribute name=xxx 624 // this catches the key=id switch 625 if (beanField != null) { 626 for (Annotation annotation : beanField.getAnnotations()) { 627 if (annotation.getType().getJavaClass().getName().equals("XmlAttribute")) { 628 Object nameValue = annotation.getNamedParameter("name"); 629 if (nameValue != null) { 630 shortName = stripQuotes(nameValue.toString()); 631 } 632 } 633 } 634 } 635 shortName = initLower(shortName); 636 MessageStructure ms = new MessageStructure(); 637 messageStructures.add(ms); 638 ms.setXmlObject(messageStructureJavaClass.getName()); 639 ms.setShortName(shortName); 640 ms.setId(ms.getXmlObject() + "." + ms.getShortName()); 641 ms.setName(calcMissing(calcName(messageStructureJavaClass, getterMethod, setterMethod, 642 beanField, shortName))); 643 ms.setType(calcType(messageStructureJavaClass, getterMethod, setterMethod, beanField, shortName)); 644 if (ms.getType().equals("Object")) { 645 System.out.println("WARNING " + ms.getId() 646 + " has Object as it's type ==> Changing to String"); 647 ms.setType("String"); 648 } else if (ms.getType().equals("ObjectList")) { 649 System.out.println( 650 "WARNING " + ms.getId() 651 + " has a list of Objects as it's type ==> Changing to List of String"); 652 ms.setType("StringList"); 653 } 654 ms.setXmlAttribute(this.calcXmlAttribute(beanField)); 655 ms.setRequired(calcRequired(getterMethod, setterMethod, beanField)); 656 ms.setReadOnly(calcReadOnly(getterMethod, setterMethod, beanField)); 657 ms.setCardinality(this.calcCardinality(messageStructureJavaClass, getterMethod, setterMethod, beanField, shortName)); 658 ms.setDescription(calcMissing(calcDescription(messageStructureJavaClass, getterMethod, setterMethod, 659 beanField))); 660 ms.setImplNotes(calcImplementationNotes(getterMethod, setterMethod, beanField)); 661 ms.setDeprecated(isDeprecated(getterMethod)); 662 ms.setStatus("???"); 663 // if (ms.getId().equals("AcademicCalendarInfo.typeKey")) { 664 // System.out.println("debug from here"); 665 // } 666 ms.setOverriden(this.calcOverridden(messageStructureJavaClass, getterMethod)); 667 JavaClass subObjToAdd = this.calcRealJavaClassOfGetterReturn(getterMethod); 668 if (subObjToAdd != null) { 669 // if (!subObjToAdd.isEnum()) { 670 if (!subObjToAdd.getName().equals("Object")) { 671 if (!subObjToAdd.getName().equals("LocaleKeyList")) { 672 if (!subObjToAdd.getName().equals("MessageGroupKeyList")) { 673 subObjectsToAdd.add(subObjToAdd); 674 } 675 } 676 } 677 // } 678 } 679 } 680 // now add all it's complex sub-objects if they haven't already been added 681 for (JavaClass subObjectToAdd : subObjectsToAdd) { 682 XmlType xmlType = xmlTypeMap.get(calcType(subObjectToAdd)); 683 if (xmlType == null) { 684 addXmlTypeAndMessageStructure(subObjectToAdd, serviceKey); 685 } else { 686 addServiceToList(xmlType, serviceKey); 687 } 688 } 689 return; 690 } 691 692 private boolean calcOverridden(JavaClass mainClass, JavaMethod getterMethod) { 693 if (getterMethod == null) { 694 return false; 695 } 696 JavaMethod infcGetter = null; 697 if (getterMethod.getParentClass().isInterface()) { 698 infcGetter = getterMethod; 699 } 700 if (infcGetter == null) { 701 infcGetter = findInterfaceMethod(mainClass, getterMethod, false); 702 } 703 if (infcGetter == null) { 704 return false; 705 } 706 Annotation annotation = this.getAnnotation(infcGetter, null, null, "Override"); 707 if (annotation != null) { 708 return true; 709 } 710 return false; 711 } 712 713 private String calcComment(JavaClass javaClass) { 714 return this.calcComment(javaClass.getComment()); 715 } 716 717 private String calcComment(String comment) { 718 return this.parseCommentVersion(comment)[0]; 719 } 720 721 private String calcVersion(JavaClass javaClass) { 722 DocletTag tag = javaClass.getTagByName("version", true); 723 if (tag != null) { 724 return tag.getValue(); 725 } 726 return this.calcVersion(javaClass.getComment()); 727 } 728 729 private String calcVersion(String comment) { 730 return this.parseCommentVersion(comment)[1]; 731 } 732 733 private String[] parseCommentVersion(String commentVersion) { 734 String[] parsed = new String[2]; 735 if (commentVersion == null) { 736 return parsed; 737 } 738 commentVersion = commentVersion.trim(); 739 int i = commentVersion.toLowerCase().indexOf("\nversion:"); 740 if (i == -1) { 741 parsed[0] = commentVersion; 742 return parsed; 743 } 744 parsed[1] = commentVersion.substring(i + "\nversion:".length()).trim(); 745 parsed[0] = commentVersion.substring(0, i).trim(); 746 747 return parsed; 748 } 749 750 private Annotation getAnnotation(JavaMethod getterMethod, 751 JavaMethod setterMethod, JavaField beanField, String type) { 752 if (beanField != null) { 753 754 for (Annotation annotation : beanField.getAnnotations()) { 755 if (annotation.getType().getJavaClass().getName().equals(type)) { 756 return annotation; 757 } 758 } 759 } 760 if (getterMethod != null) { 761 762 for (Annotation annotation : getterMethod.getAnnotations()) { 763 if (annotation.getType().getJavaClass().getName().equals(type)) { 764 return annotation; 765 } 766 } 767 } 768 if (setterMethod != null) { 769 770 for (Annotation annotation : setterMethod.getAnnotations()) { 771 if (annotation.getType().getJavaClass().getName().equals(type)) { 772 return annotation; 773 } 774 } 775 } 776 return null; 777 } 778 779 private String calcRequired(JavaMethod getterMethod, 780 JavaMethod setterMethod, JavaField beanField) { 781 Annotation annotation = this.getAnnotation(getterMethod, setterMethod, beanField, "XmlElement"); 782 if (annotation == null) { 783 annotation = this.getAnnotation(getterMethod, setterMethod, beanField, "XmlAttribute"); 784 } 785 if (annotation != null) { 786 Object required = annotation.getNamedParameter("required"); 787 if (required != null) { 788 if (required.toString().equalsIgnoreCase("true")) { 789 return "Required"; 790 } 791 } 792 } 793 if (getterMethod != null) { 794 DocletTag tag = getterMethod.getTagByName("required", true); 795 if (tag != null) { 796 if (tag.getValue() == null) { 797 return "Required"; 798 } 799 String required = "Required " + tag.getValue(); 800 return required.trim(); 801 } 802 } 803 return null; 804 } 805 806 private String calcReadOnly(JavaMethod getterMethod, 807 JavaMethod setterMethod, JavaField beanField) { 808 if (getterMethod != null) { 809 DocletTag tag = getterMethod.getTagByName("readOnly", true); 810 if (tag != null) { 811 if (tag.getValue() == null) { 812 return "Read only"; 813 } 814 String readOnly = "Read only " + tag.getValue(); 815 return readOnly.trim(); 816 } 817 } 818 return null; 819 } 820 821 private String calcImplementationNotes(JavaMethod serviceMethod) { 822 StringBuilder bldr = new StringBuilder(); 823 String newLine = ""; 824 for (DocletTag tag : serviceMethod.getTagsByName("impl", true)) { 825 bldr.append(newLine); 826 newLine = "\n"; 827 String value = tag.getValue(); 828 bldr.append(value); 829 } 830 if (hasOverride(serviceMethod)) { 831 boolean matchJustOnName = true; 832 JavaMethod overriddenMethod = findInterfaceMethod(serviceMethod.getParentClass(), serviceMethod, matchJustOnName); 833 if (overriddenMethod == null) { 834 // do it again so we can debug 835 findInterfaceMethod(serviceMethod.getParentClass(), serviceMethod, true); 836 throw new NullPointerException("could not find overridden method or method that has @Override annotation " + serviceMethod.getCallSignature()); 837 } 838 bldr.append(newLine); 839 newLine = "\n"; 840 bldr.append("Overridden method should be implemented in helper: "); 841 bldr.append(overriddenMethod.getParentClass().getName()); 842 } 843 if (bldr.length() == 0) { 844 return null; 845 } 846 return bldr.toString(); 847 } 848 849 private boolean hasOverride(JavaMethod serviceMethod) { 850 for (Annotation annotation : serviceMethod.getAnnotations()) { 851 if (annotation.getType().getJavaClass().getName().equals( 852 "Override")) { 853 return true; 854 } 855 } 856 return false; 857 } 858 859 private boolean isDeprecated(JavaMethod serviceMethod) { 860 for (Annotation annotation : serviceMethod.getAnnotations()) { 861 if (annotation.getType().getJavaClass().getName().equals( 862 "Deprecated")) { 863 return true; 864 } 865 } 866 return false; 867 } 868 869 private String calcImplementationNotes(JavaMethod getterMethod, 870 JavaMethod setterMethod, JavaField beanField) { 871 if (getterMethod != null) { 872 DocletTag tag = getterMethod.getTagByName("impl", true); 873 if (tag != null) { 874 return tag.getValue(); 875 } 876 } 877 return null; 878 } 879 880 private String calcNameFromShortName(String shortName) { 881 StringBuilder bldr = new StringBuilder(shortName.length() + 3); 882 char c = shortName.charAt(0); 883 bldr.append(Character.toUpperCase(c)); 884 boolean lastWasUpper = true; 885 for (int i = 1; i < shortName.length(); i++) { 886 c = shortName.charAt(i); 887 if (Character.isUpperCase(c)) { 888 if (!lastWasUpper) { 889 bldr.append(" "); 890 } 891 } else { 892 lastWasUpper = false; 893 } 894 bldr.append(c); 895 } 896 return bldr.toString(); 897 } 898 899 private String calcName(JavaClass mainClass, JavaMethod getterMethod, 900 JavaMethod setterMethod, JavaField beanField, String shortName) { 901 String name = this.calcNameFromTag(getterMethod, setterMethod, beanField); 902 if (name != null) { 903 return name; 904 } 905 name = this.calcNameFromNameEmbeddedInDescription(mainClass, getterMethod, setterMethod, beanField); 906 if (name != null) { 907 return name; 908 } 909 return this.calcNameFromShortName(shortName); 910 } 911 912 private String calcNameFromTag(JavaMethod getterMethod, 913 JavaMethod setterMethod, JavaField beanField) { 914 if (getterMethod != null) { 915 DocletTag tag = getterMethod.getTagByName("name", true); 916 if (tag != null) { 917 return tag.getValue(); 918 } 919 } 920 return null; 921 } 922 923 private String calcNameFromNameEmbeddedInDescription(JavaClass mainClass, JavaMethod getterMethod, 924 JavaMethod setterMethod, JavaField beanField) { 925 String nameDesc = this.calcMethodComment(mainClass, getterMethod, setterMethod, 926 beanField); 927 String[] parsed = parseNameDesc(nameDesc); 928 return parsed[0]; 929 } 930 931 private String[] parseNameDesc(String nameDesc) { 932 String[] parsed = new String[2]; 933 if (nameDesc == null) { 934 return parsed; 935 } 936 nameDesc = nameDesc.trim(); 937 if (!nameDesc.startsWith("Name:")) { 938 parsed[1] = nameDesc; 939 return parsed; 940 } 941 nameDesc = nameDesc.substring("Name:".length()).trim(); 942 int i = nameDesc.indexOf("\n"); 943 if (i == -1) { 944 parsed[0] = nameDesc.trim(); 945 return parsed; 946 } 947 parsed[0] = nameDesc.substring(0, i).trim(); 948 parsed[1] = nameDesc.substring(i).trim(); 949 return parsed; 950 } 951 952 private String calcDescription(JavaClass mainClass, JavaMethod getterMethod, 953 JavaMethod setterMethod, JavaField beanField) { 954 String nameDesc = this.calcMethodComment(mainClass, getterMethod, setterMethod, 955 beanField); 956 String[] parsed = parseNameDesc(nameDesc); 957 return parsed[1]; 958 } 959 960 private String calcMethodComment(JavaClass mainClass, JavaMethod getterMethod, 961 JavaMethod setterMethod, 962 JavaField beanField) { 963 String desc = null; 964 if (getterMethod != null) { 965 desc = getterMethod.getComment(); 966 if (isCommentNotEmpty(desc)) { 967 return desc; 968 } 969 } 970 if (setterMethod != null) { 971 desc = setterMethod.getComment(); 972 if (isCommentNotEmpty(desc)) { 973 return desc; 974 } 975 } 976 if (beanField != null) { 977 desc = beanField.getComment(); 978 if (isCommentNotEmpty(desc)) { 979 return desc; 980 } 981 } 982 desc = calcMethodCommentRecursively(mainClass, getterMethod); 983 if (isCommentNotEmpty(desc)) { 984 return desc; 985 } 986 desc = calcMethodCommentRecursively(mainClass, setterMethod); 987 if (isCommentNotEmpty(desc)) { 988 return desc; 989 } 990 return null; 991 } 992 993 private String calcMethodCommentRecursively(JavaClass mainClass, JavaMethod method) { 994 if (method == null) { 995 return null; 996 } 997 String desc = method.getComment(); 998 if (isCommentNotEmpty(desc)) { 999 return desc; 1000 } 1001 JavaMethod infcMethod = findInterfaceMethod(mainClass, method, false); 1002 if (infcMethod != null) { 1003 desc = infcMethod.getComment(); 1004 if (isCommentNotEmpty(desc)) { 1005 return desc; 1006 } 1007 } 1008 JavaMethod superMethod = findSuperMethod(method); 1009 if (superMethod != null) { 1010 desc = superMethod.getComment(); 1011 if (isCommentNotEmpty(desc)) { 1012 return desc; 1013 } 1014 } 1015 return null; 1016 } 1017 1018 private JavaMethod findSuperMethod(JavaMethod method) { 1019 // System.out.println("Searching for super method for " 1020 // + method.getParentClass().getName() + "." 1021 // + method.getCallSignature()); 1022 for (JavaMethod superMethod : method.getParentClass().getMethods(true)) { 1023 if (method.equals(superMethod)) { 1024 continue; 1025 } 1026 if (method.getCallSignature().equals(superMethod.getCallSignature())) { 1027 return superMethod; 1028 } 1029 } 1030 return null; 1031 } 1032 1033 private JavaMethod findInterfaceMethod(JavaClass mainClass, JavaMethod method, boolean matchJustOnName) { 1034 String callSig = method.getCallSignature(); 1035 if (matchJustOnName) { 1036 callSig = method.getName(); 1037 } 1038 JavaClass classToSearch = mainClass; 1039 // log ("Searching mainClass " + classToSearch.getName() + " for " + callSig, callSig); 1040 while (true) { 1041 for (JavaClass infcClass : classToSearch.getImplementedInterfaces()) { 1042 JavaMethod meth = this.findMethodOnInterfaceRecursively(infcClass, callSig, matchJustOnName); 1043 if (meth != null) { 1044 // recursionCntr = 0; 1045 return meth; 1046 } 1047 } 1048 JavaClass superClass = classToSearch.getSuperJavaClass(); 1049 if (superClass == null) { 1050 // recursionCntr = 0; 1051 // log ("Did not find " + callSig + " on " + mainClass, callSig); 1052 return null; 1053 } 1054 classToSearch = superClass; 1055 // log ("Searching superClass " + classToSearch.getName() + " for " + callSig, callSig); 1056 } 1057 } 1058 1059 // private void log (String message, String callSig) { 1060 // if (callSig.equalsIgnoreCase("getTypeKey()")) { 1061 // for (int i = 0; i < this.recursionCntr; i++) { 1062 // System.out.print (" "); 1063 // } 1064 // System.out.println (message); 1065 // } 1066 // } 1067 // private int recursionCntr = 0; 1068 private JavaMethod findMethodOnInterfaceRecursively(JavaClass infcClass, String callSig, boolean matchJustOnName) { 1069 // recursionCntr++; 1070 // log ("Searching interface " + infcClass.getName() + " for " + callSig, callSig); 1071 for (JavaMethod infcMethod : infcClass.getMethods()) { 1072 if (callSig.equals(infcMethod.getCallSignature())) { 1073 // log (callSig + " found on " + infcClass.getName() + "!!!!!!!!!!!!!!!!", callSig); 1074 // recursionCntr--; 1075 return infcMethod; 1076 } 1077 if (matchJustOnName) { 1078 if (callSig.equals(infcMethod.getName())) { 1079 return infcMethod; 1080 } 1081 } 1082 } 1083 for (JavaClass subInfc : infcClass.getImplementedInterfaces()) { 1084 // log ("Searching sub-interface " + subInfc.getName() + " for " + callSig, callSig); 1085 JavaMethod infcMethod = findMethodOnInterfaceRecursively(subInfc, callSig, matchJustOnName); 1086 if (infcMethod != null) { 1087 // recursionCntr--; 1088 return infcMethod; 1089 } 1090 } 1091 // log (callSig + " not found on " + infcClass.getName(), callSig); 1092 // this.recursionCntr--; 1093 return null; 1094 } 1095 1096 private boolean isCommentNotEmpty(String desc) { 1097 if (desc == null) { 1098 return false; 1099 } 1100 if (desc.trim().isEmpty()) { 1101 return false; 1102 } 1103 if (desc.contains("@inheritDoc")) { 1104 return false; 1105 } 1106 return true; 1107 } 1108 1109 private String getAccessorType(JavaMethod method) { 1110 String accessorType = getAccessorType(method.getAnnotations()); 1111 if (accessorType != null) { 1112 return accessorType; 1113 } 1114 accessorType = getAccessorType(method.getParentClass().getAnnotations()); 1115 return accessorType; 1116 } 1117 1118 private String getAccessorType(Annotation[] annotations) { 1119 for (Annotation annotation : annotations) { 1120 if (annotation.getType().getJavaClass().getName().equals( 1121 "XmlAccessorType")) { 1122 // System.out.println ("Looking for XmlAccessorType annotation = " 1123 // + annotation.getParameterValue ()); 1124 return annotation.getParameterValue().toString(); 1125 } 1126 } 1127 return null; 1128 } 1129 1130 private String stripQuotes(String str) { 1131 if (str.startsWith("\"")) { 1132 str = str.substring(1); 1133 } 1134 if (str.endsWith("\"")) { 1135 str = str.substring(0, str.length() - 1); 1136 } 1137 return str; 1138 } 1139 1140 private String calcMissing(String str) { 1141 if (str == null) { 1142 return "???"; 1143 } 1144 if (str.trim().isEmpty()) { 1145 return "???"; 1146 } 1147 return str; 1148 } 1149 1150 private void addServiceToList(XmlType xmlType, String serviceKey) { 1151 if (!xmlType.getService().contains(serviceKey)) { 1152 xmlType.setService(xmlType.getService() + ", " + serviceKey); 1153 } 1154 } 1155 1156 private String calcXmlAttribute(JavaField beanField) { 1157 if (beanField == null) { 1158 // TODO: worry about checking for this annotation on the method for non-field based AccessorTypes 1159 return "No"; 1160 } 1161 for (Annotation annotation : beanField.getAnnotations()) { 1162 if (annotation.getType().getJavaClass().getName().equals("XmlAttribute")) { 1163 return "Yes"; 1164 } 1165 } 1166 return "No"; 1167 } 1168 1169 private JavaField findField(JavaClass javaClass, String shortName, 1170 JavaMethod setterMethod) { 1171 JavaField field = findField(javaClass, shortName); 1172 if (field != null) { 1173 return field; 1174 } 1175 if (setterMethod != null) { 1176 String paramName = setterMethod.getParameters()[0].getName(); 1177 if (paramName.equalsIgnoreCase(shortName)) { 1178 return null; 1179 } 1180 return findField(javaClass, paramName); 1181 } 1182 return null; 1183 } 1184 1185 private JavaField findField(JavaClass javaClass, String name) { 1186 if (name == null) { 1187 return null; 1188 } 1189 for (JavaField field : javaClass.getFields()) { 1190 if (field.getName().equalsIgnoreCase(name)) { 1191 return field; 1192 } 1193 // TODO: check for shortNames that already start with is so we don't check for isIsEnrollable 1194 if (field.getName().equals("is" + name)) { 1195 return field; 1196 } 1197 } 1198 JavaClass superClass = javaClass.getSuperJavaClass(); 1199 if (superClass == null) { 1200 return null; 1201 } 1202 return findField(superClass, name); 1203 } 1204 1205 private JavaMethod findGetterMethod(JavaClass msClass, String shortName) { 1206 for (JavaMethod method : msClass.getMethods(true)) { 1207 if (method.getName().equalsIgnoreCase("get" + shortName)) { 1208 return method; 1209 } 1210 if (method.getName().toLowerCase().startsWith("is")) { 1211 if (method.getName().equalsIgnoreCase("is" + shortName)) { 1212 return method; 1213 } 1214 // shortName already has "is" in it 1215 if (method.getName().equalsIgnoreCase(shortName)) { 1216 return method; 1217 } 1218 } 1219 // TODO: followup on KimEntityResidencyInfo.getInState 1220 if (method.getName().equalsIgnoreCase("getInState") && shortName.equalsIgnoreCase( 1221 "InStateFlag")) { 1222 return method; 1223 } 1224 } 1225 return null; 1226 } 1227 1228 private JavaMethod findSetterMethod(JavaClass msClass, String shortName) { 1229 for (JavaMethod method : msClass.getMethods(true)) { 1230 if (method.getName().equals("set" + shortName)) { 1231 return method; 1232 } 1233 // TODO: check for shortNames that already start with is so we don't check for isIsEnrollable 1234 if (method.getName().equals("setIs" + shortName)) { 1235 return method; 1236 } 1237 // TODO: followup on KimEntityResidencyInfo.getInState 1238 if (method.getName().equals("setInStateFlag") && shortName.equals( 1239 "InState")) { 1240 return method; 1241 } 1242 } 1243 return null; 1244 } 1245 private static final String[] SETTER_METHODS_TO_SKIP = { 1246 // Somebody put "convenience" methods on the validation result info 1247 "ValidationResultInfo.setWarning", 1248 "ValidationResultInfo.setError", 1249 // not on original wiki but still defined as a method but not backed by a field so not in wsdl 1250 "CredentialProgramInfo.setDiplomaTitle", 1251 // synonym for the official of setCredentialType 1252 "CredentialProgramInfo.setType", 1253 // not on original wiki but still defined as a method but not backed by a field so not in wsdl 1254 "CredentialProgramInfo.setHegisCode", 1255 "CredentialProgramInfo.setCip2000Code", 1256 "CredentialProgramInfo.setCip2010Code", 1257 "CredentialProgramInfo.setSelectiveEnrollmentCode", 1258 "CoreProgramInfo.setDiplomaTitle", 1259 // synonym for the official of setCredentialType 1260 // "CoreProgramInfo.setType", 1261 // not on original wiki but still defined as a method but not backed by a field so not in wsdl 1262 "CoreProgramInfo.setHegisCode", 1263 "CoreProgramInfo.setCip2000Code", 1264 "CoreProgramInfo.setCip2010Code", 1265 "CoreProgramInfo.setSelectiveEnrollmentCode", 1266 "WhenConstraint.setValue" 1267 }; 1268 private static final String[] GETTER_METHODS_TO_SKIP = { 1269 // Somebody put "convenience" methods on the validation result info 1270 "ValidationResultInfo.getWarning", 1271 "ValidationResultInfo.getError", 1272 // not on original wiki but still defined as a method but not backed by a field so not in wsdl 1273 "CredentialProgramInfo.getDiplomaTitle", 1274 // synonym for the official of setCredentialType 1275 "CredentialProgramInfo.getType", 1276 // not on original wiki but still defined as a method but not backed by a field so not in wsdl 1277 "CredentialProgramInfo.getHegisCode", 1278 "CredentialProgramInfo.getCip2000Code", 1279 "CredentialProgramInfo.getCip2010Code", 1280 "CredentialProgramInfo.getSelectiveEnrollmentCode", 1281 "CoreProgramInfo.getDiplomaTitle", 1282 // synonym for the official of setCredentialType 1283 // "CoreProgramInfo.setType", 1284 // not on original wiki but still defined as a method but not backed by a field so not in wsdl 1285 "CoreProgramInfo.getHegisCode", 1286 "CoreProgramInfo.getCip2000Code", 1287 "CoreProgramInfo.getCip2010Code", 1288 "CoreProgramInfo.getSelectiveEnrollmentCode", 1289 "WhenConstraint.getValue" 1290 }; 1291 1292 private boolean isSetterMethodToProcess(JavaMethod method, String className) { 1293 if (!method.getName().startsWith("set")) { 1294 return false; 1295 } 1296 if (method.getParameters().length != 1) { 1297 return false; 1298 } 1299 if (method.isPrivate()) { 1300 return false; 1301 } 1302 if (method.isProtected()) { 1303 return false; 1304 } 1305 if (method.isStatic()) { 1306 return false; 1307 } 1308 if (method.getParentClass().getPackageName().startsWith("java")) { 1309 return false; 1310 } 1311 String fullName = className + "." + method.getName(); 1312 for (String skip : SETTER_METHODS_TO_SKIP) { 1313 if (skip.equals(fullName)) { 1314 return false; 1315 } 1316 } 1317 // if (method.getParentClass ().isInterface ()) 1318 // { 1319 // return false; 1320 // } 1321 for (Annotation annotation : method.getAnnotations()) { 1322 if (annotation.getType().getJavaClass().getName().equals("XmlTransient")) { 1323 return false; 1324 } 1325 } 1326 return true; 1327 } 1328 1329 private boolean isGetterMethodToProcess(JavaMethod method, String className) { 1330 if (!method.getName().startsWith("get")) { 1331 if (!method.getName().startsWith("is")) { 1332 return false; 1333 } 1334 } 1335 if (method.getParameters().length != 0) { 1336 return false; 1337 } 1338 if (method.isPrivate()) { 1339 return false; 1340 } 1341 if (method.isProtected()) { 1342 return false; 1343 } 1344 if (method.isStatic()) { 1345 return false; 1346 } 1347 if (method.getParentClass().getPackageName().startsWith("java")) { 1348 return false; 1349 } 1350 String fullName = className + "." + method.getName(); 1351 for (String skip : GETTER_METHODS_TO_SKIP) { 1352 if (skip.equals(fullName)) { 1353 return false; 1354 } 1355 } 1356 // if (method.getParentClass ().isInterface ()) 1357 // { 1358 // return false; 1359 // } 1360 for (Annotation annotation : method.getAnnotations()) { 1361 if (annotation.getType().getJavaClass().getName().equals("XmlTransient")) { 1362 return false; 1363 } 1364 } 1365 return true; 1366 } 1367 1368 private String calcShortNameFromSetter(JavaMethod method) { 1369 return method.getName().substring(3); 1370 } 1371 1372 private String calcShortNameFromGetter(JavaMethod method) { 1373 if (method.getName().startsWith("get")) { 1374 return method.getName().substring(3); 1375 } 1376 if (method.getName().startsWith("is")) { 1377 return method.getName().substring(2); 1378 } 1379 throw new IllegalArgumentException(method.getName() 1380 + " does not start with is or get"); 1381 } 1382 1383 private String calcCardinality(JavaClass mainClass, JavaMethod getterMethod, 1384 JavaMethod setterMethod, JavaField beanField, String shortName) { 1385 if (isReturnACollection(mainClass, getterMethod, setterMethod, beanField, shortName)) { 1386 return "Many"; 1387 } 1388 return "One"; 1389 } 1390 1391 private boolean isReturnACollection(JavaClass mainClass, JavaMethod getterMethod, 1392 JavaMethod setterMethod, JavaField beanField, String shortName) { 1393 if (getterMethod != null) { 1394 return isCollection(getterMethod.getReturnType()); 1395 } 1396 if (beanField != null) { 1397 return isCollection(beanField.getType()); 1398 } 1399 // TODO: check setterMethod 1400 return false; 1401 } 1402 1403 private boolean isCollection(Type type) { 1404 JavaClass javaClass = type.getJavaClass(); 1405 return this.isCollection(javaClass); 1406 } 1407 1408 private boolean isCollection(JavaClass javaClass) { 1409 if (javaClass.getName().equals("LocalKeyList")) { 1410 return true; 1411 } 1412 if (javaClass.getName().equals("MessageGroupKeyList")) { 1413 return true; 1414 } 1415 if (javaClass.getName().equals(List.class.getSimpleName())) { 1416 return true; 1417 } 1418 if (javaClass.getName().equals(ArrayList.class.getSimpleName())) { 1419 return true; 1420 } 1421 if (javaClass.getName().equals(Collection.class.getSimpleName())) { 1422 return true; 1423 } 1424 if (javaClass.getName().equals(Set.class.getSimpleName())) { 1425 return true; 1426 } 1427 return false; 1428 } 1429 1430 private String calcType(JavaClass mainClass, JavaMethod getterMethod, 1431 JavaMethod setterMethod, JavaField beanField, String shortName) { 1432 if (getterMethod != null) { 1433 return calcTypeOfGetterMethodReturn(getterMethod); 1434 } 1435 if (beanField != null) { 1436 Type type = beanField.getType(); 1437 return calcType(type); 1438 } 1439 // TODO: calc type based on the setterMethod 1440 return null; 1441 } 1442 1443 private String calcTypeOfGetterMethodReturn(JavaMethod getterMethod) { 1444 Type type = getterMethod.getReturnType(); 1445 return calcType(type); 1446 } 1447 1448 private String calcTypeOfSetterMethodFirstParam(JavaMethod setterMethod) { 1449 JavaParameter param = setterMethod.getParameters()[0]; 1450 return calcType(param); 1451 } 1452 1453 private String calcType(JavaParameter parameter) { 1454 return calcType(parameter.getType()); 1455 } 1456 1457 private String calcType(Type type) { 1458 if (type == null) { 1459 return "void"; 1460 } 1461 if (isCollection(type.getJavaClass())) { 1462 return calcType(calcRealJavaClass(type)) + "List"; 1463 } 1464 return calcType(calcRealJavaClass(type)); 1465 } 1466 1467 private String calcType(JavaClass javaClass) { 1468 if (javaClass.isEnum()) { 1469 // TODO: instead of hand mapping this take it based on the class in the @XmlEnum(String.class) tag 1470 if (javaClass.getName().equals("ErrorLevel")) { 1471 return "Integer"; 1472 } 1473 if (javaClass.getName().equals("StatementOperatorTypeKey")) { 1474 return "String"; 1475 } 1476 if (javaClass.getName().equals("WriteAccess")) { 1477 return "String"; 1478 } 1479 if (javaClass.getName().equals("Widget")) { 1480 return "String"; 1481 } 1482 if (javaClass.getName().equals("DataType")) { 1483 return "String"; 1484 } 1485 if (javaClass.getName().equals("SortDirection")) { 1486 return "String"; 1487 } 1488 if (javaClass.getName().equals("Usage")) { 1489 return "String"; 1490 } 1491 if (javaClass.getName().equals("StatementOperator")) { 1492 return "String"; 1493 } 1494 } 1495 // this is messed up instead of list of strings it is an object with a list of strings 1496 if (javaClass.getName().equals(LOCALE_KEY_LIST)) { 1497 return "StringList"; 1498 } 1499 if (javaClass.getName().equals(MESSAGE_GROUP_KEY_LIST)) { 1500 return "StringList"; 1501 } 1502 // TODO: figure out why rice stuff translates like this junk? 1503 if (javaClass.getName().equals("java$util$Map")) { 1504 return "Map<String, String>"; 1505 } 1506 if (javaClass.getName().equals("Map")) { 1507 // TODO: make sure it is in fact a String,String map 1508 return "Map<String, String>"; 1509 } 1510 return javaClass.getName(); 1511 } 1512 1513 private JavaClass calcRealJavaClassOfGetterReturn(JavaMethod getterMethod) { 1514 if (getterMethod == null) { 1515 return null; 1516 } 1517 Type type = getterMethod.getReturnType(); 1518 return this.calcRealJavaClass(type); 1519 } 1520 1521 private JavaClass calcRealJavaClassOfSetterFirstParam(JavaMethod setterMethod) { 1522 JavaParameter param = setterMethod.getParameters()[0]; 1523 return this.calcRealJavaClass(param); 1524 } 1525 1526 private JavaClass calcRealJavaClass(JavaParameter param) { 1527 Type type = param.getType(); 1528 return calcRealJavaClass(type); 1529 } 1530 1531 private JavaClass calcRealJavaClass(Type type) { 1532 if (type == null) { 1533 return null; 1534 } 1535 JavaClass javaClass = type.getJavaClass(); 1536 if (javaClass.getName().equals(LOCALE_KEY_LIST)) { 1537 return STRING_JAVA_CLASS; 1538 } 1539 if (javaClass.getName().equals(MESSAGE_GROUP_KEY_LIST)) { 1540 return STRING_JAVA_CLASS; 1541 } 1542 if (!this.isCollection(javaClass)) { 1543 return javaClass; 1544 } 1545 1546 // for (Type t : type.getActualTypeArguments ()) 1547 // { 1548 // System.out.println ("ServiceContractModelQDoxLoader: type arguments = " 1549 // + t.toString ()); 1550 // } 1551 1552 Type[]collectionTypeArguments = type.getActualTypeArguments(); 1553 1554 if (collectionTypeArguments == null) 1555 return new JavaClass (Object.class.getName()); 1556 else 1557 return collectionTypeArguments[0].getJavaClass(); 1558 } 1559 1560 private boolean isComplex(JavaClass javaClass) { 1561 if (javaClass.isEnum()) { 1562 return false; 1563 } 1564 if (javaClass.getName().equals(String.class.getSimpleName())) { 1565 return false; 1566 } 1567 if (javaClass.getName().equals(Integer.class.getSimpleName())) { 1568 return false; 1569 } 1570 if (javaClass.getName().equals(Date.class.getSimpleName())) { 1571 return false; 1572 } 1573 if (javaClass.getName().equals(Long.class.getSimpleName())) { 1574 return false; 1575 } 1576 if (javaClass.getName().equals(Boolean.class.getSimpleName())) { 1577 return false; 1578 } 1579 if (javaClass.getName().equals(Double.class.getSimpleName())) { 1580 return false; 1581 } 1582 if (javaClass.getName().equals(Float.class.getSimpleName())) { 1583 return false; 1584 } 1585 if (javaClass.getName().equals(int.class.getSimpleName())) { 1586 return false; 1587 } 1588 if (javaClass.getName().equals(long.class.getSimpleName())) { 1589 return false; 1590 } 1591 if (javaClass.getName().equals(boolean.class.getSimpleName())) { 1592 return false; 1593 } 1594 if (javaClass.getName().equals(double.class.getSimpleName())) { 1595 return false; 1596 } 1597 if (javaClass.getName().equals(float.class.getSimpleName())) { 1598 return false; 1599 } 1600 if (javaClass.getName().equals(Map.class.getSimpleName())) { 1601 return false; 1602 } 1603 1604 if (javaClass.getName().equals(String.class.getName())) { 1605 return false; 1606 } 1607 if (javaClass.getName().equals(Integer.class.getName())) { 1608 return false; 1609 } 1610 if (javaClass.getName().equals(Date.class.getName())) { 1611 return false; 1612 } 1613 if (javaClass.getName().equals(Long.class.getName())) { 1614 return false; 1615 } 1616 if (javaClass.getName().equals(Boolean.class.getName())) { 1617 return false; 1618 } 1619 if (javaClass.getName().equals(Double.class.getName())) { 1620 return false; 1621 } 1622 if (javaClass.getName().equals(Float.class.getName())) { 1623 return false; 1624 } 1625 if (javaClass.getName().equals(int.class.getName())) { 1626 return false; 1627 } 1628 if (javaClass.getName().equals(long.class.getName())) { 1629 return false; 1630 } 1631 if (javaClass.getName().equals(boolean.class.getName())) { 1632 return false; 1633 } 1634 if (javaClass.getName().equals(double.class.getName())) { 1635 return false; 1636 } 1637 if (javaClass.getName().equals(float.class.getName())) { 1638 return false; 1639 } 1640 if (javaClass.getName().equals(Map.class.getName())) { 1641 return false; 1642 } 1643 if (javaClass.getName().equals(LOCALE_KEY_LIST)) { 1644 return false; 1645 } 1646 if (javaClass.getName().equals(MESSAGE_GROUP_KEY_LIST)) { 1647 return false; 1648 } 1649 if (javaClass.getName().equals("java$util$Map")) { 1650 return false; 1651 } 1652 return true; 1653 } 1654 }