001 /** 002 * Copyright 2004-2014 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.opensource.org/licenses/ecl2.php 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.mock.mojo; 017 018 import org.kuali.student.contract.model.Service; 019 import org.kuali.student.contract.model.ServiceContractModel; 020 import org.kuali.student.contract.model.ServiceMethod; 021 import org.kuali.student.contract.model.ServiceMethodError; 022 import org.kuali.student.contract.model.ServiceMethodParameter; 023 import org.kuali.student.contract.model.XmlType; 024 import org.kuali.student.contract.model.impl.ServiceContractModelPescXsdLoader; 025 import org.kuali.student.contract.model.util.ModelFinder; 026 import org.kuali.student.contract.writer.JavaClassWriter; 027 import org.kuali.student.contract.writer.service.GetterSetterNameCalculator; 028 import org.kuali.student.contract.writer.service.MessageStructureTypeCalculator; 029 import org.kuali.student.contract.writer.service.ServiceExceptionWriter; 030 import org.slf4j.Logger; 031 import org.slf4j.LoggerFactory; 032 033 import java.util.*; 034 035 /** 036 * 037 * @author nwright 038 */ 039 public class MockImplServiceWriter extends JavaClassWriter { 040 041 private static Logger log = LoggerFactory.getLogger(MockImplServiceWriter.class); 042 043 ////////////////////////////// 044 // Constants 045 ////////////////////////////// 046 047 /** 048 * The standard type of methods used in our Service contract. 049 */ 050 protected static enum MethodType { 051 052 VALIDATE, 053 CREATE, 054 CREATE_BULK, 055 ADD, 056 UPDATE, 057 UPDATE_OTHER, 058 DELETE, 059 REMOVE, 060 DELETE_OTHER, 061 GET_CREATE, 062 GET_BY_ID, 063 GET_BY_IDS, 064 RICE_GET_BY_NAMESPACE_AND_NAME, 065 GET_IDS_BY_TYPE, 066 GET_IDS_BY_OTHER, 067 GET_INFOS_BY_OTHER, 068 GET_TYPE, 069 GET_TYPES, 070 UNKNOWN 071 }; 072 073 ////////////////////////////// 074 // Data Variables 075 ////////////////////////////// 076 077 protected ServiceContractModel model; 078 protected ModelFinder finder; 079 private String directory; 080 /** 081 * The package name is stored in the service object itself (the package spec kept 082 * moving around so I assumed the actual service name was unique but ran into a problem 083 * when we included rice because they have a StateService meaning US states and we have 084 * a StateService meaning the state of the object so I added logic to detect rice and 085 * prepend that "RICE." to it 086 */ 087 private String rootPackage; 088 089 /** 090 * Name of the service being operated on. 091 * If it is a RICE service it is prefixed with RICE. 092 * [11:32:18 AM] Norman Wright: short name... I think it gets it by taking the java class SimpleName and stripping off the word "Service" and I think making it lower case. 093 * [11:32:24 AM] Norman Wright: so OrganizationService becomes organization 094 */ 095 protected String servKey; 096 097 protected List<ServiceMethod> methods; 098 099 /** 100 * A flag that holds if the service is an R1 service. 101 */ 102 private boolean isR1; 103 104 ////////////////////////// 105 // Constructor 106 ////////////////////////// 107 108 public MockImplServiceWriter(ServiceContractModel model, 109 String directory, 110 String rootPackage, 111 String servKey, 112 List<ServiceMethod> methods, 113 boolean isR1) { 114 super(directory, calcPackage(servKey, rootPackage), calcClassName(servKey)); 115 this.model = model; 116 this.finder = new ModelFinder(model); 117 this.directory = directory; 118 this.rootPackage = rootPackage; 119 this.servKey = servKey; 120 this.methods = methods; 121 this.isR1 = isR1; 122 } 123 124 public MockImplServiceWriter(ServiceContractModel model, 125 String directory, 126 String rootPackage, 127 String servKey, 128 List<ServiceMethod> methods, 129 boolean isR1, 130 String packageName, 131 String className) { 132 super(directory, packageName, className); 133 this.model = model; 134 this.finder = new ModelFinder(model); 135 this.directory = directory; 136 this.rootPackage = rootPackage; 137 this.servKey = servKey; 138 this.methods = methods; 139 this.isR1 = isR1; 140 } 141 142 ///////////////////////// 143 // Functional Methods 144 ///////////////////////// 145 146 /** 147 * Returns the mock implementation package name. 148 * @param servKey 149 * @param rootPackage 150 * @return 151 */ 152 public static String calcPackage(String servKey, String rootPackage) { 153 String pack = rootPackage + "."; 154 // String pack = rootPackage + "." + servKey.toLowerCase() + "."; 155 // StringBuffer buf = new StringBuffer (service.getVersion ().length ()); 156 // for (int i = 0; i < service.getVersion ().length (); i ++) 157 // { 158 // char c = service.getVersion ().charAt (i); 159 // c = Character.toLowerCase (c); 160 // if (Character.isLetter (c)) 161 // { 162 // buf.append (c); 163 // continue; 164 // } 165 // if (Character.isDigit (c)) 166 // { 167 // buf.append (c); 168 // } 169 // } 170 // pack = pack + buf.toString (); 171 pack = pack + "service.impl.mock"; 172 return pack; 173 } 174 175 /** 176 * Checks if this is a RICE service. 177 * @return true if this is a RICE service. 178 */ 179 private boolean isRice() { 180 if (this.servKey.startsWith("RICE.")) { 181 return true; 182 } 183 return false; 184 } 185 186 protected static String fixServKey(String servKey) { 187 if (servKey.startsWith("RICE.")) { 188 return servKey.substring("RICE.".length()); 189 } 190 return servKey; 191 } 192 193 /** 194 * Given the service key (name), returns a calculated class name for the mock impl. 195 */ 196 public static String calcClassName(String servKey) { 197 return GetterSetterNameCalculator.calcInitUpper(fixServKey(servKey) + "ServiceMockImpl"); 198 } 199 200 public static String calcServiceInterfaceClassName(String servKey) { 201 return GetterSetterNameCalculator.calcInitUpper(fixServKey(servKey) + "Service"); 202 } 203 204 /** 205 * Analyses the method and returns a MethodType enum that describes what type of method this is. 206 */ 207 protected MethodType calcMethodType(ServiceMethod method) { 208 if (this.isRice()) { 209 if (method.getName().contains("ByNamespaceCodeAndName")) { 210 return MethodType.RICE_GET_BY_NAMESPACE_AND_NAME; 211 } 212 if (method.getName().contains("ByNameAndNamespace")) { 213 return MethodType.RICE_GET_BY_NAMESPACE_AND_NAME; 214 } 215 if (method.getName().startsWith("get")) { 216 if (method.getParameters().size() == 1) { 217 if (!method.getReturnValue().getType().endsWith("List")) { 218 if (method.getParameters().get(0).getName().equals("id")) { 219 return MethodType.GET_BY_ID; 220 } 221 222 } else { 223 if (method.getParameters().get(0).getName().equals("ids")) { 224 return MethodType.GET_BY_IDS; 225 } 226 } 227 } 228 } 229 } 230 if (method.getName().startsWith("validate")) { 231 return MethodType.VALIDATE; 232 } 233 if (method.getName().startsWith("create")) { 234 if (this.findInfoParameter(method) != null) { 235 return MethodType.CREATE; 236 } 237 return MethodType.CREATE_BULK; 238 } 239 if (method.getName().startsWith("add")) { 240 return MethodType.ADD; 241 } 242 if (method.getName().startsWith("update")) { 243 if (this.findInfoParameter(method) != null) { 244 return MethodType.UPDATE; 245 } 246 return MethodType.UPDATE_OTHER; 247 } 248 if (method.getName().startsWith("delete")) { 249 if (method.getName().contains("By")) { 250 if (!method.getName().startsWith("deleteBy")) { 251 return MethodType.DELETE_OTHER; 252 } 253 } 254 if (method.getName().contains("For")) { 255 if (!method.getName().startsWith("deleteFor")) { 256 return MethodType.DELETE_OTHER; 257 } 258 } 259 return MethodType.DELETE; 260 } 261 if (method.getName().startsWith("remove")) { 262 return MethodType.REMOVE; 263 } 264 265 if (method.getName().startsWith("getCreate")) { 266 return MethodType.GET_CREATE; 267 } 268 269 if (method.getName().startsWith("get")) { 270 if (method.getName().endsWith("ByIds")) { 271 return MethodType.GET_BY_IDS; 272 } 273 if (method.getName().endsWith("ByType")) { 274 return MethodType.GET_IDS_BY_TYPE; 275 } 276 if (method.getReturnValue().getType().endsWith("TypeInfo")) { 277 return MethodType.GET_TYPE; 278 } 279 if (method.getReturnValue().getType().endsWith("TypeInfoList")) { 280 return MethodType.GET_TYPES; 281 } 282 if (method.getName().endsWith("ByType")) { 283 return MethodType.GET_IDS_BY_TYPE; 284 } 285 if (method.getParameters().size() >= 1 && method.getParameters().size() <= 2) { 286 if (!method.getReturnValue().getType().endsWith("List")) { 287 if (method.getParameters().get(0).getName().endsWith("Id")) { 288 return MethodType.GET_BY_ID; 289 } 290 } 291 } 292 if (method.getName().contains("By")) { 293 if (method.getReturnValue().getType().equals("StringList")) { 294 return MethodType.GET_IDS_BY_OTHER; 295 } 296 if (method.getReturnValue().getType().endsWith("InfoList")) { 297 return MethodType.GET_INFOS_BY_OTHER; 298 } 299 } 300 } 301 302 return MethodType.UNKNOWN; 303 } 304 305 /** 306 * Write out the entire file 307 */ 308 public void write() { 309 indentPrint("public class " + calcClassName(servKey)); 310 println(" implements MockService, " + calcServiceInterfaceClassName(servKey)); 311 importsAdd ("org.kuali.student.common.mock.MockService"); 312 Service serv = finder.findService(servKey); 313 importsAdd(serv.getImplProject() + "." + serv.getName()); 314 openBrace(); 315 // put all the cache variables at the top 316 indentPrintln("// cache variable "); 317 indentPrintln("// The LinkedHashMap is just so the values come back in a predictable order"); 318 cacheVariablesWritten.clear(); 319 for (ServiceMethod method : methods) { 320 MethodType methodType = calcMethodType(method); 321 switch (methodType) { 322 case CREATE: 323 case ADD: 324 case GET_TYPE: 325 case GET_BY_ID: 326 writeCacheVariable(method); 327 } 328 } 329 println (""); 330 indentPrintln ("@Override"); 331 indentPrintln ("public void clear()"); 332 openBrace (); 333 cacheVariablesWritten.clear(); 334 for (ServiceMethod method : methods) { 335 MethodType methodType = calcMethodType(method); 336 switch (methodType) { 337 case CREATE: 338 case ADD: 339 case GET_TYPE: 340 case GET_BY_ID: 341 writeCacheVariableClear(method); 342 } 343 } 344 closeBrace (); 345 println (""); 346 347 for (ServiceMethod method : methods) { 348 MethodType methodType = calcMethodType(method); 349 indentPrintln(""); 350 // indentPrintln("/**"); 351 // indentPrintWrappedComment(method.getDescription()); 352 // indentPrintln("* "); 353 // for (ServiceMethodParameter param : method.getParameters()) { 354 // indentPrintWrappedComment("@param " + param.getName() + " - " 355 // + param.getType() + " - " 356 // + param.getDescription()); 357 // } 358 // indentPrintWrappedComment("@return " + method.getReturnValue(). 359 // getDescription()); 360 // indentPrintln("*/"); 361 indentPrintln("@Override"); 362 String type = method.getReturnValue().getType(); 363 String realType = stripList(type); 364 indentPrint("public " + calcType(type, realType) + " " + method.getName() 365 + "("); 366 // now do parameters 367 String comma = ""; 368 for (ServiceMethodParameter param : method.getParameters()) { 369 type = param.getType(); 370 realType = stripList(type); 371 print(comma); 372 373 String calculatedType = realType; 374 375 try { 376 377 calculatedType = calcType(type, realType); 378 379 } 380 catch (Exception e) { 381 log.warn(String.format("Method (%s) : failed to calculate type (%s), real type (%s)", method.getName(), type, realType), e); 382 } 383 384 print(calculatedType); 385 386 print(" "); 387 print(param.getName()); 388 comma = ", "; 389 } 390 println(")"); 391 // now do exceptions 392 comma = "throws "; 393 incrementIndent(); 394 for (ServiceMethodError error : method.getErrors()) { 395 indentPrint(comma); 396 String exceptionClassName = calcExceptionClassName(error); 397 String exceptionPackageName = this.calcExceptionPackageName(error); 398 println(exceptionClassName); 399 this.importsAdd(exceptionPackageName + "." + exceptionClassName); 400 comma = " ,"; 401 } 402 decrementIndent(); 403 openBrace(); 404 indentPrintln("// " + methodType); 405 switch (methodType) { 406 case VALIDATE: 407 writeValidate(method); 408 break; 409 case CREATE: 410 writeCreate(method); 411 break; 412 case ADD: 413 writeAdd(method); 414 break; 415 case UPDATE: 416 writeUpdate(method); 417 break; 418 case DELETE: 419 writeDelete(method); 420 break; 421 case REMOVE: 422 writeRemove(method); 423 break; 424 case GET_BY_ID: 425 writeGetById(method); 426 break; 427 case GET_BY_IDS: 428 writeGetByIds(method); 429 break; 430 case GET_IDS_BY_TYPE: 431 writeGetIdsByType(method); 432 break; 433 case GET_IDS_BY_OTHER: 434 writeGetIdsByOther(method); 435 break; 436 case GET_INFOS_BY_OTHER: 437 writeGetInfosByOther(method); 438 break; 439 case GET_TYPE: 440 writeGetType(method); 441 break; 442 case GET_TYPES: 443 writeGetTypes(method); 444 break; 445 case RICE_GET_BY_NAMESPACE_AND_NAME: 446 writeRiceGetByNamespaceAndName(method); 447 break; 448 default: 449 writeThrowsNotImplemented(method); 450 } 451 closeBrace(); 452 453 } 454 455 writeBoilerPlate(); 456 closeBrace(); 457 458 this.writeJavaClassAndImportsOutToFile(); 459 this.getOut().close(); 460 } 461 462 private String getInvalidParameterException() { 463 if (this.isRice()) { 464 return "RiceIllegalArgumentException"; 465 } 466 return "InvalidParameterException"; 467 } 468 469 private String getOperationFailedException() { 470 if (this.isRice()) { 471 return "RiceIllegalArgumentException"; 472 } 473 return "OperationFailedException"; 474 } 475 476 private String getDoesNotExistException() { 477 if (this.isRice()) { 478 return "RiceIllegalArgumentException"; 479 } 480 return "DoesNotExistException"; 481 } 482 483 private String getVersionMismatchException() { 484 if (this.isRice()) { 485 return "RiceIllegalStateException"; 486 } 487 return "VersionMismatchException"; 488 } 489 490 private void writeThrowsNotImplemented(ServiceMethod method) { 491 indentPrintln("throw new " + this.getOperationFailedException() + " (\"" + method.getName() + " has not been implemented\");"); 492 } 493 494 protected String initLower(String str) { 495 return str.substring(0, 1).toLowerCase() + str.substring(1); 496 } 497 498 private void writeBoilerPlate() { 499 if (this.isRice()) { 500 return; 501 } 502 indentPrintln(""); 503 indentPrintln("private StatusInfo newStatus() {"); 504 indentPrintln(" StatusInfo status = new StatusInfo();"); 505 indentPrintln(" status.setSuccess(Boolean.TRUE);"); 506 indentPrintln(" return status;"); 507 indentPrintln("}"); 508 if (isR1) { 509 this.writeBoilerPlateR1(); 510 } else { 511 this.writeBoilerPlateR2(); 512 } 513 } 514 515 private void writeBoilerPlateR1() { 516 importsAdd("org.kuali.student.common.dto.MetaInfo"); 517 indentPrintln(""); 518 519 indentPrintln("private MetaInfo newMeta() {"); 520 indentPrintln(" MetaInfo meta = new MetaInfo();"); 521 indentPrintln(" meta.setCreateId(\"MOCKUSER\");"); 522 importsAdd(Date.class.getName()); 523 indentPrintln(" meta.setCreateTime(new Date());"); 524 indentPrintln(" meta.setUpdateId(\"MOCKUSER\");"); 525 indentPrintln(" meta.setUpdateTime(meta.getCreateTime());"); 526 indentPrintln(" meta.setVersionInd(\"0\");"); 527 indentPrintln(" return meta;"); 528 indentPrintln("}"); 529 indentPrintln(""); 530 indentPrintln("private MetaInfo updateMeta(MetaInfo meta) {"); 531 indentPrintln(" meta.setUpdateId(\"MOCKUSER\");"); 532 indentPrintln(" meta.setUpdateTime(new Date());"); 533 indentPrintln(" meta.setVersionInd((Integer.parseInt(meta.getVersionInd()) + 1) + \"\");"); 534 indentPrintln(" return meta;"); 535 indentPrintln("}"); 536 indentPrintln(""); 537 538 } 539 540 private void writeBoilerPlateR2() { 541 importsAdd("org.kuali.student.r2.common.dto.MetaInfo"); 542 indentPrintln(""); 543 544 indentPrintln("private MetaInfo newMeta(ContextInfo context) {"); 545 indentPrintln(" MetaInfo meta = new MetaInfo();"); 546 indentPrintln(" meta.setCreateId(context.getPrincipalId());"); 547 importsAdd(Date.class.getName()); 548 indentPrintln(" meta.setCreateTime(new Date());"); 549 indentPrintln(" meta.setUpdateId(context.getPrincipalId());"); 550 indentPrintln(" meta.setUpdateTime(meta.getCreateTime());"); 551 indentPrintln(" meta.setVersionInd(\"0\");"); 552 indentPrintln(" return meta;"); 553 indentPrintln("}"); 554 indentPrintln(""); 555 indentPrintln("private MetaInfo updateMeta(MetaInfo old, ContextInfo context) {"); 556 indentPrintln(" MetaInfo meta = new MetaInfo(old);"); 557 indentPrintln(" meta.setUpdateId(context.getPrincipalId());"); 558 indentPrintln(" meta.setUpdateTime(new Date());"); 559 indentPrintln(" meta.setVersionInd((Integer.parseInt(meta.getVersionInd()) + 1) + \"\");"); 560 indentPrintln(" return meta;"); 561 indentPrintln("}"); 562 indentPrintln(""); 563 564 } 565 566 private void writeValidate(ServiceMethod method) { 567 indentPrintln("return new ArrayList<ValidationResultInfo> ();"); 568 this.importsAdd(ArrayList.class.getName()); 569 } 570 private Set<String> cacheVariablesWritten = new HashSet<String>(); 571 572 private void writeCacheVariable(ServiceMethod method) { 573 String objectName = calcObjectName(method); 574 if (!this.isRice()) { 575 objectName = objectName + "Info"; 576 } 577 String mapName = calcMapName(method); 578 if (cacheVariablesWritten.add(mapName)) { 579 indentPrintln("private Map<String, " + objectName + "> " + mapName + " = new LinkedHashMap<String, " + objectName + ">();"); 580 importsAdd(Map.class.getName()); 581 importsAdd(LinkedHashMap.class.getName()); 582 } 583 } 584 585 private void writeCacheVariableClear(ServiceMethod method) { 586 String objectName = calcObjectName(method); 587 if (!this.isRice()) { 588 objectName = objectName + "Info"; 589 } 590 String mapName = calcMapName(method); 591 if (cacheVariablesWritten.add(mapName)) { 592 indentPrintln("this." + mapName + ".clear ();"); 593 } 594 } 595 596 private void writeCreate(ServiceMethod method) { 597 ServiceMethodParameter typeParam = this.findTypeParameter(method); 598 ServiceMethodParameter infoParam = this.findInfoParameter(method); 599 ServiceMethodParameter contextParam = this.findContextParameter(method); 600 String objectName = calcObjectName(method); 601 String infoName = objectName; 602 if (!this.isRice()) { 603 infoName = infoName + "Info"; 604 } 605 String mapName = calcMapName(method); 606 607 if (this.isRice()) { 608 indentPrintln(infoName + " orig = this.get" + infoName + "ByNamespaceCodeAndName(" + infoParam.getName() + ".getNamespaceCode(), " + infoParam.getName() + ".getName());"); 609 indentPrintln("if (orig != null)"); 610 openBrace(); 611 indentPrintln("throw new RiceIllegalArgumentException (" + infoParam.getName() + ".getNamespaceCode() + \".\" + " + infoParam.getName() + ".getName());"); 612 closeBrace(); 613 } 614 if (typeParam != null) { 615 indentPrintln("if (!" + typeParam.getName() + ".equals (" + infoParam.getName() + ".getTypeKey())) {"); 616 indentPrintln(" throw new " + this.getInvalidParameterException() + " (\"The type parameter does not match the type on the info object\");"); 617 indentPrintln("}"); 618 } 619 if (method.getParameters().size() > 3) { 620 indentPrintln("// TODO: check the rest of the readonly fields that are specified on the create to make sure they match the info object"); 621 } 622 if (this.isR1) { 623 indentPrintln("// don't have deep copy in R1 contracts so just use the object"); 624 indentPrintln(infoName + " copy = " + infoParam.getName() + ";"); 625 } else if (this.isRice()) { 626 indentPrintln(infoName + ".Builder copy = " + infoName + ".Builder.create (" + infoParam.getName() + ");"); 627 } else { 628 indentPrintln(infoName + " copy = new " + infoName + "(" + infoParam.getName() + ");"); 629 } 630 indentPrintln("if (copy.getId() == null) {"); 631 // indentPrintln(" copy.setId(" + mapName + ".size() + \"\");"); 632 importsAdd("org.kuali.student.common.util.UUIDHelper"); 633 indentPrintln(" copy.setId(UUIDHelper.genStringUUID());"); 634 indentPrintln("}"); 635 if (contextParam != null) { 636 indentPrintln("copy.setMeta(newMeta(" + contextParam.getName() + "));"); 637 } 638 if (isR1) { 639 indentPrintln(mapName + ".put(copy.getId(), copy);"); 640 indentPrintln("// don't have deep copy in R1 contracts so just use the object"); 641 indentPrintln("return copy;"); 642 } else if (this.isRice()) { 643 indentPrintln (infoParam.getName() + " = copy.build ();"); 644 indentPrintln(mapName + ".put(" + infoParam.getName() + ".getId(), " + infoParam.getName() + ");"); 645 indentPrintln("return " + infoParam.getName() + ";"); 646 } else { 647 indentPrintln(mapName + ".put(copy.getId(), copy);"); 648 indentPrintln("return new " + infoName + "(copy);"); 649 } 650 } 651 652 private void writeAdd(ServiceMethod method) { 653 ServiceMethodParameter typeParam = this.findTypeParameter(method); 654 ServiceMethodParameter infoParam = this.findInfoParameter(method); 655 ServiceMethodParameter contextParam = this.findContextParameter(method); 656 String objectName = calcObjectName(method); 657 String infoName = objectName; 658 if (!this.isRice()) { 659 infoName = infoName + "Info"; 660 } 661 String mapName = calcMapName(method); 662 663 if (typeParam != null) { 664 indentPrintln("if (!" + typeParam.getName() + ".equals (" + infoParam.getName() + ".getTypeKey())) {"); 665 indentPrintln(" throw new " + this.getInvalidParameterException() + " (\"The type parameter does not match the type on the info object\");"); 666 indentPrintln("}"); 667 } 668 if (method.getParameters().size() > 3) { 669 indentPrintln("// TODO: check the rest of the readonly fields that are specified on the create to make sure they match the info object"); 670 } 671 if (isR1) { 672 indentPrintln("// don't have deep copy in R1 contracts so just use the object"); 673 indentPrintln(infoName + " copy = " + infoParam.getName() + ";"); 674 } else if (this.isRice()) { 675 indentPrintln(infoName + ".Builder copy = " + infoName + ".Builder.create (" + infoParam.getName() + ");"); 676 } else { 677 indentPrintln(infoName + " copy = new " + infoName + "(" + infoParam.getName() + ");"); 678 } 679 indentPrintln("if (copy.getId() == null) {"); 680 // indentPrintln(" copy.setId(" + mapName + ".size() + \"\");"); 681 importsAdd("org.kuali.student.common.util.UUIDHelper"); 682 indentPrintln(" copy.setId(UUIDHelper.genStringUUID());"); 683 indentPrintln("}"); 684 if (contextParam != null) { 685 indentPrintln("copy.setMeta(newMeta(" + contextParam.getName() + "));"); 686 } 687 if (isR1) { 688 indentPrintln(mapName + ".put(copy.getId(), copy);"); 689 indentPrintln("// don't have deep copy in R1 contracts so just use the object"); 690 indentPrintln("return copy;"); 691 } else if (this.isRice()) { 692 indentPrintln (infoParam.getName() + " = copy.build ();"); 693 indentPrintln(mapName + ".put(" + infoParam.getName() + ".getId(), " + infoParam.getName() + ");"); 694 indentPrintln("return " + infoParam.getName() + ";"); 695 } else { 696 indentPrintln(mapName + ".put(copy.getId(), copy);"); 697 indentPrintln("return new " + infoName + "(copy);"); 698 } 699 } 700 701 private ServiceMethodParameter findIdParameter(ServiceMethod method) { 702 String idFieldName = calcObjectName(method) + "Id"; 703 for (ServiceMethodParameter parameter : method.getParameters()) { 704 if (parameter.getType().equals("String")) { 705 if (parameter.getName().equals(idFieldName)) { 706 return parameter; 707 } 708 } 709 } 710 711 // if only one parameter and it is a string then grab that 712 if (method.getParameters().size() == 1) { 713 for (ServiceMethodParameter parameter : method.getParameters()) { 714 if (parameter.getType().equals("String")) { 715 return parameter; 716 } 717 } 718 } 719 // can't find name exactly 720 for (ServiceMethodParameter parameter : method.getParameters()) { 721 if (parameter.getType().equals("String")) { 722 if (parameter.getName().endsWith("Id")) { 723 return parameter; 724 } 725 } 726 } 727 // can't find name exactly try key 728 for (ServiceMethodParameter parameter : method.getParameters()) { 729 if (parameter.getType().equals("String")) { 730 if (!parameter.getName().endsWith("TypeKey")) { 731 if (parameter.getName().endsWith("Key")) { 732 return parameter; 733 } 734 } 735 } 736 } 737 log.warn("Could not find the Id paramter for " + method.getService() + "." + method.getName() + " so returning the first one"); 738 return method.getParameters().get(0); 739 } 740 741 private ServiceMethodParameter findContextParameter(ServiceMethod method) { 742 for (ServiceMethodParameter parameter : method.getParameters()) { 743 if (parameter.getType().equals("ContextInfo")) { 744 return parameter; 745 } 746 } 747 return null; 748 } 749 750 private ServiceMethodParameter findInfoParameter(ServiceMethod method) { 751 String objectName = calcObjectName(method); 752 if (!this.isRice()) { 753 objectName = objectName + "Info"; 754 } 755 for (ServiceMethodParameter parameter : method.getParameters()) { 756 if (parameter.getType().equals(objectName)) { 757 return parameter; 758 } 759 } 760 if (method.getParameters().size() >= 1) { 761 return method.getParameters().get(0); 762 } 763 return null; 764 } 765 766 private ServiceMethodParameter findTypeParameter(ServiceMethod method) { 767 for (ServiceMethodParameter parameter : method.getParameters()) { 768 if (parameter.getType().equals("String")) { 769 if (parameter.getName().endsWith("TypeKey")) { 770 return parameter; 771 } 772 if (parameter.getName().endsWith("Type")) { 773 return parameter; 774 } 775 } 776 } 777 return null; 778 } 779 780 private String calcMapName(ServiceMethod method) { 781 String mapName = this.calcObjectName(method); 782 mapName = this.initLower(mapName) + "Map"; 783 return mapName; 784 } 785 786 protected String calcObjectName(ServiceMethod method) { 787 if (method.getName().startsWith("create")) { 788 return method.getName().substring("create".length()); 789 } 790 if (method.getName().startsWith("update")) { 791 return method.getName().substring("update".length()); 792 } 793 if (method.getName().startsWith("validate")) { 794 return method.getName().substring("validate".length()); 795 } 796 if (method.getName().startsWith("delete")) { 797 return method.getName().substring("delete".length()); 798 } 799 if (method.getName().startsWith("get")) { 800 if (method.getReturnValue().getType().equals("StringList")) { 801 if (method.getName().contains("IdsBy")) { 802 return method.getName().substring("get".length(), 803 method.getName().indexOf("IdsBy")); 804 } 805 if (method.getName().contains("IdsFor")) { 806 return method.getName().substring("get".length(), 807 method.getName().indexOf("IdsFor")); 808 } 809 return method.getName().substring("get".length()); 810 } 811 String name = method.getReturnValue().getType(); 812 if (name.endsWith("List")) { 813 name = name.substring(0, name.length() - "List".length()); 814 } 815 if (name.endsWith("Info")) { 816 name = name.substring(0, name.length() - "Info".length()); 817 } 818 return name; 819 } 820 if (method.getName().startsWith("add")) { 821 return method.getName().substring("add".length()); 822 } 823 if (method.getName().startsWith("remove")) { 824 return method.getName().substring("remove".length()); 825 } 826 String returnType = this.stripList(method.getReturnValue().getType()); 827 XmlType type = this.finder.findXmlType(returnType); 828 if (type.getPrimitive().equals(XmlType.COMPLEX)) { 829 return returnType; 830 } 831 throw new IllegalArgumentException(method.getName()); 832 } 833 834 private void writeUpdate(ServiceMethod method) { 835 ServiceMethodParameter idParam = this.findIdParameter(method); 836 ServiceMethodParameter infoParam = this.findInfoParameter(method); 837 ServiceMethodParameter contextParam = this.findContextParameter(method); 838 if (infoParam == null) { 839 throw new NullPointerException(method.getName()); 840 } 841 String objectName = calcObjectName(method); 842 String infoName = objectName; 843 if (!this.isRice()) { 844 infoName = infoName + "Info"; 845 } 846 String mapName = calcMapName(method); 847 if (idParam != null) { 848 if (!this.isRice()) { 849 indentPrintln("if (!" + idParam.getName() + ".equals (" + infoParam.getName() + ".getId())) {"); 850 indentPrintln(" throw new " + this.getInvalidParameterException() + " (\"The id parameter does not match the id on the info object\");"); 851 indentPrintln("}"); 852 } 853 } 854 if (isR1) { 855 indentPrintln("// don't have deep copy in R1 contracts so just use the object"); 856 indentPrintln(infoName + " copy = " + infoParam.getName() + ";"); 857 } else if (this.isRice()) { 858 indentPrintln(infoName + ".Builder copy = " + infoName + ".Builder.create (" + infoParam.getName() + ");"); 859 } else { 860 indentPrintln(infoName + " copy = new " + infoName + "(" + infoParam.getName() + ");"); 861 } 862 if (contextParam != null) { 863 indentPrintln(infoName + " old = this.get" + objectName + "(" + infoParam.getName() + ".getId(), " + contextParam.getName() + ");"); 864 } else { 865 indentPrintln(infoName + " old = this.get" + objectName + "(" + infoParam.getName() + ".getId());"); 866 } 867 if (isR1) { 868 indentPrintln("if (!old.getMetaInfo().getVersionInd().equals(copy.getMetaInfo().getVersionInd())) {"); 869 indentPrintln(" throw new " + this.getVersionMismatchException() + "(old.getMetaInfo().getVersionInd());"); 870 indentPrintln("}"); 871 if (contextParam != null) { 872 indentPrintln("copy.setMeta(updateMeta(copy.getMetaInfo()));"); 873 } 874 } else if (this.isRice()) { 875 indentPrintln("if (!old.getVersionNumber().equals(copy.getVersionNumber())) {"); 876 indentPrintln(" throw new " + this.getVersionMismatchException() + "(\"\" + old.getVersionNumber());"); 877 indentPrintln("}"); 878 indentPrintln("copy.setVersionNumber(copy.getVersionNumber() + 1);"); 879 } else { 880 indentPrintln("if (!old.getMeta().getVersionInd().equals(copy.getMeta().getVersionInd())) {"); 881 indentPrintln(" throw new " + this.getVersionMismatchException() + "(old.getMeta().getVersionInd());"); 882 indentPrintln("}"); 883 if (contextParam != null) { 884 indentPrintln("copy.setMeta(updateMeta(copy.getMeta(), contextInfo));"); 885 } 886 } 887 if (isR1) { 888 indentPrintln("this." + mapName + " .put(" + infoParam.getName() + ".getId(), copy);"); 889 indentPrintln("// don't have deep copy in R1 contracts so just use the object"); 890 indentPrintln("return copy;"); 891 } else if (this.isRice()) { 892 indentPrintln (infoParam.getName() + " = copy.build ();"); 893 indentPrintln("this." + mapName + " .put(" + infoParam.getName() + ".getId(), " + infoParam.getName() + ");"); 894 indentPrintln("return " + infoParam.getName() + ";"); 895 } else { 896 indentPrintln("this." + mapName + " .put(" + infoParam.getName() + ".getId(), copy);"); 897 indentPrintln("return new " + infoName + "(copy);"); 898 } 899 900 } 901 902 private void writeDelete(ServiceMethod method) { 903 ServiceMethodParameter idParam = this.findIdParameter(method); 904 String mapName = calcMapName(method); 905 indentPrintln("if (this." + mapName + ".remove(" + idParam.getName() + ") == null) {"); 906 indentPrintln(" throw new " + this.getOperationFailedException() + "(" + idParam.getName() + ");"); 907 indentPrintln("}"); 908 indentPrintln("return newStatus();"); 909 } 910 911 private void writeRemove(ServiceMethod method) { 912 ServiceMethodParameter idParam = this.findIdParameter(method); 913 String mapName = calcMapName(method); 914 indentPrintln("if (this." + mapName + ".remove(" + idParam.getName() + ") == null) {"); 915 indentPrintln(" throw new " + this.getOperationFailedException() + "(" + idParam.getName() + ");"); 916 indentPrintln("}"); 917 indentPrintln("return newStatus();"); 918 } 919 920 private void writeGetById(ServiceMethod method) { 921 ServiceMethodParameter idParam = this.findIdParameter(method); 922 String mapName = calcMapName(method); 923 indentPrintln("if (!this." + mapName + ".containsKey(" + idParam.getName() + ")) {"); 924 indentPrintln(" throw new " + this.getDoesNotExistException() + "(" + idParam.getName() + ");"); 925 indentPrintln("}"); 926 String objectName = calcObjectName(method); 927 String infoName = objectName; 928 if (!this.isRice()) { 929 infoName = infoName + "Info"; 930 } 931 if (isR1) { 932 indentPrintln("// r1 objects do not have deep cody"); 933 indentPrintln("return this." + mapName + ".get (" + idParam.getName() + ");"); 934 } else if (this.isRice()) { 935 indentPrintln("return this." + mapName + ".get (" + idParam.getName() + ");"); 936 } else { 937 indentPrintln("return new " + infoName + "(this." + mapName + ".get (" + idParam.getName() + "));"); 938 } 939 940 } 941 942 private void writeGetByIds(ServiceMethod method) { 943 String objectName = this.calcObjectName(method); 944 String infoName = objectName; 945 if (!this.isRice()) { 946 infoName = infoName + "Info"; 947 } 948 ServiceMethodParameter idListParam = this.findIdListParameter(method); 949 ServiceMethodParameter contextParam = this.findContextParameter(method); 950 this.importsAdd(ArrayList.class.getName()); 951 indentPrintln("List<" + infoName + "> list = new ArrayList<" + infoName + "> ();"); 952 953 indentPrintln("for (String id: " + idListParam.getName() + ") {"); 954 if (this.isRice()) { 955 indentPrintln(" list.add (this.get" + objectName + "(id));"); 956 } else { 957 indentPrintln(" list.add (this.get" + objectName + "(id, " + contextParam.getName() + "));"); 958 } 959 indentPrintln("}"); 960 indentPrintln("return list;"); 961 } 962 963 private void writeGetIdsByOther(ServiceMethod method) { 964 String objectName = this.calcObjectName(method); 965 String infoName = objectName; 966 if (!this.isRice()) { 967 infoName = infoName + "Info"; 968 } 969 String mapName = calcMapName(method); 970 this.importsAdd(ArrayList.class.getName()); 971 indentPrintln("List<String> list = new ArrayList<String> ();"); 972 indentPrintln("for (" + infoName + " info: " + mapName + ".values ()) {"); 973 for (ServiceMethodParameter parameter : method.getParameters()) { 974 if (parameter.getType().equals("ContextInfo")) { 975 continue; 976 } 977 incrementIndent(); 978 indentPrintln("if (" + parameter.getName() + ".equals(info.get" + initUpper(parameter.getName()) + "())) {"); 979 } 980 indentPrintln(" list.add (info.getId ());"); 981 for (ServiceMethodParameter parameter : method.getParameters()) { 982 if (parameter.getType().equals("ContextInfo")) { 983 continue; 984 } 985 indentPrintln("}"); 986 decrementIndent(); 987 } 988 indentPrintln("}"); 989 indentPrintln("return list;"); 990 } 991 992 private void writeGetIdsByType(ServiceMethod method) { 993 String objectName = this.calcObjectName(method); 994 String infoName = objectName; 995 if (!this.isRice()) { 996 infoName = infoName + "Info"; 997 } 998 String mapName = calcMapName(method); 999 this.importsAdd(ArrayList.class.getName()); 1000 indentPrintln("List<String> list = new ArrayList<String> ();"); 1001 indentPrintln("for (" + infoName + " info: " + mapName + ".values ()) {"); 1002 for (ServiceMethodParameter parameter : method.getParameters()) { 1003 if (parameter.getType().equals("ContextInfo")) { 1004 continue; 1005 } 1006 incrementIndent(); 1007 indentPrintln("if (" + parameter.getName() + ".equals(info.getTypeKey())) {"); 1008 } 1009 indentPrintln(" list.add (info.getId ());"); 1010 for (ServiceMethodParameter parameter : method.getParameters()) { 1011 if (parameter.getType().equals("ContextInfo")) { 1012 continue; 1013 } 1014 indentPrintln("}"); 1015 decrementIndent(); 1016 } 1017 indentPrintln("}"); 1018 indentPrintln("return list;"); 1019 } 1020 1021 private void writeRiceGetByNamespaceAndName(ServiceMethod method) { 1022 String objectName = this.calcObjectName(method); 1023 String infoName = objectName; 1024 if (!this.isRice()) { 1025 infoName = infoName + "Info"; 1026 } 1027 String mapName = calcMapName(method); 1028 indentPrintln("for (" + infoName + " info: " + mapName + ".values ()) {"); 1029 for (ServiceMethodParameter parameter : method.getParameters()) { 1030 incrementIndent(); 1031 indentPrintln("if (" + parameter.getName() + ".equals(info.get" + initUpper(parameter.getName()) + "())) {"); 1032 } 1033 indentPrintln(" return " + infoName + ".Builder.create (info).build ();"); 1034 for (ServiceMethodParameter parameter : method.getParameters()) { 1035 indentPrintln("}"); 1036 decrementIndent(); 1037 } 1038 indentPrintln("}"); 1039 indentPrintln("throw new RiceIllegalArgumentException ();"); 1040 } 1041 1042 private void writeGetInfosByOther(ServiceMethod method) { 1043 String objectName = this.calcObjectName(method); 1044 String infoName = objectName; 1045 if (!this.isRice()) { 1046 infoName = infoName + "Info"; 1047 } 1048 String mapName = calcMapName(method); 1049 this.importsAdd(ArrayList.class.getName()); 1050 indentPrintln("List<" + infoName + "> list = new ArrayList<" + infoName + "> ();"); 1051 indentPrintln("for (" + infoName + " info: " + mapName + ".values ()) {"); 1052 for (ServiceMethodParameter parameter : method.getParameters()) { 1053 if (parameter.getType().equals("ContextInfo")) { 1054 continue; 1055 } 1056 incrementIndent(); 1057 indentPrintln("if (" + parameter.getName() + ".equals(info.get" + initUpper(parameter.getName()) + "())) {"); 1058 } 1059 indentPrintln(" list.add (new " + infoName + "(info));"); 1060 for (ServiceMethodParameter parameter : method.getParameters()) { 1061 if (parameter.getType().equals("ContextInfo")) { 1062 continue; 1063 } 1064 indentPrintln("}"); 1065 decrementIndent(); 1066 } 1067 indentPrintln("}"); 1068 indentPrintln("return list;"); 1069 } 1070 1071 private void writeGetType(ServiceMethod method) { 1072 ServiceMethodParameter idParam = this.findIdParameter(method); 1073 String mapName = calcMapName(method); 1074 indentPrintln("if (!this." + mapName + ".containsKey(" + idParam.getName() + ")) {"); 1075 indentPrintln(" throw new " + this.getOperationFailedException() + "(" + idParam.getName() + ");"); 1076 indentPrintln("}"); 1077 indentPrintln("return this." + mapName + ".get (" + idParam.getName() + ");"); 1078 } 1079 1080 private void writeGetTypes(ServiceMethod method) { 1081 String mapName = calcMapName(method); 1082 String objectName = this.calcObjectName(method); 1083 String infoName = objectName; 1084 if (!this.isRice()) { 1085 infoName = infoName + "Info"; 1086 } 1087 this.importsAdd(ArrayList.class.getName()); 1088 indentPrintln("return new ArrayList<" + infoName + ">(" + mapName + ".values ());"); 1089 } 1090 1091 private String initUpper(String str) { 1092 return str.substring(0, 1).toUpperCase() + str.substring(1); 1093 } 1094 1095 private ServiceMethodParameter findIdListParameter(ServiceMethod method) { 1096 String idFieldName = calcObjectName(method) + "Ids"; 1097 if (this.isRice()) { 1098 idFieldName = "ids"; 1099 } 1100 for (ServiceMethodParameter parameter : method.getParameters()) { 1101 if (parameter.getType().equals("StringList")) { 1102 if (parameter.getName().equals(idFieldName)) { 1103 return parameter; 1104 } 1105 } 1106 } 1107 // can't find name exactly 1108 for (ServiceMethodParameter parameter : method.getParameters()) { 1109 if (parameter.getType().equals("StringList")) { 1110 if (parameter.getName().endsWith("Ids")) { 1111 return parameter; 1112 } 1113 } 1114 } 1115 // can't find name exactly try key 1116 for (ServiceMethodParameter parameter : method.getParameters()) { 1117 if (parameter.getType().equals("StringList")) { 1118 if (parameter.getName().endsWith("Keys")) { 1119 return parameter; 1120 } 1121 } 1122 } 1123 return null; 1124 } 1125 1126 private String stripList(String str) { 1127 return GetterSetterNameCalculator.stripList(str); 1128 } 1129 1130 private String calcExceptionClassName(ServiceMethodError error) { 1131 if (error.getClassName() == null) { 1132 return ServiceExceptionWriter.calcClassName(error.getType()); 1133 } 1134 return error.getClassName(); 1135 } 1136 1137 private String calcExceptionPackageName(ServiceMethodError error) { 1138 if (error.getClassName() == null) { 1139 return ServiceExceptionWriter.calcPackage(rootPackage); 1140 } 1141 return error.getPackageName(); 1142 } 1143 1144 private String calcType(String type, String realType) { 1145 XmlType t = finder.findXmlType(this.stripList(type)); 1146 String retType = MessageStructureTypeCalculator.calculate(this, model, type, realType, 1147 t.getJavaPackage()); 1148 if (this.isRice()) { 1149 if (retType.equals("Boolean")) { 1150 retType = "boolean"; 1151 } 1152 if (retType.equals("Void")) { 1153 retType = "void"; 1154 } 1155 } 1156 return retType; 1157 } 1158 }