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.ServiceContractModel;
19  import org.kuali.student.contract.model.ServiceMethod;
20  import org.kuali.student.contract.model.ServiceMethodError;
21  import org.kuali.student.contract.model.ServiceMethodParameter;
22  import org.kuali.student.contract.model.XmlType;
23  import org.kuali.student.contract.model.util.ModelFinder;
24  import org.kuali.student.contract.writer.JavaClassWriter;
25  import org.kuali.student.contract.writer.service.GetterSetterNameCalculator;
26  import org.kuali.student.contract.writer.service.MessageStructureTypeCalculator;
27  import org.kuali.student.contract.writer.service.ServiceExceptionWriter;
28  import org.slf4j.Logger;
29  import org.slf4j.LoggerFactory;
30  
31  import java.util.*;
32  import javax.persistence.CascadeType;
33  import javax.persistence.Column;
34  import javax.persistence.Entity;
35  import javax.persistence.FetchType;
36  import javax.persistence.NamedQueries;
37  import javax.persistence.NamedQuery;
38  import javax.persistence.OneToMany;
39  import javax.persistence.Table;
40  import javax.persistence.Temporal;
41  import javax.persistence.TemporalType;
42  import org.apache.commons.lang.StringUtils;
43  import org.kuali.student.contract.model.MessageStructure;
44  
45  /**
46   *
47   * @author nwright
48   */
49  public class JpaEntityWriter extends JavaClassWriter {
50  
51      private static final Logger log = LoggerFactory.getLogger(JpaEntityWriter.class);
52  
53      //////////////////////////////
54      // Constants
55      //////////////////////////////
56      /**
57       * The standard type of methods used in our Service contract.
58       */
59      protected static enum MethodType {
60  
61          VALIDATE,
62          CREATE,
63          CREATE_BULK,
64          ADD,
65          UPDATE,
66          UPDATE_OTHER,
67          DELETE,
68          REMOVE,
69          DELETE_OTHER,
70          GET_CREATE,
71          GET_BY_ID,
72          GET_BY_IDS,
73          RICE_GET_BY_NAMESPACE_AND_NAME,
74          GET_IDS_BY_TYPE,
75          GET_IDS_BY_OTHER,
76          GET_INFOS_BY_OTHER,
77          GET_TYPE,
78          GET_TYPES,
79          SEARCH_FOR_IDS,
80          SEARCH_FOR_INFOS,
81          UNKNOWN
82      };
83  
84      //////////////////////////////
85      // Data Variables
86      //////////////////////////////
87      protected ServiceContractModel model;
88      protected ModelFinder finder;
89      private String directory;
90      private XmlType xmlType;
91      /**
92       * The package name is stored in the service object itself (the package spec
93       * kept moving around so I assumed the actual service name was unique but
94       * ran into a problem when we included rice because they have a StateService
95       * meaning US states and we have a StateService meaning the state of the
96       * object so I added logic to detect rice and prepend that "RICE." to it
97       */
98      private String rootPackage;
99  
100     /**
101      * Name of the service being operated on. If it is a RICE service it is
102      * prefixed with RICE. [11:32:18 AM] Norman Wright: short name... I think it
103      * gets it by taking the java class SimpleName and stripping off the word
104      * "Service" and I think making it lower case. [11:32:24 AM] Norman Wright:
105      * so OrganizationService becomes organization
106      */
107     protected String servKey;
108     /**
109      * A flag that holds if the service is an R1 service.
110      */
111     private boolean isR1;
112     private List<ServiceMethod> methods;
113 
114     //////////////////////////
115     // Constructor
116     //////////////////////////
117     public JpaEntityWriter(ServiceContractModel model,
118             String directory,
119             String rootPackage,
120             String servKey,
121             List<ServiceMethod> methods,
122             XmlType xmlType,
123             boolean isR1) {
124         super(directory, calcPackage(servKey, rootPackage), calcClassName(servKey, xmlType));
125         this.model = model;
126         this.finder = new ModelFinder(model);
127         this.directory = directory;
128         this.rootPackage = rootPackage;
129         this.servKey = servKey;
130         this.methods = methods;
131         this.xmlType = xmlType;
132         this.isR1 = isR1;
133     }
134 
135     public JpaEntityWriter(ServiceContractModel model,
136             String directory,
137             String rootPackage,
138             String servKey,
139             List<ServiceMethod> methods,
140             XmlType xmlType,
141             boolean isR1,
142             String packageName,
143             String className) {
144         super(directory, packageName, className);
145         this.model = model;
146         this.finder = new ModelFinder(model);
147         this.directory = directory;
148         this.rootPackage = rootPackage;
149         this.servKey = servKey;
150         this.methods = methods;
151         this.xmlType = xmlType;
152         this.isR1 = isR1;
153     }
154 
155     /////////////////////////
156     // Functional Methods
157     /////////////////////////
158     /**
159      * Returns the jpa implementation package name.
160      *
161      * @param servKey
162      * @param rootPackage
163      * @return
164      */
165     public static String calcPackage(String servKey, String rootPackage) {
166         String pack = rootPackage + ".";
167 //        String pack = rootPackage + "." + servKey.toLowerCase() + ".";
168 //  StringBuffer buf = new StringBuffer (service.getVersion ().length ());
169 //  for (int i = 0; i < service.getVersion ().length (); i ++)
170 //  {
171 //   char c = service.getVersion ().charAt (i);
172 //   c = Character.toLowerCase (c);
173 //   if (Character.isLetter (c))
174 //   {
175 //    buf.append (c);
176 //    continue;
177 //   }
178 //   if (Character.isDigit (c))
179 //   {
180 //    buf.append (c);
181 //   }
182 //  }
183 //  pack = pack + buf.toString ();
184         pack = pack + "service.impl.jpa." + servKey.toLowerCase();
185         return pack;
186     }
187 
188     /**
189      * Checks if this is a RICE service.
190      *
191      * @return true if this is a RICE service.
192      */
193     private boolean isRice() {
194         if (this.servKey.startsWith("RICE.")) {
195             return true;
196         }
197         return false;
198     }
199 
200     protected static String fixServKey(String servKey) {
201         if (servKey.startsWith("RICE.")) {
202             return servKey.substring("RICE.".length());
203         }
204         return servKey;
205     }
206 
207     /**
208      * Given the service key (name), returns a calculated class name for the jpa
209      * impl.
210      */
211     public static String calcClassName(String servKey, XmlType xmlType) {
212         String name = calcInfcName(xmlType) + "Entity";
213         return name;
214     }
215 
216     private String calcInfcName() {
217         String name = calcInfcName(xmlType);
218         String pkg = xmlType.getJavaPackage();
219         if (pkg.endsWith(".dto")) {
220             pkg = pkg.substring(0, pkg.length() - ".dto".length()) + ".infc";
221         }
222         importsAdd(pkg + "." + name);
223         return name;
224     }
225 
226     private String calcInfoName() {
227         String name = initUpper(xmlType.getName());
228         String pkg = xmlType.getJavaPackage();
229         importsAdd(pkg + "." + name);
230         return name;
231     }
232 
233     public static String calcInfcName(XmlType xmlType) {
234         String name = xmlType.getName();
235         if (name.endsWith("Info")) {
236             name = name.substring(0, name.length() - "Info".length());
237         }
238         name = GetterSetterNameCalculator.calcInitUpper(name);
239         return name;
240     }
241 
242     /**
243      * Analyses the method and returns a MethodType enum that describes what
244      * type of method this is.
245      */
246     protected MethodType calcMethodType(ServiceMethod method) {
247         if (this.isRice()) {
248             if (method.getName().contains("ByNamespaceCodeAndName")) {
249                 return MethodType.RICE_GET_BY_NAMESPACE_AND_NAME;
250             }
251             if (method.getName().contains("ByNameAndNamespace")) {
252                 return MethodType.RICE_GET_BY_NAMESPACE_AND_NAME;
253             }
254             if (method.getName().startsWith("get")) {
255                 if (method.getParameters().size() == 1) {
256                     if (!method.getReturnValue().getType().endsWith("List")) {
257                         if (method.getParameters().get(0).getName().equals("id")) {
258                             return MethodType.GET_BY_ID;
259                         }
260 
261                     } else {
262                         if (method.getParameters().get(0).getName().equals("ids")) {
263                             return MethodType.GET_BY_IDS;
264                         }
265                     }
266                 }
267             }
268         }
269         if (method.getName().startsWith("validate")) {
270             return MethodType.VALIDATE;
271         }
272         if (method.getName().startsWith("create")) {
273             if (this.findInfoParameter(method) != null) {
274                 return MethodType.CREATE;
275             }
276             return MethodType.CREATE_BULK;
277         }
278         if (method.getName().startsWith("add")) {
279             return MethodType.ADD;
280         }
281         if (method.getName().startsWith("update")) {
282             if (this.findInfoParameter(method) != null) {
283                 return MethodType.UPDATE;
284             }
285             return MethodType.UPDATE_OTHER;
286         }
287         if (method.getName().startsWith("delete")) {
288             if (method.getName().contains("By")) {
289                 if (!method.getName().startsWith("deleteBy")) {
290                     return MethodType.DELETE_OTHER;
291                 }
292             }
293             if (method.getName().contains("For")) {
294                 if (!method.getName().startsWith("deleteFor")) {
295                     return MethodType.DELETE_OTHER;
296                 }
297             }
298             return MethodType.DELETE;
299         }
300         if (method.getName().startsWith("remove")) {
301             return MethodType.REMOVE;
302         }
303 
304         if (method.getName().startsWith("getCreate")) {
305             return MethodType.GET_CREATE;
306         }
307 
308         if (method.getName().startsWith("get")) {
309             if (method.getName().endsWith("ByIds")) {
310                 return MethodType.GET_BY_IDS;
311             }
312             if (method.getName().endsWith("ByKeys")) {
313                 return MethodType.GET_BY_IDS;
314             }
315             if (method.getName().endsWith("ByType")) {
316                 return MethodType.GET_IDS_BY_TYPE;
317             }
318             if (method.getReturnValue().getType().endsWith("TypeInfo")) {
319                 return MethodType.GET_TYPE;
320             }
321             if (method.getReturnValue().getType().endsWith("TypeInfoList")) {
322                 return MethodType.GET_TYPES;
323             }
324             if (method.getName().endsWith("ByType")) {
325                 return MethodType.GET_IDS_BY_TYPE;
326             }
327             if (method.getParameters().size() >= 1 && method.getParameters().size() <= 2) {
328                 if (!method.getReturnValue().getType().endsWith("List")) {
329 //                    if (method.getParameters().get(0).getName().endsWith("Id")) {
330                     return MethodType.GET_BY_ID;
331 //                    }
332                 }
333             }
334             if (method.getName().contains("By")) {
335                 if (method.getReturnValue().getType().equals("StringList")) {
336                     return MethodType.GET_IDS_BY_OTHER;
337                 }
338                 if (method.getReturnValue().getType().endsWith("InfoList")) {
339                     return MethodType.GET_INFOS_BY_OTHER;
340                 }
341             }
342         }
343         if (method.getName().startsWith("searchFor")) {
344             if (method.getName().endsWith("Ids")) {
345                 return MethodType.SEARCH_FOR_IDS;
346             }
347             if (method.getName().endsWith("Keys")) {
348                 return MethodType.SEARCH_FOR_IDS;
349             }
350             return MethodType.SEARCH_FOR_INFOS;
351         }
352 
353         return MethodType.UNKNOWN;
354     }
355 
356     private String calcTableName(XmlType xmlType) {
357         String tableName = xmlType.getTableName();
358         if (tableName != null) {
359             return tableName;
360         }
361         return calcTableName(xmlType.getName());
362     }
363 
364     private String calcTableName(String name) {
365         if (name.endsWith("Info")) {
366             name = name.substring(0, name.length() - "Info".length());
367         }
368         String tableName = "KSEN_" + splitCamelCase(name).toUpperCase();
369         tableName = applyAbbreviations(tableName.toUpperCase());
370         return tableName;
371     }
372 
373     // got this from
374     // http://stackoverflow.com/questions/2559759/how-do-i-convert-camelcase-into-human-readable-names-in-java
375     private static String splitCamelCase(String s) {
376         if (s == null) {
377             return null;
378         }
379         return s.replaceAll(String.format("%s|%s|%s",
380                 "(?<=[A-Z])(?=[A-Z][a-z])", "(?<=[^A-Z])(?=[A-Z])",
381                 "(?<=[A-Za-z])(?=[^A-Za-z])"), "_");
382     }
383 
384     private String calcColumnName(MessageStructure ms) {
385         String name = ms.getColumnName();
386         if (name != null) {
387             return name;
388         }
389         if (ms.getShortName().equalsIgnoreCase("TypeKey")) {
390             String prefix = calcTableName(xmlType);
391             if (prefix.startsWith("KSEN_")) {
392                 prefix = prefix.substring("KSEN_".length());
393             }
394             // already applied
395 //            prefix = applyAbbreviations (prefix.toUpperCase());
396             return prefix + "_TYPE";
397         }
398         if (ms.getShortName().equalsIgnoreCase("StateKey")) {
399             String prefix = calcTableName(xmlType);
400             if (prefix.startsWith("KSEN_")) {
401                 prefix = prefix.substring("KSEN_".length());
402             }
403             // already applied
404 //            prefix = applyAbbreviations (prefix.toUpperCase());
405             return prefix + "_STATE";
406         }
407         name = splitCamelCase(ms.getShortName());
408         name = applyAbbreviations(name.toUpperCase());
409         return name;
410     }
411 
412     private static final Map<String, String> ABBREVIATIONS = new LinkedHashMap<String, String>();
413 
414     // known abbreviations see https://wiki.kuali.org/display/STUDENT/Database+Abbreviations+for+R2
415     static {
416         ABBREVIATIONS.put("ABBREVIATION", "ABBREV");
417         ABBREVIATIONS.put("ACCOUNT", "ACCT");
418         ABBREVIATIONS.put("ACCOUNTING", "ACCT");
419         ABBREVIATIONS.put("ACCREDITING", "ACCRED");
420         ABBREVIATIONS.put("ACCREDIT", "ACCRED");
421         ABBREVIATIONS.put("ACCREDITATION", "ACCRED");
422         ABBREVIATIONS.put("ACTION", "ACTN");
423         ABBREVIATIONS.put("AFFILIATION", "AFFIL");
424         ABBREVIATIONS.put("AMOUNT", "AMT");
425         ABBREVIATIONS.put("APPLIED", "APPLD");
426         ABBREVIATIONS.put("APPLICATION", "APP");
427         ABBREVIATIONS.put("ALLOWABLE", "ALOW");
428         ABBREVIATIONS.put("ALTERNATE", "ALT");
429         ABBREVIATIONS.put("APPOINTMENT", "APPT");
430         ABBREVIATIONS.put("ASSOCIATED", "ASSO");
431         ABBREVIATIONS.put("ATTRIBUTE", "ATTR");
432         ABBREVIATIONS.put("CAMPUS", "CAMP");
433         ABBREVIATIONS.put("CANONICAL LEARNING UNIT", "CLU");
434         ABBREVIATIONS.put("CATEGORY", "CAT");
435         ABBREVIATIONS.put("CODE", "CD");
436         ABBREVIATIONS.put("COMPLETE", "COMP");
437         ABBREVIATIONS.put("COMPONENT", "CMP");
438         ABBREVIATIONS.put("CONTEXT", "CTX");
439         ABBREVIATIONS.put("CONTINUE", "CONT");
440         ABBREVIATIONS.put("COUNT", "CNT");
441         ABBREVIATIONS.put("CREDIT", "CR");
442         ABBREVIATIONS.put("CRITERIA", "CRIT");
443         ABBREVIATIONS.put("DATE", "DT");
444         ABBREVIATIONS.put("DEADLINE", "DEDLN");
445         ABBREVIATIONS.put("DEFAULT", "DEF");
446         ABBREVIATIONS.put("DEFINABLE", "DEFNBL");
447         ABBREVIATIONS.put("DEFINITION", "DEFN");
448         ABBREVIATIONS.put("DESCRIPTION", "DESCR");
449         ABBREVIATIONS.put("DISABLED", "DISBLD");
450         ABBREVIATIONS.put("DATE OVERRIDE", "DO");
451         ABBREVIATIONS.put("DOCUMENT", "DOC");
452         ABBREVIATIONS.put("DURATION", "DUR");
453         ABBREVIATIONS.put("DIVISION", "DIV");
454         ABBREVIATIONS.put("EFFECTIVE", "EFF");
455         ABBREVIATIONS.put("ENROLL", "ENRL");
456         ABBREVIATIONS.put("ENROLLED", "ENRL");
457         ABBREVIATIONS.put("ENROLLMENT", "ENRL");
458         ABBREVIATIONS.put("ENROLLABLE", "ENRL");
459         ABBREVIATIONS.put("ESTIMATE", "EST");
460         ABBREVIATIONS.put("EXEMPTION", "EXEMPT");
461         ABBREVIATIONS.put("EXPENDITURE", "EXPEND");
462         ABBREVIATIONS.put("EXPIRATION", "EXP");
463         ABBREVIATIONS.put("EXPIRED", "EXP");
464         ABBREVIATIONS.put("FLEXIBLE", "FLEX");
465         ABBREVIATIONS.put("FREQUENCY", "FREQ");
466         ABBREVIATIONS.put("GROUP", "GRP");
467         ABBREVIATIONS.put("HAZARD", "HAZR");
468         ABBREVIATIONS.put("HAZARDOUS", "HAZR");
469         ABBREVIATIONS.put("HEADER", "HDR");
470         ABBREVIATIONS.put("HIERARCHY", "HIRCHY");
471         ABBREVIATIONS.put("IDENTIFIER", "ID");
472         ABBREVIATIONS.put("INACTIVE", "INACV");
473         ABBREVIATIONS.put("INDEPENDENT", "INDPT");
474         ABBREVIATIONS.put("INDICATOR", "IND");
475         ABBREVIATIONS.put("INSTRUCTOR", "INSTR");
476         ABBREVIATIONS.put("INSTRUCTION", "INSTRN");
477         ABBREVIATIONS.put("INSTRUCTIONAL", "INSTRN");
478         ABBREVIATIONS.put("INTENSITY", "INTSTY");
479         ABBREVIATIONS.put("INTERVAL", "INTVL");
480         ABBREVIATIONS.put("LEARNING OBJECTIVE", "LO");
481         ABBREVIATIONS.put("LEARNING RESULT", "LR");
482         ABBREVIATIONS.put("LEARNING UNIT", "LU");
483         ABBREVIATIONS.put("LOCATION", "LOC");
484         ABBREVIATIONS.put("LONG", "LNG");
485         ABBREVIATIONS.put("LEVEL", "LVL");
486         ABBREVIATIONS.put("LIFECYCLE", "LIFCYC");
487         ABBREVIATIONS.put("MARKETING", "MKTG");
488         ABBREVIATIONS.put("MAXIMUM", "MAX");
489         ABBREVIATIONS.put("MEMBER", "MBR");
490         ABBREVIATIONS.put("MESSAGE", "MSG");
491         ABBREVIATIONS.put("MILESTONE", "MSTONE");
492         ABBREVIATIONS.put("MILLISECONDS", "MS");
493         ABBREVIATIONS.put("MINIMUM", "MIN");
494         ABBREVIATIONS.put("NAMESPACE", "NMSPC");
495         ABBREVIATIONS.put("NEXT", "NEXT");
496         ABBREVIATIONS.put("NUMBER", "NUM");
497         ABBREVIATIONS.put("OFFICIAL", "OFFIC");
498         ABBREVIATIONS.put("ORG ORG RELATION TYPE", "OORT");
499         ABBREVIATIONS.put("OPTION", "OPT");
500         ABBREVIATIONS.put("ORGANIZATION", "ORG");
501         ABBREVIATIONS.put("PARAMETER", "PARM");
502         ABBREVIATIONS.put("PARAMETER VALUE", "PV");
503         ABBREVIATIONS.put("PERCENT", "PERCT");
504         ABBREVIATIONS.put("PERIOD", "PRD");
505         ABBREVIATIONS.put("PERSON", "PERS");
506         ABBREVIATIONS.put("POSITION", "POS");
507         ABBREVIATIONS.put("PRIMARY", "PRI");
508         ABBREVIATIONS.put("PROCESS", "PROC");
509         ABBREVIATIONS.put("PUBLISH", "PUBL");
510         ABBREVIATIONS.put("PUBLISHING", "PUBL");
511         ABBREVIATIONS.put("QUANTITY", "QTY");
512         ABBREVIATIONS.put("RECOGNITIION", "RECOG");
513         ABBREVIATIONS.put("RECORD", "REC");
514         ABBREVIATIONS.put("REFERENCE", "REF");
515         ABBREVIATIONS.put("REGISTRATION", "REG");
516         ABBREVIATIONS.put("RELATION", "RELN");
517         ABBREVIATIONS.put("RELATIONSHIP", "RELN");
518         ABBREVIATIONS.put("ROLLOVER RESULT", "ROR");
519         ABBREVIATIONS.put("REQUEST", "RQST");
520         ABBREVIATIONS.put("REQUIRED", "REQ");
521         ABBREVIATIONS.put("REPONSIBLE", "RESP");
522         ABBREVIATIONS.put("RESOURCE", "RSRC");
523         ABBREVIATIONS.put("RESTRICTION", "RESTR");
524         ABBREVIATIONS.put("RESULT VALUE GROUP", "RVG");
525         ABBREVIATIONS.put("REVIEW", "REVIEW");
526         ABBREVIATIONS.put("RICH TEXT", "RT");
527         ABBREVIATIONS.put("SCHEDULE", "SCHED");
528         ABBREVIATIONS.put("SHORT", "SHRT");
529         ABBREVIATIONS.put("SLOT RULE", "SR");
530         ABBREVIATIONS.put("STANDARD", "STD");
531         ABBREVIATIONS.put("STATE", "ST");
532         ABBREVIATIONS.put("STATEMENT", "STMNT");
533         ABBREVIATIONS.put("STUDENT", "STU");
534         ABBREVIATIONS.put("STUDY", "STDY");
535         ABBREVIATIONS.put("SUBJECT", "SUBJ");
536         ABBREVIATIONS.put("SUFFIX", "SUFX");
537         ABBREVIATIONS.put("TEMPLATE", "TMPLT");
538         ABBREVIATIONS.put("TIME", "TM");
539         ABBREVIATIONS.put("TITLE", "TTL");
540         ABBREVIATIONS.put("TOTAL", "TOT");
541         ABBREVIATIONS.put("TRANSACTION", "TRANS");
542         ABBREVIATIONS.put("TYPE", "TYP");
543         ABBREVIATIONS.put("VARIATION", "VARTN");
544         ABBREVIATIONS.put("VERSION NUMBER", "VER_NBR");
545         ABBREVIATIONS.put("", "");
546     }
547 
548     private String applyAbbreviations(String name) {
549         // THIS DOESN'T HANDLE THE MULTI-WORD ABBREVIATIONS!
550         // good enough for now
551         String[] parts = name.split("_");
552         for (int i = 0; i < parts.length; i++) {
553             String abbrev = ABBREVIATIONS.get(parts[i]);
554             if (abbrev != null) {
555                 System.out.println("Replacing abbreviation " + parts[i] + " with " + abbrev);
556                 parts[i] = abbrev;
557             }
558         }
559         name = StringUtils.join(parts, '_');
560         return name;
561     }
562 
563     private boolean isNullable(MessageStructure ms) {
564         if (ms.getRequired() == null) {
565             return true;
566         }
567         if (ms.getRequired().equalsIgnoreCase("Required")) {
568             return false;
569         }
570         // figure out what to do if it is qualified like
571         // "required on update"
572         return true;
573     }
574 
575     private String keyOrId() {
576 
577         if (finder.findMessageStructure(xmlType.getName(), "id") != null) {
578             return "Id";
579         }
580         if (finder.findMessageStructure(xmlType.getName(), "key") != null) {
581             return "Key";
582         }
583         return "Id";
584     }
585 
586     private boolean hasAttributes() {
587         for (MessageStructure ms : finder.findMessageStructures(xmlType.getName())) {
588             if (ms.getShortName().equals("attributes")) {
589                 return true;
590             }
591         }
592         return false;
593     }
594 
595     private boolean isMethodForThisType(XmlType xmlType, ServiceMethod method) {
596         String objectName = calcObjectName(method);
597         if (objectName == null) {
598             return false;
599         }
600         if (xmlType.getName().equalsIgnoreCase(objectName + "Info")) {
601             return true;
602         }
603         return false;
604     }
605 
606     /**
607      * Write out the entire file
608      */
609     public void write() {
610         indentPrintln("@Entity");
611         importsAdd(Entity.class.getName());
612         String tableName = calcTableName(xmlType);
613         if (xmlType.getTableName() == null) {
614             indentPrintln("//TODO: JPAIMPL double check table name because it was calculated based on heuristics and may not match the actual table name");
615         }
616         indentPrintln("@Table(name = \"" + tableName + "\")");
617         importsAdd(Table.class.getName());
618 //@NamedQueries({
619 //    @NamedQuery(name = "HoldIssueEntity.getIdsByType",
620 //    query = "select id from HoldIssueEntity where holdIssueType = :type"),
621 //    @NamedQuery(name = "HoldIssueEntity.getByOrganization",
622 //    query = "select ISSUE from HoldIssueEntity ISSUE where ISSUE.organizationId = :organizationId")
623 //})
624         String className = calcClassName(servKey, xmlType);
625         String attributeEntity = JpaAttributeEntityWriter.calcClassName(servKey, xmlType);
626         indentPrintln("@NamedQueries({");
627         String comma = "";
628         for (ServiceMethod method : methods) {
629             if (!isMethodForThisType(xmlType, method)) {
630                 continue;
631             }
632             MethodType methodType = calcMethodType(method);
633             switch (methodType) {
634                 case GET_IDS_BY_TYPE:
635                     indentPrint(comma);
636                     comma = ",";
637                     indentPrintln("@NamedQuery(name = \"" + className + ".getIdsByType\",");
638                     indentPrintln("    query = \"select id from " + className + " where typeKey = :type\")");
639                     break;
640                 case GET_IDS_BY_OTHER:
641                     indentPrintln("//TODO: JPAIMPL double check this JPQL queries to make sure they match the intention of the service method");
642                     indentPrint(comma);
643                     comma = ",";
644                     String namedQuery = calcNamedQuery(method);
645                     indentPrintln("@NamedQuery(name = \"" + className + "." + namedQuery + "\",");
646 
647                     indentPrint("    query = \"select id from " + className);
648                     String and = " where ";
649                     for (ServiceMethodParameter param : method.getParameters()) {
650                         if (param.getType().equals("ContextInfo")) {
651                             continue;
652                         }
653                         print(and);
654                         and = " and ";
655                         String paramName = initLower(param.getName());
656                         print(paramName + " = :" + paramName);
657                     }
658                     println("\")");
659                     break;
660                 case GET_INFOS_BY_OTHER:
661                     indentPrintln("//TODO: JPAIMPL double check this JPQL queries to make sure they match the intention of the service method");
662                     indentPrint(comma);
663                     comma = ",";
664                     namedQuery = calcNamedQuery(method);
665                     indentPrintln("@NamedQuery(name = \"" + className + "." + namedQuery + "\",");
666 
667                     indentPrint("    query = \"select " + className + " from " + className);
668                     and = " where ";
669                     for (ServiceMethodParameter param : method.getParameters()) {
670                         if (param.getType().equals("ContextInfo")) {
671                             continue;
672                         }
673                         print(and);
674                         and = " and ";
675                         String paramName = initLower(param.getName());
676                         print(paramName + " = :" + paramName);
677                     }
678                     println("\")");
679                     break;
680             }
681         }
682         indentPrintln("})");
683         importsAdd(NamedQueries.class.getName());
684         importsAdd(NamedQuery.class.getName());
685         indentPrint("public class " + calcClassName(servKey, xmlType));
686         println(" extends MetaEntity");
687         importsAdd("org.kuali.student.r2.common.entity.MetaEntity");
688 
689         boolean hasAttributes = hasAttributes();
690         String attributeEntityName = JpaAttributeEntityWriter.calcClassName(servKey, xmlType);
691         if (hasAttributes) {
692             indentPrintln("    implements AttributeOwner<" + attributeEntityName + ">");
693             importsAdd("org.kuali.student.r2.common.entity.AttributeOwner");
694         }
695         openBrace();
696 
697         for (MessageStructure ms : finder.findMessageStructures(xmlType.getName())) {
698             if (ms.getShortName().equalsIgnoreCase("id")) {
699                 continue;
700             }
701             if (ms.getShortName().equalsIgnoreCase("meta")) {
702                 continue;
703             }
704             if (ms.getShortName().equalsIgnoreCase("key")) {
705                 continue;
706             }
707             if (ms.getShortName().equalsIgnoreCase("descr")) {
708                 importsAdd(Column.class.getName());
709                 importsAdd("org.kuali.student.r1.common.entity.KSEntityConstants");
710                 indentPrintln("@Column(name = \"DESCR_PLAIN\", length = KSEntityConstants.EXTRA_LONG_TEXT_LENGTH, nullable = false)");
711                 indentPrintln("private String descrPlain;");
712                 indentPrintln("@Column(name = \"DESCR_FORMATTED\", length = KSEntityConstants.EXTRA_LONG_TEXT_LENGTH)");
713                 indentPrintln("private String descrFormatted;");
714                 continue;
715             }
716             if (ms.getShortName().equalsIgnoreCase("attributes")) {
717                 importsAdd(OneToMany.class.getName());
718                 importsAdd(CascadeType.class.getName());
719                 importsAdd(FetchType.class.getName());
720                 importsAdd(Set.class.getName());
721                 importsAdd(HashSet.class.getName());
722                 indentPrintln("@OneToMany(cascade = CascadeType.ALL, mappedBy = \"owner\", fetch = FetchType.EAGER, orphanRemoval = true)");
723                 indentPrintln("private final Set<" + attributeEntity + "> attributes = new HashSet<" + attributeEntity + ">();");
724                 JpaAttributeEntityWriter attrEntityWriter
725                         = new JpaAttributeEntityWriter(model, directory, rootPackage, servKey, methods, xmlType, isR1, className);
726                 attrEntityWriter.write();
727                 continue;
728             }
729             //    @Column(name = "NAME")
730             //    private String name;
731             importsAdd(Column.class.getName());
732             String columnName = calcColumnName(ms);
733             if (ms.getType().equalsIgnoreCase("Date")) {
734                 importsAdd(Temporal.class.getName());
735                 importsAdd(TemporalType.class.getName());
736                 indentPrintln("@Temporal(TemporalType.TIMESTAMP)");
737             }
738             if (shouldAddJpaImplTodo(ms)) {
739                 indentPrintln("//TODO: JPAIMPL double check column name it was calculated based on heuristics and may not match actual table column");
740             }
741             indentPrintln("@Column(name= \"" + columnName + "\", nullable=" + this.isNullable(ms) + ")");
742             String javaClass = this.calcType(ms.getType(), this.stripList(ms.getType()));
743             indentPrintln("private " + javaClass + " " + initLower(ms.getShortName()) + ";");
744         }
745 
746         println("");
747 //    public HoldIssueEntity() {
748 //    }
749 //
750 //    public HoldIssueEntity(HoldIssue dto) {
751 //        super(dto);
752 //        this.setId(dto.getId());
753 //        this.setHoldIssueType(dto.getTypeKey());
754 //        this.fromDto(dto);
755 //    }
756         String infcName = this.calcInfcName();
757         println("");
758         indentPrintln("public " + className + "() {");
759         indentPrintln("}");
760         println("");
761         indentPrintln("public " + className + "(" + infcName + " dto) {");
762         incrementIndent();
763         indentPrintln("super(dto);");
764         String keyOrId = this.keyOrId();
765         indentPrintln("this.setId(dto.get" + keyOrId + "());");
766         indentPrintln("this.setTypeKey(dto.getTypeKey());");
767         indentPrintln("// TODO: JPAIMPL insert other fields that should only be specified on create");
768         indentPrintln("this.fromDto(dto);");
769         decrementIndent();
770         indentPrintln("}");
771 
772 //        public void fromDto(HoldIssue dto) {
773 //        super.fromDTO(dto);
774 //        
775 //        setName(dto.getName());
776 //        setHoldIssueState(dto.getStateKey());
777 //        setOrganizationId(dto.getOrganizationId());
778 //        if (dto.getDescr() != null) {
779 //            this.setDescrFormatted(dto.getDescr().getFormatted());
780 //            this.setDescrPlain(dto.getDescr().getPlain());
781 //        } else {
782 //            this.setDescrFormatted(null);
783 //            this.setDescrPlain(null);
784 //        }
785 //
786 //        // dynamic attributes
787 //        this.getAttributes().clear();
788 //        for (Attribute att : dto.getAttributes()) {
789 //            HoldIssueAttributeEntity attEntity = new HoldIssueAttributeEntity(att, this);
790 //            this.getAttributes().add(attEntity);
791 //        }
792 //    }
793         println("");
794         indentPrintln("public void fromDto(" + infcName + " dto) {");
795         incrementIndent();
796         indentPrintln("super.fromDTO(dto);");
797         indentPrintln("// TODO: JPAIMPL move all fields that are only supposed to be only specified on create up to the constructor section (like type is)");
798         for (MessageStructure ms : finder.findMessageStructures(xmlType.getName())) {
799             if (ms.getShortName().equalsIgnoreCase("id")) {
800                 continue;
801             }
802             if (ms.getShortName().equalsIgnoreCase("meta")) {
803                 continue;
804             }
805             if (ms.getShortName().equalsIgnoreCase("key")) {
806                 continue;
807             }
808             if (ms.getShortName().equalsIgnoreCase("typeKey")) {
809                 continue;
810             }
811             if (ms.getShortName().equalsIgnoreCase("typeKey")) {
812                 continue;
813             }
814             if (ms.getShortName().equalsIgnoreCase("descr")) {
815                 println("");
816                 indentPrintln("if (dto.getDescr() != null) {");
817                 indentPrintln("    this.setDescrFormatted(dto.getDescr().getFormatted());");
818                 indentPrintln("    this.setDescrPlain(dto.getDescr().getPlain());");
819                 indentPrintln("} else {");
820                 indentPrintln("     this.setDescrFormatted(null);");
821                 indentPrintln("     this.setDescrPlain(null);");
822                 indentPrintln("}");
823                 println("");
824                 continue;
825             }
826             if (ms.getShortName().equalsIgnoreCase("attributes")) {
827                 importsAdd("org.kuali.student.r2.common.infc.Attribute");
828                 println("");
829                 indentPrintln("// dynamic attributes");
830                 indentPrintln("this.getAttributes().clear();");
831                 indentPrintln("for (Attribute att : dto.getAttributes()) {");
832                 indentPrintln("    " + attributeEntityName + " attEntity = new " + attributeEntityName + "(att, this);");
833                 indentPrintln("    this.getAttributes().add(attEntity);");
834                 indentPrintln("}");
835                 continue;
836             }
837             // regular fields
838             String upperName = initUpper(ms.getShortName());
839             indentPrintln("set" + upperName + "(dto.get" + upperName + "());");
840         }
841         decrementIndent();
842         indentPrintln("}");
843 
844 //       public AppliedHoldInfo toDto() {
845 //        AppliedHoldInfo info = new AppliedHoldInfo();
846 //        info.setId(getId());
847 //        info.setName(name);
848 //        info.setEffectiveDate(effectiveDate);
849 //        info.setReleasedDate(releasedDate);
850 //        info.setPersonId(personId);
851 //        info.setTypeKey(holdType);
852 //        info.setStateKey(holdState);
853 //        if (holdIssue != null) {
854 //            info.setHoldIssueId(holdIssue.getId());
855 //        }
856 //        info.setDescr(new RichTextHelper().toRichTextInfo(getDescrPlain(), getDescrFormatted()));
857 //
858 //        info.setMeta(super.toDTO());
859 //        for (AppliedHoldAttributeEntity att : getAttributes()) {
860 //            AttributeInfo attInfo = att.toDto();
861 //            info.getAttributes().add(attInfo);
862 //        }
863 //        return info;
864 //    }
865         String infoName = this.calcInfoName();
866         println("");
867         indentPrintln("public " + infoName + " toDto() {");
868         incrementIndent();
869         indentPrintln(infoName + " info = new " + infoName + "();");
870         for (MessageStructure ms : finder.findMessageStructures(xmlType.getName())) {
871             if (ms.getShortName().equalsIgnoreCase("id")) {
872                 indentPrintln("info.setId(getId());");
873                 continue;
874             }
875             if (ms.getShortName().equalsIgnoreCase("meta")) {
876                 indentPrintln("info.setMeta(super.toDTO());");
877                 continue;
878             }
879             if (ms.getShortName().equalsIgnoreCase("key")) {
880                 indentPrintln("info.setKey(getId());");
881                 continue;
882             }
883             if (ms.getShortName().equalsIgnoreCase("descr")) {
884                 importsAdd("org.kuali.student.r2.common.util.RichTextHelper");
885                 indentPrintln("info.setDescr(new RichTextHelper().toRichTextInfo(getDescrPlain(), getDescrFormatted()));");
886                 continue;
887             }
888             if (ms.getShortName().equalsIgnoreCase("attributes")) {
889                 importsAdd("org.kuali.student.r2.common.dto.AttributeInfo");
890                 println("");
891                 indentPrintln("// dynamic attributes");
892                 indentPrintln("for (" + attributeEntityName + " att : getAttributes()) {");
893                 indentPrintln("    AttributeInfo attInfo = att.toDto();");
894                 indentPrintln("    info.getAttributes().add(attInfo);");
895                 indentPrintln("}");
896                 continue;
897             }
898             // regular fields
899             String upperName = initUpper(ms.getShortName());
900             indentPrintln("info.set" + upperName + "(this.get" + upperName + "());");
901         }
902         indentPrintln("return info;");
903         decrementIndent();
904         indentPrintln("}");
905 
906         // write getters and setters
907         for (MessageStructure ms : finder.findMessageStructures(xmlType.getName())) {
908             if (ms.getShortName().equalsIgnoreCase("id")) {
909                 continue;
910             }
911             if (ms.getShortName().equalsIgnoreCase("meta")) {
912                 continue;
913             }
914             if (ms.getShortName().equalsIgnoreCase("key")) {
915                 continue;
916             }
917             if (ms.getShortName().equalsIgnoreCase("descr")) {
918                 println("");
919                 indentPrintln("public String getDescrPlain() {");
920                 indentPrintln("    return this.descrPlain;");
921                 indentPrintln("}");
922                 println("");
923                 indentPrintln("public void setDescrPlain(String descrPlain) {");
924                 indentPrintln("    this.descrPlain = descrPlain;");
925                 indentPrintln("}");
926                 println("");
927                 indentPrintln("public String getDescrFormatted() {");
928                 indentPrintln("    return this.descrFormatted;");
929                 indentPrintln("}");
930                 println("");
931                 indentPrintln("public void setDescrFormatted(String descrFormatted) {");
932                 indentPrintln("    this.descrFormatted = descrFormatted;");
933                 indentPrintln("}");
934                 continue;
935             }
936             if (ms.getShortName().equalsIgnoreCase("attributes")) {
937                 println("");
938                 indentPrintln("@Override");
939                 indentPrintln("public void setAttributes(Set<" + attributeEntityName + "> attributes) {");
940                 incrementIndent();
941                 indentPrintln("this.attributes.clear();");
942                 indentPrintln("if (attributes != null) {");
943                 indentPrintln("    this.attributes.addAll(attributes);");
944                 indentPrintln("}");
945                 decrementIndent();
946                 indentPrintln("}");
947                 println("");
948                 indentPrintln("@Override");
949                 indentPrintln("public Set<" + attributeEntityName + "> getAttributes() {");
950                 indentPrintln("    return attributes;");
951                 indentPrintln("}");
952                 println("");
953                 continue;
954             }
955             importsAdd(Column.class.getName());
956             String variableName = initLower(ms.getShortName());
957             String javaClass = this.calcType(ms.getType(), this.stripList(ms.getType()));
958             String upperName = initUpper(ms.getShortName());
959             println("");
960             indentPrintln("public " + javaClass + " get" + upperName + "() {");
961             indentPrintln("    return this." + variableName + ";");
962             indentPrintln("}");
963             println("");
964             indentPrintln("public void set" + upperName + "(" + javaClass + " " + variableName + ") {");
965             indentPrintln("    this." + variableName + " = " + variableName + ";");
966             indentPrintln("}");
967         }
968 
969         println("");
970         closeBrace();
971 
972         this.writeJavaClassAndImportsOutToFile();
973         this.getOut().close();
974     }
975 
976     private boolean shouldAddJpaImplTodo(MessageStructure ms) {
977         if (ms.getColumnName() != null) {
978             return false;
979         }
980         if (ms.getShortName().equalsIgnoreCase("name")) {
981             return false;
982         }
983         if (ms.getShortName().equalsIgnoreCase("descr")) {
984             return false;
985         }
986         if (ms.getShortName().equalsIgnoreCase("effectiveDate")) {
987             return false;
988         }
989         if (ms.getShortName().equalsIgnoreCase("expirationDate")) {
990             return false;
991         }
992         return true;
993     }
994 
995     private String getInvalidParameterException() {
996         if (this.isRice()) {
997             return "RiceIllegalArgumentException";
998         }
999         return "InvalidParameterException";
1000     }
1001 
1002     private String getOperationFailedException() {
1003         if (this.isRice()) {
1004             return "RiceIllegalArgumentException";
1005         }
1006         return "OperationFailedException";
1007     }
1008 
1009     private String getDoesNotExistException() {
1010         if (this.isRice()) {
1011             return "RiceIllegalArgumentException";
1012         }
1013         return "DoesNotExistException";
1014     }
1015 
1016     private String getVersionMismatchException() {
1017         if (this.isRice()) {
1018             return "RiceIllegalStateException";
1019         }
1020         return "VersionMismatchException";
1021     }
1022 
1023     private void writeThrowsNotImplemented(ServiceMethod method) {
1024         indentPrintln("throw new " + this.getOperationFailedException() + " (\"" + method.getName() + " has not been implemented\");");
1025     }
1026 
1027     protected String initLower(String str) {
1028         return str.substring(0, 1).toLowerCase() + str.substring(1);
1029     }
1030 
1031     private String calcCriteriaLookupServiceVariableName(ServiceMethod method) {
1032         String objectName = calcObjectName(method);
1033         String variableName = initLower(objectName) + "CriteriaLookupService";
1034         return variableName;
1035     }
1036 
1037     private ServiceMethodParameter findIdParameter(ServiceMethod method) {
1038         String idFieldName = calcObjectName(method) + "Id";
1039         for (ServiceMethodParameter parameter : method.getParameters()) {
1040             if (parameter.getType().equals("String")) {
1041                 if (parameter.getName().equals(idFieldName)) {
1042                     return parameter;
1043                 }
1044             }
1045         }
1046 
1047         // if only one parameter and it is a string then grab that
1048         if (method.getParameters().size() == 1) {
1049             for (ServiceMethodParameter parameter : method.getParameters()) {
1050                 if (parameter.getType().equals("String")) {
1051                     return parameter;
1052                 }
1053             }
1054         }
1055         // can't find name exactly 
1056         for (ServiceMethodParameter parameter : method.getParameters()) {
1057             if (parameter.getType().equals("String")) {
1058                 if (parameter.getName().endsWith("Id")) {
1059                     return parameter;
1060                 }
1061             }
1062         }
1063         // can't find name exactly try key 
1064         for (ServiceMethodParameter parameter : method.getParameters()) {
1065             if (parameter.getType().equals("String")) {
1066                 if (!parameter.getName().endsWith("TypeKey")) {
1067                     if (parameter.getName().endsWith("Key")) {
1068                         return parameter;
1069                     }
1070                 }
1071             }
1072         }
1073         log.warn("Could not find the Id paramter for {}.{} so returning the first one", method.getService(), method.getName());
1074         return method.getParameters().get(0);
1075     }
1076 
1077     private ServiceMethodParameter findContextParameter(ServiceMethod method) {
1078         for (ServiceMethodParameter parameter : method.getParameters()) {
1079             if (parameter.getType().equals("ContextInfo")) {
1080                 return parameter;
1081             }
1082         }
1083         return null;
1084     }
1085 
1086     private ServiceMethodParameter findInfoParameter(ServiceMethod method) {
1087         String objectName = calcObjectName(method);
1088         if (!this.isRice()) {
1089             objectName = objectName + "Info";
1090         }
1091         for (ServiceMethodParameter parameter : method.getParameters()) {
1092             if (parameter.getType().equals(objectName)) {
1093                 return parameter;
1094             }
1095         }
1096         if (method.getParameters().size() >= 1) {
1097             return method.getParameters().get(0);
1098         }
1099         return null;
1100     }
1101 
1102     private ServiceMethodParameter findTypeParameter(ServiceMethod method) {
1103         for (ServiceMethodParameter parameter : method.getParameters()) {
1104             if (parameter.getType().equals("String")) {
1105                 if (parameter.getName().endsWith("TypeKey")) {
1106                     return parameter;
1107                 }
1108                 if (parameter.getName().endsWith("Type")) {
1109                     return parameter;
1110                 }
1111             }
1112         }
1113         return null;
1114     }
1115 
1116     private String calcDaoVariableName(ServiceMethod method) {
1117         String daoVariableName = this.calcObjectName(method);
1118         daoVariableName = this.initLower(daoVariableName) + "Dao";
1119         return daoVariableName;
1120     }
1121 
1122     private String calcEntityClassName(ServiceMethod method) {
1123         String objectName = this.calcObjectName(method);
1124         objectName = objectName + "Entity";
1125         return objectName;
1126     }
1127 
1128     protected String calcObjectName(ServiceMethod method) {
1129         if (method.getName().startsWith("create")) {
1130             return method.getName().substring("create".length());
1131         }
1132         if (method.getName().startsWith("update")) {
1133             return method.getName().substring("update".length());
1134         }
1135         if (method.getName().startsWith("validate")) {
1136             return method.getName().substring("validate".length());
1137         }
1138         if (method.getName().startsWith("delete")) {
1139             return method.getName().substring("delete".length());
1140         }
1141         if (method.getName().startsWith("get")) {
1142             if (method.getReturnValue().getType().equals("StringList")) {
1143                 if (method.getName().contains("IdsBy")) {
1144                     return method.getName().substring("get".length(),
1145                             method.getName().indexOf("IdsBy"));
1146                 }
1147                 if (method.getName().contains("KeysBy")) {
1148                     return method.getName().substring("get".length(),
1149                             method.getName().indexOf("KeysBy"));
1150                 }
1151                 if (method.getName().contains("IdsFor")) {
1152                     return method.getName().substring("get".length(),
1153                             method.getName().indexOf("IdsFor"));
1154                 }
1155                 if (method.getName().contains("With")) {
1156                     return method.getName().substring("get".length(),
1157                             method.getName().indexOf("With"));
1158                 }
1159                 if (method.getName().contains("By")) {
1160                     return method.getName().substring("get".length(),
1161                             method.getName().indexOf("By"));
1162                 }
1163                 return method.getName().substring("get".length());
1164             }
1165             String name = method.getReturnValue().getType();
1166             if (name.endsWith("List")) {
1167                 name = name.substring(0, name.length() - "List".length());
1168             }
1169             if (name.endsWith("Info")) {
1170                 name = name.substring(0, name.length() - "Info".length());
1171             }
1172             return name;
1173         }
1174 
1175         if (method.getName().startsWith("searchFor")) {
1176             if (method.getReturnValue().getType().equals("StringList")) {
1177                 if (method.getName().endsWith("Ids")) {
1178                     return method.getName().substring("searchFor".length(),
1179                             method.getName().indexOf("Ids"));
1180                 }
1181                 if (method.getName().endsWith("Keys")) {
1182                     return method.getName().substring("get".length(),
1183                             method.getName().indexOf("Keys"));
1184                 }
1185                 return method.getName().substring("searchFor".length());
1186             }
1187             String name = method.getReturnValue().getType();
1188             if (name.endsWith("List")) {
1189                 name = name.substring(0, name.length() - "List".length());
1190             }
1191             if (name.endsWith("Info")) {
1192                 name = name.substring(0, name.length() - "Info".length());
1193             }
1194             return name;
1195         }
1196         if (method.getName().startsWith("add")) {
1197             return method.getName().substring("add".length());
1198         }
1199         if (method.getName().startsWith("remove")) {
1200             return method.getName().substring("remove".length());
1201         }
1202         String returnType = this.stripList(method.getReturnValue().getType());
1203         XmlType type = this.finder.findXmlType(returnType);
1204         if (type.getPrimitive().equals(XmlType.COMPLEX)) {
1205             return returnType;
1206         }
1207         return null;
1208     }
1209 
1210     private String calcNamedQuery(ServiceMethod method) {
1211         String objectName = calcObjectName(method);
1212         if (objectName == null) {
1213             return null;
1214         }
1215         String name = method.getName();
1216         if (name.startsWith("get")) {
1217             name = name.substring("get".length());
1218         }
1219         if (name.startsWith(objectName)) {
1220             name = name.substring(objectName.length());
1221         }
1222 //        if (name.startsWith("Ids")) {
1223 //            name = name.substring("Ids".length());
1224 //        }
1225 //        if (name.isEmpty()) {
1226 //            throw new RuntimeException (method.getName());
1227 //        }
1228         // remove plural
1229         if (!method.getReturnValue().getType().equals("StringList")) {
1230             if (name.startsWith("s")) {
1231                 name = name.substring("s".length());
1232             }
1233         }
1234         // add back the get
1235         name = "get" + name;
1236         return name;
1237     }
1238 
1239     private ServiceMethodParameter findCriteriaParam(ServiceMethod method) {
1240         for (ServiceMethodParameter param : method.getParameters()) {
1241             if (param.getType().equals("QueryByCriteria")) {
1242                 return param;
1243             }
1244         }
1245         return null;
1246     }
1247 
1248     private ServiceMethodParameter getTypeParameter(ServiceMethod method) {
1249         ServiceMethodParameter fallbackParam = null;
1250         for (ServiceMethodParameter parameter : method.getParameters()) {
1251             if (parameter.getName().endsWith("TypeKey")) {
1252                 return parameter;
1253             }
1254             if (parameter.getType().equals("String")) {
1255                 if (parameter.getName().toLowerCase().contains("type")) {
1256                     fallbackParam = parameter;
1257                 }
1258             }
1259         }
1260         return fallbackParam;
1261     }
1262 
1263     private String calcInfoName(ServiceMethod method) {
1264         String objectName = this.calcObjectName(method);
1265         String infoName = objectName;
1266         if (!this.isRice()) {
1267             infoName = infoName + "Info";
1268         }
1269         return infoName;
1270     }
1271 
1272     private String initUpper(String str) {
1273         return str.substring(0, 1).toUpperCase() + str.substring(1);
1274     }
1275 
1276     private ServiceMethodParameter findIdListParameter(ServiceMethod method) {
1277         String idFieldName = calcObjectName(method) + "Ids";
1278         if (this.isRice()) {
1279             idFieldName = "ids";
1280         }
1281         for (ServiceMethodParameter parameter : method.getParameters()) {
1282             if (parameter.getType().equals("StringList")) {
1283                 if (parameter.getName().equals(idFieldName)) {
1284                     return parameter;
1285                 }
1286             }
1287         }
1288         // can't find name exactly 
1289         for (ServiceMethodParameter parameter : method.getParameters()) {
1290             if (parameter.getType().equals("StringList")) {
1291                 if (parameter.getName().endsWith("Ids")) {
1292                     return parameter;
1293                 }
1294             }
1295         }
1296         // can't find name exactly try key 
1297         for (ServiceMethodParameter parameter : method.getParameters()) {
1298             if (parameter.getType().equals("StringList")) {
1299                 if (parameter.getName().endsWith("Keys")) {
1300                     return parameter;
1301                 }
1302             }
1303         }
1304         return null;
1305     }
1306 
1307     private String stripList(String str) {
1308         return GetterSetterNameCalculator.stripList(str);
1309     }
1310 
1311     private String calcExceptionClassName(ServiceMethodError error) {
1312         if (error.getClassName() == null) {
1313             return ServiceExceptionWriter.calcClassName(error.getType());
1314         }
1315         return error.getClassName();
1316     }
1317 
1318     private String calcExceptionPackageName(ServiceMethodError error) {
1319         if (error.getClassName() == null) {
1320             return ServiceExceptionWriter.calcPackage(rootPackage);
1321         }
1322         return error.getPackageName();
1323     }
1324 
1325     private String calcType(String type, String realType) {
1326         XmlType t = finder.findXmlType(this.stripList(type));
1327         String retType = MessageStructureTypeCalculator.calculate(this, model, type, realType,
1328                 t.getJavaPackage());
1329         if (this.isRice()) {
1330             if (retType.equals("Boolean")) {
1331                 retType = "boolean";
1332             }
1333             if (retType.equals("Void")) {
1334                 retType = "void";
1335             }
1336         }
1337         return retType;
1338     }
1339 }