View Javadoc
1   /**
2    * Copyright 2004-2014 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.student.jpa.mojo;
17  
18  import org.kuali.student.contract.model.Service;
19  import org.kuali.student.contract.model.ServiceContractModel;
20  import org.kuali.student.contract.model.ServiceMethod;
21  import org.kuali.student.contract.model.ServiceMethodError;
22  import org.kuali.student.contract.model.ServiceMethodParameter;
23  import org.kuali.student.contract.model.XmlType;
24  import org.kuali.student.contract.model.util.ModelFinder;
25  import org.kuali.student.contract.writer.JavaClassWriter;
26  import org.kuali.student.contract.writer.service.GetterSetterNameCalculator;
27  import org.kuali.student.contract.writer.service.MessageStructureTypeCalculator;
28  import org.kuali.student.contract.writer.service.ServiceExceptionWriter;
29  import org.slf4j.Logger;
30  import org.slf4j.LoggerFactory;
31  
32  import java.util.*;
33  import org.kuali.rice.core.api.criteria.CriteriaLookupService;
34  import org.kuali.rice.core.api.criteria.GenericQueryResults;
35  import org.springframework.transaction.annotation.Transactional;
36  
37  /**
38   *
39   * @author nwright
40   */
41  public class JpaImplServiceWriter extends JavaClassWriter {
42  
43      private static Logger log = LoggerFactory.getLogger(JpaImplServiceWriter.class);
44  
45      //////////////////////////////
46      // Constants
47      //////////////////////////////
48      /**
49       * The standard type of methods used in our Service contract.
50       */
51      protected static enum MethodType {
52  
53          VALIDATE,
54          CREATE,
55          CREATE_BULK,
56          ADD,
57          UPDATE,
58          UPDATE_OTHER,
59          DELETE,
60          REMOVE,
61          DELETE_OTHER,
62          GET_CREATE,
63          GET_BY_ID,
64          GET_BY_IDS,
65          RICE_GET_BY_NAMESPACE_AND_NAME,
66          GET_IDS_BY_TYPE,
67          GET_IDS_BY_OTHER,
68          GET_INFOS_BY_OTHER,
69          GET_TYPE,
70          GET_TYPES,
71          SEARCH_FOR_IDS,
72          SEARCH_FOR_INFOS,
73          UNKNOWN
74      };
75  
76      //////////////////////////////
77      // Data Variables
78      //////////////////////////////
79      protected ServiceContractModel model;
80      protected ModelFinder finder;
81      private String directory;
82      /**
83       * The package name is stored in the service object itself (the package spec
84       * kept moving around so I assumed the actual service name was unique but
85       * ran into a problem when we included rice because they have a StateService
86       * meaning US states and we have a StateService meaning the state of the
87       * object so I added logic to detect rice and prepend that "RICE." to it
88       */
89      private String rootPackage;
90  
91      /**
92       * Name of the service being operated on. If it is a RICE service it is
93       * prefixed with RICE. [11:32:18 AM] Norman Wright: short name... I think it
94       * gets it by taking the java class SimpleName and stripping off the word
95       * "Service" and I think making it lower case. [11:32:24 AM] Norman Wright:
96       * so OrganizationService becomes organization
97       */
98      protected String servKey;
99  
100     protected List<ServiceMethod> methods;
101 
102     /**
103      * A flag that holds if the service is an R1 service.
104      */
105     private boolean isR1;
106 
107     //////////////////////////
108     // Constructor
109     //////////////////////////
110     public JpaImplServiceWriter(ServiceContractModel model,
111             String directory,
112             String rootPackage,
113             String servKey,
114             List<ServiceMethod> methods,
115             boolean isR1) {
116         super(directory, calcPackage(servKey, rootPackage), calcClassName(servKey));
117         this.model = model;
118         this.finder = new ModelFinder(model);
119         this.directory = directory;
120         this.rootPackage = rootPackage;
121         this.servKey = servKey;
122         this.methods = methods;
123         this.isR1 = isR1;
124     }
125 
126     public JpaImplServiceWriter(ServiceContractModel model,
127             String directory,
128             String rootPackage,
129             String servKey,
130             List<ServiceMethod> methods,
131             boolean isR1,
132             String packageName,
133             String className) {
134         super(directory, packageName, className);
135         this.model = model;
136         this.finder = new ModelFinder(model);
137         this.directory = directory;
138         this.rootPackage = rootPackage;
139         this.servKey = servKey;
140         this.methods = methods;
141         this.isR1 = isR1;
142     }
143 
144     /////////////////////////
145     // Functional Methods
146     /////////////////////////
147     /**
148      * Returns the jpa implementation package name.
149      *
150      * @param servKey
151      * @param rootPackage
152      * @return
153      */
154     public static String calcPackage(String servKey, String rootPackage) {
155         String pack = rootPackage + ".";
156 //        String pack = rootPackage + "." + servKey.toLowerCase() + ".";
157 //  StringBuffer buf = new StringBuffer (service.getVersion ().length ());
158 //  for (int i = 0; i < service.getVersion ().length (); i ++)
159 //  {
160 //   char c = service.getVersion ().charAt (i);
161 //   c = Character.toLowerCase (c);
162 //   if (Character.isLetter (c))
163 //   {
164 //    buf.append (c);
165 //    continue;
166 //   }
167 //   if (Character.isDigit (c))
168 //   {
169 //    buf.append (c);
170 //   }
171 //  }
172 //  pack = pack + buf.toString ();
173         pack = pack + "service.impl.jpa." + servKey.toLowerCase();
174         return pack;
175     }
176 
177     /**
178      * Checks if this is a RICE service.
179      *
180      * @return true if this is a RICE service.
181      */
182     private boolean isRice() {
183         if (this.servKey.startsWith("RICE.")) {
184             return true;
185         }
186         return false;
187     }
188 
189     protected static String fixServKey(String servKey) {
190         if (servKey.startsWith("RICE.")) {
191             return servKey.substring("RICE.".length());
192         }
193         return servKey;
194     }
195 
196     /**
197      * Given the service key (name), returns a calculated class name for the jpa
198      * impl.
199      */
200     public static String calcClassName(String servKey) {
201         return GetterSetterNameCalculator.calcInitUpper(fixServKey(servKey) + "ServiceJpaImpl");
202     }
203 
204     public static String calcServiceInterfaceClassName(String servKey) {
205         return GetterSetterNameCalculator.calcInitUpper(fixServKey(servKey) + "Service");
206     }
207 
208     /**
209      * Analyses the method and returns a MethodType enum that describes what
210      * type of method this is.
211      */
212     protected MethodType calcMethodType(ServiceMethod method) {
213 //        if (method.getName().equals("getInstructionalDaysForTerm")) {
214 //            System.out.println("debug here");
215 //        }
216         if (this.isRice()) {
217             if (method.getName().contains("ByNamespaceCodeAndName")) {
218                 return MethodType.RICE_GET_BY_NAMESPACE_AND_NAME;
219             }
220             if (method.getName().contains("ByNameAndNamespace")) {
221                 return MethodType.RICE_GET_BY_NAMESPACE_AND_NAME;
222             }
223             if (method.getName().startsWith("get")) {
224                 if (method.getParameters().size() == 1) {
225                     if (!method.getReturnValue().getType().endsWith("List")) {
226                         if (method.getParameters().get(0).getName().equals("id")) {
227                             return MethodType.GET_BY_ID;
228                         }
229 
230                     } else {
231                         if (method.getParameters().get(0).getName().equals("ids")) {
232                             return MethodType.GET_BY_IDS;
233                         }
234                     }
235                 }
236             }
237         }
238         if (method.getName().startsWith("validate")) {
239             return MethodType.VALIDATE;
240         }
241         if (method.getName().startsWith("create")) {
242             if (method.getName().startsWith("createBatch")) {
243                 return MethodType.CREATE_BULK;
244             }
245             if (method.getName().startsWith("createSocRolloverResultItems")) {
246                 return MethodType.CREATE_BULK;
247             }
248             if (method.getName().contains("FromExisting")) {
249                 return MethodType.CREATE_BULK;
250             }
251             ServiceMethodParameter infoParam = this.findInfoParameter(method);
252             if (infoParam == null) {
253                 return MethodType.CREATE_BULK;
254             }
255             if (method.getReturnValue().getType().endsWith("List")) {
256                 return MethodType.CREATE_BULK;
257             }
258             return MethodType.CREATE;
259         }
260         if (method.getName().startsWith("add")) {
261             return MethodType.ADD;
262         }
263         if (method.getName().startsWith("update")) {
264             if (this.findInfoParameter(method) != null) {
265                 return MethodType.UPDATE;
266             }
267             return MethodType.UPDATE_OTHER;
268         }
269         if (method.getName().startsWith("delete")) {
270             if (method.getName().contains("By")) {
271                 if (!method.getName().startsWith("deleteBy")) {
272                     return MethodType.DELETE_OTHER;
273                 }
274             }
275             if (method.getName().contains("For")) {
276                 if (!method.getName().startsWith("deleteFor")) {
277                     return MethodType.DELETE_OTHER;
278                 }
279             }
280             return MethodType.DELETE;
281         }
282         if (method.getName().startsWith("remove")) {
283             return MethodType.REMOVE;
284         }
285 
286         if (method.getName().startsWith("getCreate")) {
287             return MethodType.GET_CREATE;
288         }
289 
290         if (method.getName().startsWith("get")) {
291             if (method.getName().endsWith("ByIds")) {
292                 return MethodType.GET_BY_IDS;
293             }
294             if (method.getName().endsWith("ByKeys")) {
295                 return MethodType.GET_BY_IDS;
296             }
297             if (method.getName().endsWith("ByType")) {
298                 return MethodType.GET_IDS_BY_TYPE;
299             }
300             if (method.getReturnValue().getType().endsWith("TypeInfo")) {
301                 return MethodType.GET_TYPE;
302             }
303             if (method.getReturnValue().getType().endsWith("TypeInfoList")) {
304                 return MethodType.GET_TYPES;
305             }
306             if (method.getName().endsWith("ByType")) {
307                 return MethodType.GET_IDS_BY_TYPE;
308             }
309             String splitName = splitCamelCase(method.getName());
310             if (splitName.contains(" By ")) {
311                 if (method.getReturnValue().getType().equals("StringList")) {
312                     return MethodType.GET_IDS_BY_OTHER;
313                 }
314                 if (method.getReturnValue().getType().endsWith("InfoList")) {
315                     return MethodType.GET_INFOS_BY_OTHER;
316                 }
317                 return MethodType.UNKNOWN;
318             }
319             if (splitName.contains(" For ")) {
320                 if (method.getReturnValue().getType().equals("StringList")) {
321                     return MethodType.GET_IDS_BY_OTHER;
322                 }
323                 if (method.getReturnValue().getType().endsWith("InfoList")) {
324                     return MethodType.GET_INFOS_BY_OTHER;
325                 }
326                 return MethodType.UNKNOWN;
327             }
328             if (method.getParameters().size() >= 1 && method.getParameters().size() <= 2) {
329                 if (!method.getReturnValue().getType().endsWith("List")) {
330                     if (method.getParameters().get(0).getName().endsWith("Id")) {
331                         return MethodType.GET_BY_ID;
332                     }
333                     if (method.getParameters().get(0).getName().endsWith("Key")) {
334                         return MethodType.GET_BY_ID;
335                     }
336                 }
337             }
338         }
339         if (method.getName().startsWith("searchFor")) {
340             if (method.getName().endsWith("Ids")) {
341                 return MethodType.SEARCH_FOR_IDS;
342             }
343             if (method.getName().endsWith("Keys")) {
344                 return MethodType.SEARCH_FOR_IDS;
345             }
346             return MethodType.SEARCH_FOR_INFOS;
347         }
348 
349         return MethodType.UNKNOWN;
350     }
351 
352     // got this from
353     // http://stackoverflow.com/questions/2559759/how-do-i-convert-camelcase-into-human-readable-names-in-java
354     private static String splitCamelCase(String s) {
355         if (s == null) {
356             return null;
357         }
358         return s.replaceAll(String.format("%s|%s|%s",
359                 "(?<=[A-Z])(?=[A-Z][a-z])", "(?<=[^A-Z])(?=[A-Z])",
360                 "(?<=[A-Za-z])(?=[^A-Za-z])"), " ");
361     }
362 
363     /**
364      * Write out the entire file
365      */
366     public void write() {
367         indentPrintln("@Transactional(readOnly = true, noRollbackFor = {DoesNotExistException.class}, rollbackFor = {Throwable.class})");
368         importsAdd(Transactional.class.getName());
369         indentPrint("public class " + calcClassName(servKey));
370         println(" implements " + calcServiceInterfaceClassName(servKey));
371         Service serv = finder.findService(servKey);
372         importsAdd(serv.getImplProject() + "." + serv.getName());
373         openBrace();
374         // put all the cache variables at the top
375         indentPrintln("// dao variables ");
376         jpaEntitiesWritten.clear();
377         for (ServiceMethod method : methods) {
378             MethodType methodType = calcMethodType(method);
379             switch (methodType) {
380                 case CREATE:
381                 case GET_TYPE:
382                 case GET_BY_ID:
383                     writeDaoVariable(method);
384             }
385         }
386 
387         for (ServiceMethod method : methods) {
388             MethodType methodType = calcMethodType(method);
389             println("");
390 //            indentPrintln("/**");
391 //            indentPrintWrappedComment(method.getDescription());
392 //            indentPrintln("* ");
393 //            for (ServiceMethodParameter param : method.getParameters()) {
394 //                indentPrintWrappedComment("@param " + param.getName() + " - "
395 //                        + param.getType() + " - "
396 //                        + param.getDescription());
397 //            }
398 //            indentPrintWrappedComment("@return " + method.getReturnValue().
399 //                    getDescription());
400 //            indentPrintln("*/");
401             indentPrintln("@Override");
402             switch (methodType) {
403                 case CREATE:
404                     indentPrintln("@Transactional");
405                     break;
406                 case ADD:
407                     indentPrintln("@Transactional");
408                     break;
409                 case UPDATE:
410                     indentPrintln("@Transactional");
411                     break;
412                 case DELETE:
413                     indentPrintln("@Transactional");
414                     break;
415                 case REMOVE:
416                     indentPrintln("@Transactional");
417                     break;
418                 case GET_BY_ID:
419                     indentPrintln("@Transactional(readOnly = true)");
420                     break;
421                 case GET_BY_IDS:
422                     indentPrintln("@Transactional(readOnly = true)");
423                     break;
424                 case GET_IDS_BY_TYPE:
425                     indentPrintln("@Transactional(readOnly = true)");
426                     break;
427                 case GET_IDS_BY_OTHER:
428                     indentPrintln("@Transactional(readOnly = true)");
429                     break;
430                 case GET_INFOS_BY_OTHER:
431                     indentPrintln("@Transactional(readOnly = true)");
432                     break;
433                 case GET_TYPE:
434                     indentPrintln("@Transactional(readOnly = true)");
435                     break;
436                 case GET_TYPES:
437                     indentPrintln("@Transactional(readOnly = true)");
438                     break;
439                 case RICE_GET_BY_NAMESPACE_AND_NAME:
440                     indentPrintln("@Transactional(readOnly = true)");
441                     break;
442                 default:
443             }
444             String type = method.getReturnValue().getType();
445             String realType = stripList(type);
446             indentPrint("public " + calcType(type, realType) + " " + method.getName()
447                     + "(");
448             // now do parameters
449             String comma = "";
450             for (ServiceMethodParameter param : method.getParameters()) {
451                 type = param.getType();
452                 realType = stripList(type);
453                 print(comma);
454                 print(calcType(type, realType));
455                 print(" ");
456                 print(param.getName());
457                 comma = ", ";
458             }
459             println(")");
460             // now do exceptions
461             comma = "throws ";
462             incrementIndent();
463             for (ServiceMethodError error : method.getErrors()) {
464                 indentPrint(comma);
465                 String exceptionClassName = calcExceptionClassName(error);
466                 String exceptionPackageName = this.calcExceptionPackageName(error);
467                 println(exceptionClassName);
468                 this.importsAdd(exceptionPackageName + "." + exceptionClassName);
469                 comma = "      ,";
470             }
471             decrementIndent();
472             openBrace();
473             indentPrintln("// " + methodType);
474             switch (methodType) {
475                 case VALIDATE:
476                     writeValidate(method);
477                     break;
478                 case CREATE:
479                     writeCreate(method);
480                     break;
481                 case ADD:
482                     writeAdd(method);
483                     break;
484                 case UPDATE:
485                     writeUpdate(method);
486                     break;
487                 case DELETE:
488                     writeDelete(method);
489                     break;
490                 case REMOVE:
491                     writeRemove(method);
492                     break;
493                 case GET_BY_ID:
494                     writeGetById(method);
495                     break;
496                 case GET_BY_IDS:
497                     writeGetByIds(method);
498                     break;
499                 case GET_IDS_BY_TYPE:
500                     writeGetIdsByType(method);
501                     break;
502                 case GET_IDS_BY_OTHER:
503                     writeGetIdsByOther(method);
504                     break;
505                 case GET_INFOS_BY_OTHER:
506                     writeGetInfosByOther(method);
507                     break;
508                 case SEARCH_FOR_IDS:
509                     writeSearchForIds(method);
510                     break;
511                 case SEARCH_FOR_INFOS:
512                     writeSearchForInfos(method);
513                     break;
514                 case GET_TYPE:
515                     writeGetType(method);
516                     break;
517                 case GET_TYPES:
518                     writeGetTypes(method);
519                     break;
520                 case RICE_GET_BY_NAMESPACE_AND_NAME:
521                     writeRiceGetByNamespaceAndName(method);
522                     break;
523                 default:
524                     writeThrowsNotImplemented(method);
525             }
526             closeBrace();
527         }
528 
529         closeBrace();
530 
531         this.writeJavaClassAndImportsOutToFile();
532         this.getOut().close();
533     }
534 
535     private String getInvalidParameterException() {
536         if (this.isRice()) {
537             return "RiceIllegalArgumentException";
538         }
539         return "InvalidParameterException";
540     }
541 
542     private String getOperationFailedException() {
543         if (this.isRice()) {
544             return "RiceIllegalArgumentException";
545         }
546         return "OperationFailedException";
547     }
548 
549     private String getDoesNotExistException() {
550         if (this.isRice()) {
551             return "RiceIllegalArgumentException";
552         }
553         return "DoesNotExistException";
554     }
555 
556     private String getVersionMismatchException() {
557         if (this.isRice()) {
558             return "RiceIllegalStateException";
559         }
560         return "VersionMismatchException";
561     }
562 
563     private void writeThrowsNotImplemented(ServiceMethod method) {
564         indentPrintln("throw new " + this.getOperationFailedException() + " (\"" + method.getName() + " has not been implemented\");");
565     }
566 
567     protected String initLower(String str) {
568         return str.substring(0, 1).toLowerCase() + str.substring(1);
569     }
570 
571     private String calcCriteriaLookupServiceVariableName(ServiceMethod method) {
572         String objectName = calcObjectName(method);
573         String variableName = initLower(objectName) + "CriteriaLookupService";
574         return variableName;
575     }
576 
577     private void writeValidate(ServiceMethod method) {
578         indentPrintln("return new ArrayList<ValidationResultInfo> ();");
579         this.importsAdd(ArrayList.class.getName());
580     }
581     private final Set<String> jpaEntitiesWritten = new HashSet<String>();
582 
583     private void writeDaoVariable(ServiceMethod method) {
584         String objectName = calcObjectName(method);
585         String className = objectName + "Dao";
586         String variableName = calcDaoVariableName(method);
587         if (jpaEntitiesWritten.add(variableName)) {
588             XmlType xmlType = finder.findXmlType(objectName + "Info");
589             if (xmlType == null) {
590                 System.out.println ("Cannot write DAO because the object does not follow patterns.  ObjectName=" 
591                         + objectName + " method=" + method);
592                 return;
593             }
594             new JpaEntityWriter(model, directory, rootPackage, servKey, methods, xmlType, isR1).write();
595             new JpaDaoWriter(model, directory, rootPackage, servKey, methods, xmlType, isR1).write();
596             println("");
597             indentPrintln("private " + className + " " + variableName + ";");
598             println("");
599             indentPrintln("public void set" + className + "(" + className + " " + variableName + ") {");
600             incrementIndent();
601             indentPrintln("this." + variableName + " = " + variableName + ";");
602             decrementIndent();
603             indentPrintln("}");
604             println("");
605             indentPrintln("public " + className + " get" + className + "() {");
606             incrementIndent();
607             indentPrintln("return this." + variableName + ";");
608             decrementIndent();
609             indentPrintln("}");
610 
611             variableName = calcCriteriaLookupServiceVariableName(method);
612 
613             importsAdd(CriteriaLookupService.class.getName());
614             className = "CriteriaLookupService";
615             println("");
616             indentPrintln("// Criteria Lookup for this object");
617             indentPrintln("private " + className + " " + variableName + ";");
618             println("");
619             indentPrintln("public void set" + initUpper(variableName) + "(" + className + " " + variableName + ") {");
620             incrementIndent();
621             indentPrintln("this." + variableName + " = " + variableName + ";");
622             decrementIndent();
623             indentPrintln("}");
624             println("");
625             indentPrintln("public " + className + " get" + initUpper(variableName) + "() {");
626             incrementIndent();
627             indentPrintln("return this." + variableName + ";");
628             decrementIndent();
629             indentPrintln("}");
630 
631         }
632     }
633 
634     private void writeCreate(ServiceMethod method) {
635 
636 //        holdInfo.setPersonId(personId);
637 //        holdInfo.setHoldIssueId(issueId);
638 //        holdInfo.setTypeKey(holdTypeKey);
639 //
640 //        HoldIssueEntity holdIssueEntity = holdIssueDao.find(issueId);
641 //        if (holdIssueEntity == null) {
642 //            throw new InvalidParameterException(issueId);
643 //        }
644 //        AppliedHoldEntity entity = new AppliedHoldEntity(holdInfo);
645 //        entity.setHoldIssue(holdIssueEntity);
646 //        entity.setEntityCreated(context);
647 //        appliedHoldDao.persist(entity);
648 //        appliedHoldDao.getEm().flush();
649 //        return entity.toDto();
650         String daoVariable = calcDaoVariableName(method);
651         String entityClassName = calcEntityClassName(method);
652         ServiceMethodParameter typeParam = this.findTypeParameter(method);
653         ServiceMethodParameter infoParam = this.findInfoParameter(method);
654         ServiceMethodParameter contextParam = this.findContextParameter(method);
655         String objectName = calcObjectName(method);
656         String infoName = objectName;
657         if (!this.isRice()) {
658             infoName = infoName + "Info";
659         }
660         String daoName = calcDaoVariableName(method);
661         if (typeParam != null) {
662             indentPrintln(infoParam.getName() + ".setTypeKey (" + typeParam.getName() + ");");
663         }
664         if (method.getParameters().size() > 3) {
665             indentPrintln("//TODO: JPAIMPL overwrite the rest of the readonly fields that are specified on the create in the info object");
666         }
667         indentPrintln(entityClassName + " entity = new " + entityClassName + "(" + infoParam.getName() + ");");
668         indentPrintln("entity.setEntityCreated(" + contextParam.getName() + ");");
669         indentPrintln(daoVariable + ".persist(entity);");
670         indentPrintln(daoVariable + ".getEm().flush();");
671         indentPrintln("return entity.toDto();");
672     }
673 
674     private void writeAdd(ServiceMethod method) {
675         indentPrintln ("//TODO: JPAIMPL this needs to be implemented");
676         indentPrintln ("throw new OperationFailedException (\"Not implemented\");");
677     }
678 
679     private ServiceMethodParameter findIdParameter(ServiceMethod method) {
680         String idFieldName = calcObjectName(method) + "Id";
681         for (ServiceMethodParameter parameter : method.getParameters()) {
682             if (parameter.getType().equals("String")) {
683                 if (parameter.getName().equals(idFieldName)) {
684                     return parameter;
685                 }
686             }
687         }
688 
689         // if only one parameter and it is a string then grab that
690         if (method.getParameters().size() == 1) {
691             for (ServiceMethodParameter parameter : method.getParameters()) {
692                 if (parameter.getType().equals("String")) {
693                     return parameter;
694                 }
695             }
696         }
697         // can't find name exactly 
698         for (ServiceMethodParameter parameter : method.getParameters()) {
699             if (parameter.getType().equals("String")) {
700                 if (parameter.getName().endsWith("Id")) {
701                     return parameter;
702                 }
703             }
704         }
705         // can't find name exactly try key 
706         for (ServiceMethodParameter parameter : method.getParameters()) {
707             if (parameter.getType().equals("String")) {
708                 if (!parameter.getName().endsWith("TypeKey")) {
709                     if (parameter.getName().endsWith("Key")) {
710                         return parameter;
711                     }
712                 }
713             }
714         }
715         log.warn("Could not find the Id paramter for " + method.getService() + "." + method.getName() + " so returning the first one");
716         return method.getParameters().get(0);
717     }
718 
719     private ServiceMethodParameter findContextParameter(ServiceMethod method) {
720         for (ServiceMethodParameter parameter : method.getParameters()) {
721             if (parameter.getType().equals("ContextInfo")) {
722                 return parameter;
723             }
724         }
725         return null;
726     }
727 
728     private ServiceMethodParameter findInfoParameter(ServiceMethod method) {
729         String objectName = calcObjectName(method);
730         if (!this.isRice()) {
731             objectName = objectName + "Info";
732         }
733         for (ServiceMethodParameter parameter : method.getParameters()) {
734             if (parameter.getType().equals(objectName)) {
735                 return parameter;
736             }
737         }
738         if (method.getParameters().size() >= 1) {
739             return method.getParameters().get(0);
740         }
741         return null;
742     }
743 
744     private ServiceMethodParameter findTypeParameter(ServiceMethod method) {
745         for (ServiceMethodParameter parameter : method.getParameters()) {
746             if (parameter.getType().equals("String")) {
747                 if (parameter.getName().endsWith("TypeKey")) {
748                     return parameter;
749                 }
750                 if (parameter.getName().endsWith("Type")) {
751                     return parameter;
752                 }
753             }
754         }
755         return null;
756     }
757 
758     private String calcDaoVariableName(ServiceMethod method) {
759         String daoVariableName = this.calcObjectName(method);
760         daoVariableName = this.initLower(daoVariableName) + "Dao";
761         return daoVariableName;
762     }
763 
764     private String calcEntityClassName(ServiceMethod method) {
765         String objectName = this.calcObjectName(method);
766         objectName = objectName + "Entity";
767         return objectName;
768     }
769 
770     protected String calcObjectName(ServiceMethod method) {
771         if (method.getName().startsWith("create")) {
772             return method.getName().substring("create".length());
773         }
774         if (method.getName().startsWith("update")) {
775             return method.getName().substring("update".length());
776         }
777         if (method.getName().startsWith("validate")) {
778             return method.getName().substring("validate".length());
779         }
780         if (method.getName().startsWith("delete")) {
781             return method.getName().substring("delete".length());
782         }
783         if (method.getName().startsWith("get")) {
784             if (method.getReturnValue().getType().equals("StringList")) {
785                 if (method.getName().contains("IdsBy")) {
786                     return method.getName().substring("get".length(),
787                             method.getName().indexOf("IdsBy"));
788                 }
789                 if (method.getName().contains("KeysBy")) {
790                     return method.getName().substring("get".length(),
791                             method.getName().indexOf("KeysBy"));
792                 }
793                 if (method.getName().contains("IdsFor")) {
794                     return method.getName().substring("get".length(),
795                             method.getName().indexOf("IdsFor"));
796                 }
797                 if (method.getName().contains("With")) {
798                     return method.getName().substring("get".length(),
799                             method.getName().indexOf("With"));
800                 }
801                 if (method.getName().contains("By")) {
802                     return method.getName().substring("get".length(),
803                             method.getName().indexOf("By"));
804                 }
805                 return method.getName().substring("get".length());
806             }
807             String name = method.getReturnValue().getType();
808             if (name.endsWith("List")) {
809                 name = name.substring(0, name.length() - "List".length());
810             }
811             if (name.endsWith("Info")) {
812                 name = name.substring(0, name.length() - "Info".length());
813             }
814             return name;
815         }
816 
817         if (method.getName().startsWith("searchFor")) {
818             if (method.getReturnValue().getType().equals("StringList")) {
819                 if (method.getName().endsWith("Ids")) {
820                     return method.getName().substring("searchFor".length(),
821                             method.getName().indexOf("Ids"));
822                 }
823                 if (method.getName().endsWith("Keys")) {
824                     return method.getName().substring("get".length(),
825                             method.getName().indexOf("Keys"));
826                 }
827                 return method.getName().substring("searchFor".length());
828             }
829             String name = method.getReturnValue().getType();
830             if (name.endsWith("List")) {
831                 name = name.substring(0, name.length() - "List".length());
832             }
833             if (name.endsWith("Info")) {
834                 name = name.substring(0, name.length() - "Info".length());
835             }
836             return name;
837         }
838         if (method.getName().startsWith("add")) {
839             return method.getName().substring("add".length());
840         }
841         if (method.getName().startsWith("remove")) {
842             return method.getName().substring("remove".length());
843         }
844         String returnType = this.stripList(method.getReturnValue().getType());
845         XmlType type = this.finder.findXmlType(returnType);
846         if (type.getPrimitive().equals(XmlType.COMPLEX)) {
847             return returnType;
848         }
849         throw new IllegalArgumentException(method.getName());
850     }
851 
852     private void writeUpdate(ServiceMethod method) {
853 //        if (!holdId.equals(holdInfo.getId())) {
854 //            throw new InvalidParameterException(holdId + " does not match the id in the object " + holdInfo.getId());
855 //        }
856 //        AppliedHoldEntity entity = appliedHoldDao.find(holdId);
857 //        if (null == entity) {
858 //            throw new DoesNotExistException(holdId);
859 //        }
860 //        entity.fromDto(holdInfo);
861 //        entity.setEntityUpdated(context);
862 //        entity = appliedHoldDao.merge(entity);
863 //        appliedHoldDao.getEm().flush(); // need to flush to get the version indicator updated
864 //        return entity.toDto();
865         ServiceMethodParameter idParam = this.findIdParameter(method);
866         ServiceMethodParameter infoParam = this.findInfoParameter(method);
867         ServiceMethodParameter contextParam = this.findContextParameter(method);
868         String daoVariable = calcDaoVariableName(method);
869         String entityClassName = calcEntityClassName(method);
870         if (infoParam == null) {
871             throw new NullPointerException(method.getName());
872         }
873         String objectName = calcObjectName(method);
874         String infoName = objectName;
875         if (!this.isRice()) {
876             infoName = infoName + "Info";
877         }
878         if (idParam != null) {
879             if (!this.isRice()) {
880                 indentPrintln("if (!" + idParam.getName() + ".equals (" + infoParam.getName() + ".getId())) {");
881                 indentPrintln("    throw new " + this.getInvalidParameterException() + " (\"The id parameter does not match the id on the info object\");");
882                 indentPrintln("}");
883             }
884         }
885         indentPrintln(entityClassName + " entity = " + daoVariable + ".find(" + idParam.getName() + ");");
886         indentPrintln("if (entity == null) {");
887         incrementIndent();
888         indentPrintln("throw new DoesNotExistException(" + idParam.getName() + ");");
889         decrementIndent();
890         indentPrintln("}");
891         indentPrintln("entity.fromDto(" + infoParam.getName() + ");");
892         indentPrintln("entity.setEntityUpdated(" + contextParam.getName() + ");");
893         indentPrintln("entity = " + daoVariable + ".merge(entity);");
894         indentPrintln("return entity.toDto();");
895     }
896 
897     private void writeDelete(ServiceMethod method) {
898 //        AppliedHoldEntity entity = appliedHoldDao.find(holdId);
899 //        if (null == entity) {
900 //            throw new DoesNotExistException(holdId);
901 //        }
902 //        appliedHoldDao.remove(entity);
903 //        StatusInfo status = new StatusInfo();
904 //        status.setSuccess(Boolean.TRUE);
905 //        return status;
906         ServiceMethodParameter idParam = this.findIdParameter(method);
907         String daoVariable = calcDaoVariableName(method);
908         String entityClassName = calcEntityClassName(method);
909         indentPrintln(entityClassName + " entity = " + daoVariable + ".find(" + idParam.getName() + ");");
910         indentPrintln("if (entity == null) {");
911         incrementIndent();
912         indentPrintln("throw new DoesNotExistException(" + idParam.getName() + ");");
913         decrementIndent();
914         indentPrintln("}");
915         indentPrintln(daoVariable + ".remove(entity);");
916         indentPrintln("StatusInfo status = new StatusInfo();");
917         importsAdd("org.kuali.student.r2.common.dto.StatusInfo");
918         indentPrintln("status.setSuccess(Boolean.TRUE);");
919         indentPrintln("return status;");
920     }
921 
922     private void writeRemove(ServiceMethod method) {
923         indentPrintln ("//TODO: JPAIMPL this needs to be implemented");
924         indentPrintln ("throw new OperationFailedException (\"Not implemented\");");
925     }
926 
927     private void writeGetById(ServiceMethod method) {
928 //        AppliedHoldEntity entity = appliedHoldDao.find(holdId);
929 //        if (entity == null) {
930 //            throw new DoesNotExistException(holdId);
931 //        }
932 //        return entity.toDto();
933         ServiceMethodParameter idParam = this.findIdParameter(method);
934         String daoVariable = calcDaoVariableName(method);
935         String entityClassName = calcEntityClassName(method);
936         indentPrintln(entityClassName + " entity = " + daoVariable + ".find(" + idParam.getName() + ");");
937         indentPrintln("if (entity == null) {");
938         incrementIndent();
939         indentPrintln("throw new DoesNotExistException(" + idParam.getName() + ");");
940         decrementIndent();
941         indentPrintln("}");
942         indentPrintln("return entity.toDto();");
943     }
944 
945     private void writeGetByIds(ServiceMethod method) {
946 //        List<HoldIssueEntity> holdIssues = holdIssueDao.findByIds(issueIds);
947 //        List<HoldIssueInfo> result = new ArrayList<HoldIssueInfo>(holdIssues.size());
948 //        for (HoldIssueEntity entity : holdIssues) {
949 //            if (entity == null) {
950 //                // if one of the entities from "findByIds" is returned as null, then one of the keys in the list was not found
951 //                throw new DoesNotExistException();
952 //            }
953 //            result.add(entity.toDto());
954 //        }
955 //        return result;
956         String daoVariable = calcDaoVariableName(method);
957         String entityClassName = calcEntityClassName(method);
958         String objectName = this.calcObjectName(method);
959         ServiceMethodParameter idListParam = this.findIdListParameter(method);
960         String infoName = objectName;
961         infoName = infoName + "Info";
962         this.importsAdd(ArrayList.class.getName());
963         indentPrintln("List<" + entityClassName + "> entities = " + daoVariable + ".findByIds(" + idListParam.getName() + ");");
964         indentPrintln("List<" + infoName + "> list = new ArrayList<" + infoName + "> (entities.size());");
965         indentPrintln("for (" + entityClassName + " entity : entities) {");
966         incrementIndent();
967         indentPrintln("if (entity == null) {");
968         incrementIndent();
969         indentPrintln("throw new DoesNotExistException();");
970         decrementIndent();
971         indentPrintln("}");
972         indentPrintln("list.add(entity.toDto());");
973         decrementIndent();
974         indentPrintln("}");
975         indentPrintln("return list;");
976     }
977 
978     private String calcNamedQuery(ServiceMethod method) {
979         String objectName = calcObjectName(method);
980         String name = method.getName();
981         if (name.startsWith("get")) {
982             name = name.substring("get".length());
983         }
984         if (name.startsWith(objectName)) {
985             name = name.substring(objectName.length());
986         }
987 //        if (name.startsWith("Ids")) {
988 //            name = name.substring("Ids".length());
989 //        }
990 //        if (name.isEmpty()) {
991 //            throw new RuntimeException (method.getName());
992 //        }
993         // remove plural
994         if (!method.getReturnValue().getType().equals("StringList")) {
995             if (name.startsWith("s")) {
996                 name = name.substring("s".length());
997             }
998         }
999         // add back the get
1000         name = "get" + name;
1001         return name;
1002     }
1003 
1004     private void writeGetIdsByOther(ServiceMethod method) {
1005 //      return appliedHoldDao.getIdsByIssue(issueId);
1006         String objectName = this.calcObjectName(method);
1007         String infoName = objectName;
1008         if (!this.isRice()) {
1009             infoName = infoName + "Info";
1010         }
1011         String daoVariableName = calcDaoVariableName(method);
1012         String namedQuery = calcNamedQuery(method);
1013         indentPrint("return " + daoVariableName + "." + namedQuery + "(");
1014         String comma = "";
1015         for (ServiceMethodParameter param : method.getParameters()) {
1016             if (param.getType().equals("ContextInfo")) {
1017                 continue;
1018             }
1019             print(comma);
1020             comma = ", ";
1021             print(param.getName());
1022         }
1023         println(");");
1024     }
1025 
1026     private ServiceMethodParameter findCriteriaParam(ServiceMethod method) {
1027         for (ServiceMethodParameter param : method.getParameters()) {
1028             if (param.getType().equals("QueryByCriteria")) {
1029                 return param;
1030             }
1031         }
1032         return null;
1033     }
1034 
1035     private void writeSearchForIds(ServiceMethod method) {
1036 //        List<String> results = new ArrayList<String>();
1037 //        GenericQueryResults<AppliedHoldEntity> appliedHolds = criteriaLookupService.lookup(AppliedHoldEntity.class, criteria);
1038 //        if (null != appliedHolds && appliedHolds.getResults().size() > 0) {
1039 //            for (AppliedHoldEntity appliedHold : appliedHolds.getResults()) {
1040 //                results.add(appliedHold.getId());
1041 //            }
1042 //        }
1043 //        return results;
1044         String objectName = this.calcObjectName(method);
1045         String infoName = objectName;
1046         if (!this.isRice()) {
1047             infoName = infoName + "Info";
1048         }
1049         String criteriaLookupVariableName = calcCriteriaLookupServiceVariableName(method);
1050         String entityClassName = this.calcEntityClassName(method);
1051         ServiceMethodParameter criteriaParam = findCriteriaParam(method);
1052         importsAdd(CriteriaLookupService.class.getName());
1053         importsAdd(ArrayList.class.getName());
1054         importsAdd(List.class.getName());
1055         indentPrintln("List<String> results = new ArrayList<String>();");
1056         importsAdd (GenericQueryResults.class.getName ());
1057         indentPrintln("GenericQueryResults<" + entityClassName + "> entities");
1058         indentPrintln("    = " + criteriaLookupVariableName + ".lookup(" + entityClassName + ".class, " + criteriaParam.getName() + ");");
1059         indentPrintln("if (null != entities && !entities.getResults().isEmpty()) {");
1060         incrementIndent();
1061         indentPrintln("for (" + entityClassName + " entity : entities.getResults()) {");
1062         incrementIndent();
1063         indentPrintln("results.add(entity.getId());");
1064         decrementIndent();
1065         indentPrintln("}");
1066         decrementIndent();
1067         indentPrintln("}");
1068         indentPrintln("return results;");
1069     }
1070 
1071     private void writeSearchForInfos(ServiceMethod method) {
1072 //        List<AppliedHoldInfo> results = new ArrayList<AppliedHoldInfo>();
1073 //        GenericQueryResults<AppliedHoldEntity> appliedHolds = criteriaLookupService.lookup(AppliedHoldEntity.class, criteria);
1074 //        if (null != appliedHolds && appliedHolds.getResults().size() > 0) {
1075 //            for (AppliedHoldEntity appliedHold : appliedHolds.getResults()) {
1076 //                results.add(appliedHold.toDto());
1077 //            }
1078 //        }
1079 //        return results;
1080         String objectName = this.calcObjectName(method);
1081         String criteriaLookupVariableName = calcCriteriaLookupServiceVariableName(method);
1082         String entityClassName = this.calcEntityClassName(method);
1083         String infoName = this.calcInfoName(method);
1084         ServiceMethodParameter criteriaParam = findCriteriaParam(method);
1085         importsAdd(CriteriaLookupService.class.getName());
1086         importsAdd(ArrayList.class.getName());
1087         importsAdd(List.class.getName());
1088         indentPrintln("List<" + infoName + "> results = new ArrayList<" + infoName + ">();");
1089         importsAdd (GenericQueryResults.class.getName ());
1090         indentPrintln("GenericQueryResults<" + entityClassName + "> entities");
1091         indentPrintln("    = " + criteriaLookupVariableName + ".lookup(" + entityClassName + ".class, " + criteriaParam.getName() + ");");
1092         indentPrintln("if (null != entities && !entities.getResults().isEmpty()) {");
1093         incrementIndent();
1094         indentPrintln("for (" + entityClassName + " entity : entities.getResults()) {");
1095         incrementIndent();
1096         indentPrintln("results.add(entity.toDto());");
1097         decrementIndent();
1098         indentPrintln("}");
1099         decrementIndent();
1100         indentPrintln("}");
1101         indentPrintln("return results;");
1102     }
1103 
1104     private ServiceMethodParameter getTypeParameter(ServiceMethod method) {
1105         ServiceMethodParameter fallbackParam = null;
1106         for (ServiceMethodParameter parameter : method.getParameters()) {
1107             if (parameter.getName().endsWith("TypeKey")) {
1108                 return parameter;
1109             }
1110             if (parameter.getType().equals("String")) {
1111                 if (parameter.getName().toLowerCase().contains("type")) {
1112                     fallbackParam = parameter;
1113                 }
1114             }
1115         }
1116         return fallbackParam;
1117     }
1118 
1119     private String calcInfoName(ServiceMethod method) {
1120         String objectName = this.calcObjectName(method);
1121         String infoName = objectName;
1122         if (!this.isRice()) {
1123             infoName = infoName + "Info";
1124         }
1125         return infoName;
1126     }
1127 
1128     private void writeGetIdsByType(ServiceMethod method) {
1129         String objectName = this.calcObjectName(method);
1130         String infoName = this.calcInfoName(method);
1131         String daoVariable = calcDaoVariableName(method);
1132         ServiceMethodParameter typeParam = this.getTypeParameter(method);
1133         if (typeParam == null) {
1134 
1135         }
1136         indentPrintln("return " + daoVariable + ".getIdsByType(" + typeParam.getName() + ");");
1137     }
1138 
1139     private void writeRiceGetByNamespaceAndName(ServiceMethod method) {
1140         indentPrintln ("//TODO: JPAIMPL this needs to be implemented");
1141         indentPrintln ("throw new OperationFailedException (\"Not implemented\");");
1142     }
1143 
1144     private void writeGetInfosByOther(ServiceMethod method) {
1145 //        List<AppliedHoldEntity> entities = this.appliedHoldDao.getByPerson(personId);
1146 //        List<AppliedHoldInfo> result = new ArrayList<AppliedHoldInfo>(entities.size());
1147 //        for (AppliedHoldEntity entity : entities) {
1148 //            result.add(entity.toDto());
1149 //        }
1150 //        return result;
1151         String objectName = this.calcObjectName(method);
1152         String infoName = objectName;
1153         if (!this.isRice()) {
1154             infoName = infoName + "Info";
1155         }
1156         String daoVariableName = calcDaoVariableName(method);
1157         String namedQuery = calcNamedQuery(method);
1158         String entityClassName = calcEntityClassName(method);
1159         indentPrint("List<" + entityClassName + "> entities = " + daoVariableName + "." + namedQuery + "(");
1160         String comma = "";
1161         for (ServiceMethodParameter param : method.getParameters()) {
1162             if (param.getType().equals("ContextInfo")) {
1163                 continue;
1164             }
1165             print(comma);
1166             comma = ", ";
1167             print(param.getName());
1168         }
1169         println(");");
1170         this.importsAdd(ArrayList.class.getName());
1171         indentPrintln("List<" + infoName + "> list = new ArrayList<" + infoName + "> (entities.size());");
1172         indentPrintln("for (" + entityClassName + " entity: entities) {");
1173         indentPrintln("    list.add (entity.toDto ());");
1174         indentPrintln("}");
1175         indentPrintln("return list;");
1176     }
1177 
1178     private void writeGetType(ServiceMethod method) {
1179         indentPrintln ("//TODO: JPAIMPL this needs to be implemented");
1180         indentPrintln ("throw new OperationFailedException (\"Not implemented\");");
1181     }
1182 
1183     private void writeGetTypes(ServiceMethod method) {
1184         indentPrintln ("//TODO: JPAIMPL this needs to be implemented");
1185         indentPrintln ("throw new OperationFailedException (\"Not implemented\");");
1186     }
1187 
1188     private String initUpper(String str) {
1189         return str.substring(0, 1).toUpperCase() + str.substring(1);
1190     }
1191 
1192     private ServiceMethodParameter findIdListParameter(ServiceMethod method) {
1193         String idFieldName = calcObjectName(method) + "Ids";
1194         if (this.isRice()) {
1195             idFieldName = "ids";
1196         }
1197         for (ServiceMethodParameter parameter : method.getParameters()) {
1198             if (parameter.getType().equals("StringList")) {
1199                 if (parameter.getName().equals(idFieldName)) {
1200                     return parameter;
1201                 }
1202             }
1203         }
1204         // can't find name exactly 
1205         for (ServiceMethodParameter parameter : method.getParameters()) {
1206             if (parameter.getType().equals("StringList")) {
1207                 if (parameter.getName().endsWith("Ids")) {
1208                     return parameter;
1209                 }
1210             }
1211         }
1212         // can't find name exactly try key 
1213         for (ServiceMethodParameter parameter : method.getParameters()) {
1214             if (parameter.getType().equals("StringList")) {
1215                 if (parameter.getName().endsWith("Keys")) {
1216                     return parameter;
1217                 }
1218             }
1219         }
1220         return null;
1221     }
1222 
1223     private String stripList(String str) {
1224         return GetterSetterNameCalculator.stripList(str);
1225     }
1226 
1227     private String calcExceptionClassName(ServiceMethodError error) {
1228         if (error.getClassName() == null) {
1229             return ServiceExceptionWriter.calcClassName(error.getType());
1230         }
1231         return error.getClassName();
1232     }
1233 
1234     private String calcExceptionPackageName(ServiceMethodError error) {
1235         if (error.getClassName() == null) {
1236             return ServiceExceptionWriter.calcPackage(rootPackage);
1237         }
1238         return error.getPackageName();
1239     }
1240 
1241     private String calcType(String type, String realType) {
1242         XmlType t = finder.findXmlType(this.stripList(type));
1243         String retType = MessageStructureTypeCalculator.calculate(this, model, type, realType,
1244                 t.getJavaPackage());
1245         if (this.isRice()) {
1246             if (retType.equals("Boolean")) {
1247                 retType = "boolean";
1248             }
1249             if (retType.equals("Void")) {
1250                 retType = "void";
1251             }
1252         }
1253         return retType;
1254     }
1255 }