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.Query;
33  import org.kuali.student.contract.model.MessageStructure;
34  
35  /**
36   *
37   * @author nwright
38   */
39  public class JpaDaoWriter extends JavaClassWriter {
40  
41      private static final Logger log = LoggerFactory.getLogger(JpaDaoWriter.class);
42  
43      //////////////////////////////
44      // Constants
45      //////////////////////////////
46      /**
47       * The standard type of methods used in our Service contract.
48       */
49      protected static enum MethodType {
50  
51          VALIDATE,
52          CREATE,
53          CREATE_BULK,
54          ADD,
55          UPDATE,
56          UPDATE_OTHER,
57          DELETE,
58          REMOVE,
59          DELETE_OTHER,
60          GET_CREATE,
61          GET_BY_ID,
62          GET_BY_IDS,
63          RICE_GET_BY_NAMESPACE_AND_NAME,
64          GET_IDS_BY_TYPE,
65          GET_IDS_BY_OTHER,
66          GET_INFOS_BY_OTHER,
67          GET_TYPE,
68          GET_TYPES,
69          SEARCH_FOR_IDS,
70          SEARCH_FOR_INFOS,
71          UNKNOWN
72      };
73  
74      //////////////////////////////
75      // Data Variables
76      //////////////////////////////
77      protected ServiceContractModel model;
78      protected ModelFinder finder;
79      private String directory;
80      private XmlType xmlType;
81      /**
82       * The package name is stored in the service object itself (the package spec
83       * kept moving around so I assumed the actual service name was unique but
84       * ran into a problem when we included rice because they have a StateService
85       * meaning US states and we have a StateService meaning the state of the
86       * object so I added logic to detect rice and prepend that "RICE." to it
87       */
88      private String rootPackage;
89  
90      /**
91       * Name of the service being operated on. If it is a RICE service it is
92       * prefixed with RICE. [11:32:18 AM] Norman Wright: short name... I think it
93       * gets it by taking the java class SimpleName and stripping off the word
94       * "Service" and I think making it lower case. [11:32:24 AM] Norman Wright:
95       * so OrganizationService becomes organization
96       */
97      protected String servKey;
98      /**
99       * A flag that holds if the service is an R1 service.
100      */
101     private boolean isR1;
102     private List<ServiceMethod> methods;
103 
104     //////////////////////////
105     // Constructor
106     //////////////////////////
107     public JpaDaoWriter(ServiceContractModel model,
108             String directory,
109             String rootPackage,
110             String servKey,
111             List<ServiceMethod> methods,
112             XmlType xmlType,
113             boolean isR1) {
114         super(directory, calcPackage(servKey, rootPackage), calcClassName(servKey, xmlType));
115         this.model = model;
116         this.finder = new ModelFinder(model);
117         this.directory = directory;
118         this.rootPackage = rootPackage;
119         this.servKey = servKey;
120         this.methods = methods;
121         this.xmlType = xmlType;
122         this.isR1 = isR1;
123     }
124 
125     public JpaDaoWriter(ServiceContractModel model,
126             String directory,
127             String rootPackage,
128             String servKey,
129             List<ServiceMethod> methods,
130             XmlType xmlType,
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.xmlType = xmlType;
142         this.isR1 = isR1;
143     }
144 
145     /////////////////////////
146     // Functional Methods
147     /////////////////////////
148     /**
149      * Returns the jpa implementation package name.
150      *
151      * @param servKey
152      * @param rootPackage
153      * @return
154      */
155     public static String calcPackage(String servKey, String rootPackage) {
156         String pack = rootPackage + ".";
157 //        String pack = rootPackage + "." + servKey.toLowerCase() + ".";
158 //  StringBuffer buf = new StringBuffer (service.getVersion ().length ());
159 //  for (int i = 0; i < service.getVersion ().length (); i ++)
160 //  {
161 //   char c = service.getVersion ().charAt (i);
162 //   c = Character.toLowerCase (c);
163 //   if (Character.isLetter (c))
164 //   {
165 //    buf.append (c);
166 //    continue;
167 //   }
168 //   if (Character.isDigit (c))
169 //   {
170 //    buf.append (c);
171 //   }
172 //  }
173 //  pack = pack + buf.toString ();
174         pack = pack + "service.impl.jpa." + servKey.toLowerCase();
175         return pack;
176     }
177 
178     /**
179      * Checks if this is a RICE service.
180      *
181      * @return true if this is a RICE service.
182      */
183     private boolean isRice() {
184         if (this.servKey.startsWith("RICE.")) {
185             return true;
186         }
187         return false;
188     }
189 
190     protected static String fixServKey(String servKey) {
191         if (servKey.startsWith("RICE.")) {
192             return servKey.substring("RICE.".length());
193         }
194         return servKey;
195     }
196 
197     /**
198      * Given the service key (name), returns a calculated class name for the jpa
199      * impl.
200      */
201     public static String calcClassName(String servKey, XmlType xmlType) {
202         String name = calcInfcName(xmlType) + "Dao";
203         return name;
204     }
205 
206     private String calcInfcName() {
207         String name = calcInfcName(xmlType);
208         String pkg = xmlType.getJavaPackage();
209         if (pkg.endsWith(".dto")) {
210             pkg = pkg.substring(0, pkg.length() - ".dto".length()) + ".infc";
211         }
212         importsAdd(pkg + "." + name);
213         return name;
214     }
215 
216     private String calcInfoName() {
217         String name = initUpper(xmlType.getName());
218         String pkg = xmlType.getJavaPackage();
219         importsAdd(pkg + "." + name);
220         return name;
221     }
222 
223     public static String calcInfcName(XmlType xmlType) {
224         String name = xmlType.getName();
225         if (name.endsWith("Info")) {
226             name = name.substring(0, name.length() - "Info".length());
227         }
228         name = GetterSetterNameCalculator.calcInitUpper(name);
229         return name;
230     }
231 
232     protected MethodType calcMethodType(ServiceMethod method) {
233 //        if (method.getName().equals("getInstructionalDaysForTerm")) {
234 //            System.out.println("debug here");
235 //        }
236         if (this.isRice()) {
237             if (method.getName().contains("ByNamespaceCodeAndName")) {
238                 return MethodType.RICE_GET_BY_NAMESPACE_AND_NAME;
239             }
240             if (method.getName().contains("ByNameAndNamespace")) {
241                 return MethodType.RICE_GET_BY_NAMESPACE_AND_NAME;
242             }
243             if (method.getName().startsWith("get")) {
244                 if (method.getParameters().size() == 1) {
245                     if (!method.getReturnValue().getType().endsWith("List")) {
246                         if (method.getParameters().get(0).getName().equals("id")) {
247                             return MethodType.GET_BY_ID;
248                         }
249 
250                     } else {
251                         if (method.getParameters().get(0).getName().equals("ids")) {
252                             return MethodType.GET_BY_IDS;
253                         }
254                     }
255                 }
256             }
257         }
258         if (method.getName().startsWith("validate")) {
259             return MethodType.VALIDATE;
260         }
261         if (method.getName().startsWith("create")) {
262             if (method.getName().startsWith("createBatch")) {
263                 return MethodType.CREATE_BULK;
264             }
265             if (method.getName().startsWith("createSocRolloverResultItems")) {
266                 return MethodType.CREATE_BULK;
267             }
268             if (method.getName().contains("FromExisting")) {
269                 return MethodType.CREATE_BULK;
270             }
271             ServiceMethodParameter infoParam = this.findInfoParameter(method);
272             if (infoParam == null) {
273                 return MethodType.CREATE_BULK;
274             }
275             if (method.getReturnValue().getType().endsWith("List")) {
276                 return MethodType.CREATE_BULK;
277             }
278             return MethodType.CREATE;
279         }
280         if (method.getName().startsWith("add")) {
281             return MethodType.ADD;
282         }
283         if (method.getName().startsWith("update")) {
284             if (this.findInfoParameter(method) != null) {
285                 return MethodType.UPDATE;
286             }
287             return MethodType.UPDATE_OTHER;
288         }
289         if (method.getName().startsWith("delete")) {
290             if (method.getName().contains("By")) {
291                 if (!method.getName().startsWith("deleteBy")) {
292                     return MethodType.DELETE_OTHER;
293                 }
294             }
295             if (method.getName().contains("For")) {
296                 if (!method.getName().startsWith("deleteFor")) {
297                     return MethodType.DELETE_OTHER;
298                 }
299             }
300             return MethodType.DELETE;
301         }
302         if (method.getName().startsWith("remove")) {
303             return MethodType.REMOVE;
304         }
305 
306         if (method.getName().startsWith("getCreate")) {
307             return MethodType.GET_CREATE;
308         }
309 
310         if (method.getName().startsWith("get")) {
311             if (method.getName().endsWith("ByIds")) {
312                 return MethodType.GET_BY_IDS;
313             }
314             if (method.getName().endsWith("ByKeys")) {
315                 return MethodType.GET_BY_IDS;
316             }
317             if (method.getName().endsWith("ByType")) {
318                 return MethodType.GET_IDS_BY_TYPE;
319             }
320             if (method.getReturnValue().getType().endsWith("TypeInfo")) {
321                 return MethodType.GET_TYPE;
322             }
323             if (method.getReturnValue().getType().endsWith("TypeInfoList")) {
324                 return MethodType.GET_TYPES;
325             }
326             if (method.getName().endsWith("ByType")) {
327                 return MethodType.GET_IDS_BY_TYPE;
328             }
329             String splitName = splitCamelCase(method.getName());
330             if (splitName.contains("_By_")) {
331                 if (method.getReturnValue().getType().equals("StringList")) {
332                     return MethodType.GET_IDS_BY_OTHER;
333                 }
334                 if (method.getReturnValue().getType().endsWith("InfoList")) {
335                     return MethodType.GET_INFOS_BY_OTHER;
336                 }
337                 return MethodType.UNKNOWN;
338             }
339             if (splitName.contains("_For_")) {
340                 if (method.getReturnValue().getType().equals("StringList")) {
341                     return MethodType.GET_IDS_BY_OTHER;
342                 }
343                 if (method.getReturnValue().getType().endsWith("InfoList")) {
344                     return MethodType.GET_INFOS_BY_OTHER;
345                 }
346                 return MethodType.UNKNOWN;
347             }
348             if (method.getParameters().size() >= 1 && method.getParameters().size() <= 2) {
349                 if (!method.getReturnValue().getType().endsWith("List")) {
350                     if (method.getParameters().get(0).getName().endsWith("Id")) {
351                         return MethodType.GET_BY_ID;
352                     }
353                     if (method.getParameters().get(0).getName().endsWith("Key")) {
354                         return MethodType.GET_BY_ID;
355                     }
356                 }
357             }
358         }
359         if (method.getName().startsWith("searchFor")) {
360             if (method.getName().endsWith("Ids")) {
361                 return MethodType.SEARCH_FOR_IDS;
362             }
363             if (method.getName().endsWith("Keys")) {
364                 return MethodType.SEARCH_FOR_IDS;
365             }
366             return MethodType.SEARCH_FOR_INFOS;
367         }
368 
369         return MethodType.UNKNOWN;
370     }
371 
372     private String calcTableName(XmlType xmlType) {
373         String tableName = xmlType.getTableName();
374         if (tableName != null) {
375             return tableName;
376         }
377         return calcTableName(xmlType.getName());
378     }
379 
380     private String calcTableName(String name) {
381         if (name.endsWith("Info")) {
382             name = name.substring(0, name.length() - "Info".length());
383         }
384         String tableName = "KSEN_" + splitCamelCase(name).toUpperCase();
385         return tableName;
386     }
387 
388     // got this from
389     // http://stackoverflow.com/questions/2559759/how-do-i-convert-camelcase-into-human-readable-names-in-java
390     private static String splitCamelCase(String s) {
391         if (s == null) {
392             return null;
393         }
394         return s.replaceAll(String.format("%s|%s|%s",
395                 "(?<=[A-Z])(?=[A-Z][a-z])", "(?<=[^A-Z])(?=[A-Z])",
396                 "(?<=[A-Za-z])(?=[^A-Za-z])"), "_");
397     }
398 
399     private String calcColumnName(MessageStructure ms) {
400         if (ms.getShortName().equalsIgnoreCase("TypeKey")) {
401             String prefix = calcTableName(xmlType);
402             if (prefix.startsWith("KSEN_")) {
403                 prefix = prefix.substring("KSEN_".length());
404             }
405             return prefix + "_TYPE";
406         }
407         if (ms.getShortName().equalsIgnoreCase("StateKey")) {
408             String prefix = calcTableName(xmlType);
409             if (prefix.startsWith("KSEN_")) {
410                 prefix = prefix.substring("KSEN_".length());
411             }
412             return prefix + "_STATE";
413         }
414         String name = splitCamelCase(ms.getShortName());
415         // TODO: apply known abbreviations see https://wiki.kuali.org/display/STUDENT/Database+Abbreviations+for+R2
416         return name.toUpperCase();
417     }
418 
419     private boolean isNullable(MessageStructure ms) {
420         if (ms.getRequired() == null) {
421             return true;
422         }
423         if (ms.getRequired().equalsIgnoreCase("Required")) {
424             return false;
425         }
426         // figure out what to do if it is qualified like
427         // "required on update"
428         return true;
429     }
430 
431     private String keyOrId() {
432 
433         if (finder.findMessageStructure(xmlType.getName(), "id") != null) {
434             return "Id";
435         }
436         if (finder.findMessageStructure(xmlType.getName(), "key") != null) {
437             return "Key";
438         }
439         return "Id";
440     }
441 
442     private boolean hasAttributes() {
443         for (MessageStructure ms : finder.findMessageStructures(xmlType.getName())) {
444             if (ms.getShortName().equals("attributes")) {
445                 return true;
446             }
447         }
448         return false;
449     }
450 
451     private boolean isMethodForThisType(XmlType xmlType, ServiceMethod method) {
452         String objectName = calcObjectName(method);
453         if (objectName == null) {
454             return false;
455         }
456         if (xmlType.getName().equalsIgnoreCase(objectName + "Info")) {
457             return true;
458         }
459         return false;
460     }
461 
462     /**
463      * Write out the entire file
464      */
465     public void write() {
466         String className = calcClassName(servKey, xmlType);
467         String entityName = JpaEntityWriter.calcClassName(servKey, xmlType);
468         indentPrint("public class " + className);
469         println(" extends GenericEntityDao<" + entityName + "> {");
470         incrementIndent();
471         importsAdd("org.kuali.student.r2.common.dao.GenericEntityDao");
472         for (ServiceMethod method : methods) {
473             if (!isMethodForThisType(xmlType, method)) {
474                 continue;
475             }
476             MethodType methodType = calcMethodType(method);
477             String returnClass = null;
478             switch (methodType) {
479                 case GET_IDS_BY_TYPE:
480                     importsAdd(List.class.getName());
481                     println("");
482                     indentPrintln("public List<String> getIdsByType(String type) {");
483                     incrementIndent();
484                     importsAdd(Query.class.getName());
485                     indentPrintln("Query query = em.createNamedQuery(\"" + entityName + ".getIdsByType\");");
486                     indentPrintln("query.setParameter(\"type\", type);");
487                     indentPrintln("return query.getResultList();");
488                     decrementIndent();
489                     indentPrintln("}");
490                     break;
491                 case GET_IDS_BY_OTHER:
492                 case GET_INFOS_BY_OTHER:
493                     importsAdd(List.class.getName());
494                     importsAdd(Query.class.getName());
495                     if (methodType.equals(MethodType.GET_IDS_BY_OTHER)) {
496                         returnClass = "String";
497                     } else {
498                         returnClass = entityName;
499                     }
500                     println("");
501                     String namedQuery = calcNamedQuery(method);
502                     indentPrint("public List<" + returnClass + "> " + namedQuery + "(");
503                     String comma = "";
504                     for (ServiceMethodParameter param : method.getParameters()) {
505                         if (param.getType().equals("ContextInfo")) {
506                             continue;
507                         }
508                         print(comma);
509                         comma = ", ";
510                         String paramName = initLower(param.getName());
511                         String javaClass = this.calcType(param.getType(), this.stripList(param.getType()));
512                         print(javaClass + " " + paramName);
513                     }
514                     println(") {");
515                     incrementIndent();
516                     indentPrintln("Query query = em.createNamedQuery(\"" + entityName + "." + namedQuery + "\");");
517                     for (ServiceMethodParameter param : method.getParameters()) {
518                         if (param.getType().equals("ContextInfo")) {
519                             continue;
520                         }
521                         String paramName = initLower(param.getName());
522                         indentPrintln("query.setParameter(\"" + paramName + "\", " + paramName + ");");
523                     }
524                     indentPrintln("return query.getResultList();");
525                     decrementIndent();
526                     indentPrintln("}");
527                     break;
528             }
529         }
530 
531         println("");
532         closeBrace();
533 
534         this.writeJavaClassAndImportsOutToFile();
535         this.getOut().close();
536     }
537 
538     private String getInvalidParameterException() {
539         if (this.isRice()) {
540             return "RiceIllegalArgumentException";
541         }
542         return "InvalidParameterException";
543     }
544 
545     private String getOperationFailedException() {
546         if (this.isRice()) {
547             return "RiceIllegalArgumentException";
548         }
549         return "OperationFailedException";
550     }
551 
552     private String getDoesNotExistException() {
553         if (this.isRice()) {
554             return "RiceIllegalArgumentException";
555         }
556         return "DoesNotExistException";
557     }
558 
559     private String getVersionMismatchException() {
560         if (this.isRice()) {
561             return "RiceIllegalStateException";
562         }
563         return "VersionMismatchException";
564     }
565 
566     private void writeThrowsNotImplemented(ServiceMethod method) {
567         indentPrintln("throw new " + this.getOperationFailedException() + " (\"" + method.getName() + " has not been implemented\");");
568     }
569 
570     protected String initLower(String str) {
571         return str.substring(0, 1).toLowerCase() + str.substring(1);
572     }
573 
574     private String calcCriteriaLookupServiceVariableName(ServiceMethod method) {
575         String objectName = calcObjectName(method);
576         String variableName = initLower(objectName) + "CriteriaLookupService";
577         return variableName;
578     }
579 
580     private ServiceMethodParameter findIdParameter(ServiceMethod method) {
581         String idFieldName = calcObjectName(method) + "Id";
582         for (ServiceMethodParameter parameter : method.getParameters()) {
583             if (parameter.getType().equals("String")) {
584                 if (parameter.getName().equals(idFieldName)) {
585                     return parameter;
586                 }
587             }
588         }
589 
590         // if only one parameter and it is a string then grab that
591         if (method.getParameters().size() == 1) {
592             for (ServiceMethodParameter parameter : method.getParameters()) {
593                 if (parameter.getType().equals("String")) {
594                     return parameter;
595                 }
596             }
597         }
598         // can't find name exactly 
599         for (ServiceMethodParameter parameter : method.getParameters()) {
600             if (parameter.getType().equals("String")) {
601                 if (parameter.getName().endsWith("Id")) {
602                     return parameter;
603                 }
604             }
605         }
606         // can't find name exactly try key 
607         for (ServiceMethodParameter parameter : method.getParameters()) {
608             if (parameter.getType().equals("String")) {
609                 if (!parameter.getName().endsWith("TypeKey")) {
610                     if (parameter.getName().endsWith("Key")) {
611                         return parameter;
612                     }
613                 }
614             }
615         }
616         log.warn("Could not find the Id paramter for {}.{} so returning the first one", method.getService(), method.getName());
617         return method.getParameters().get(0);
618     }
619 
620     private ServiceMethodParameter findContextParameter(ServiceMethod method) {
621         for (ServiceMethodParameter parameter : method.getParameters()) {
622             if (parameter.getType().equals("ContextInfo")) {
623                 return parameter;
624             }
625         }
626         return null;
627     }
628 
629     private ServiceMethodParameter findInfoParameter(ServiceMethod method) {
630         String objectName = calcObjectName(method);
631         if (!this.isRice()) {
632             objectName = objectName + "Info";
633         }
634         for (ServiceMethodParameter parameter : method.getParameters()) {
635             if (parameter.getType().equals(objectName)) {
636                 return parameter;
637             }
638         }
639         if (method.getParameters().size() >= 1) {
640             return method.getParameters().get(0);
641         }
642         return null;
643     }
644 
645     private ServiceMethodParameter findTypeParameter(ServiceMethod method) {
646         for (ServiceMethodParameter parameter : method.getParameters()) {
647             if (parameter.getType().equals("String")) {
648                 if (parameter.getName().endsWith("TypeKey")) {
649                     return parameter;
650                 }
651                 if (parameter.getName().endsWith("Type")) {
652                     return parameter;
653                 }
654             }
655         }
656         return null;
657     }
658 
659     private String calcDaoVariableName(ServiceMethod method) {
660         String daoVariableName = this.calcObjectName(method);
661         daoVariableName = this.initLower(daoVariableName) + "Dao";
662         return daoVariableName;
663     }
664 
665     private String calcEntityClassName(ServiceMethod method) {
666         String objectName = this.calcObjectName(method);
667         objectName = objectName + "Entity";
668         return objectName;
669     }
670 
671     protected String calcObjectName(ServiceMethod method) {
672         if (method.getName().startsWith("create")) {
673             return method.getName().substring("create".length());
674         }
675         if (method.getName().startsWith("update")) {
676             return method.getName().substring("update".length());
677         }
678         if (method.getName().startsWith("validate")) {
679             return method.getName().substring("validate".length());
680         }
681         if (method.getName().startsWith("delete")) {
682             return method.getName().substring("delete".length());
683         }
684         if (method.getName().startsWith("get")) {
685             if (method.getReturnValue().getType().equals("StringList")) {
686                 if (method.getName().contains("IdsBy")) {
687                     return method.getName().substring("get".length(),
688                             method.getName().indexOf("IdsBy"));
689                 }
690                 if (method.getName().contains("KeysBy")) {
691                     return method.getName().substring("get".length(),
692                             method.getName().indexOf("KeysBy"));
693                 }
694                 if (method.getName().contains("IdsFor")) {
695                     return method.getName().substring("get".length(),
696                             method.getName().indexOf("IdsFor"));
697                 }
698                 if (method.getName().contains("With")) {
699                     return method.getName().substring("get".length(),
700                             method.getName().indexOf("With"));
701                 }
702                 if (method.getName().contains("By")) {
703                     return method.getName().substring("get".length(),
704                             method.getName().indexOf("By"));
705                 }
706                 return method.getName().substring("get".length());
707             }
708             String name = method.getReturnValue().getType();
709             if (name.endsWith("List")) {
710                 name = name.substring(0, name.length() - "List".length());
711             }
712             if (name.endsWith("Info")) {
713                 name = name.substring(0, name.length() - "Info".length());
714             }
715             return name;
716         }
717 
718         if (method.getName().startsWith("searchFor")) {
719             if (method.getReturnValue().getType().equals("StringList")) {
720                 if (method.getName().endsWith("Ids")) {
721                     return method.getName().substring("searchFor".length(),
722                             method.getName().indexOf("Ids"));
723                 }
724                 if (method.getName().endsWith("Keys")) {
725                     return method.getName().substring("get".length(),
726                             method.getName().indexOf("Keys"));
727                 }
728                 return method.getName().substring("searchFor".length());
729             }
730             String name = method.getReturnValue().getType();
731             if (name.endsWith("List")) {
732                 name = name.substring(0, name.length() - "List".length());
733             }
734             if (name.endsWith("Info")) {
735                 name = name.substring(0, name.length() - "Info".length());
736             }
737             return name;
738         }
739         if (method.getName().startsWith("add")) {
740             return method.getName().substring("add".length());
741         }
742         if (method.getName().startsWith("remove")) {
743             return method.getName().substring("remove".length());
744         }
745         String returnType = this.stripList(method.getReturnValue().getType());
746         XmlType type = this.finder.findXmlType(returnType);
747         if (type.getPrimitive().equals(XmlType.COMPLEX)) {
748             return returnType;
749         }
750         return null;
751     }
752 
753     private String calcNamedQuery(ServiceMethod method) {
754         String objectName = calcObjectName(method);
755         String name = method.getName();
756         if (name.startsWith("get")) {
757             name = name.substring("get".length());
758         }
759         if (name.startsWith(objectName)) {
760             name = name.substring(objectName.length());
761         }
762 //        if (name.startsWith("Ids")) {
763 //            name = name.substring("Ids".length());
764 //        }
765 //        if (name.isEmpty()) {
766 //            throw new RuntimeException (method.getName());
767 //        }
768         // remove plural
769         if (!method.getReturnValue().getType().equals("StringList")) {
770             if (name.startsWith("s")) {
771                 name = name.substring("s".length());
772             }
773         }
774         // add back the get
775         name = "get" + name;
776         return name;
777     }
778 
779     private ServiceMethodParameter findCriteriaParam(ServiceMethod method) {
780         for (ServiceMethodParameter param : method.getParameters()) {
781             if (param.getType().equals("QueryByCriteria")) {
782                 return param;
783             }
784         }
785         return null;
786     }
787 
788     private ServiceMethodParameter getTypeParameter(ServiceMethod method) {
789         ServiceMethodParameter fallbackParam = null;
790         for (ServiceMethodParameter parameter : method.getParameters()) {
791             if (parameter.getName().endsWith("TypeKey")) {
792                 return parameter;
793             }
794             if (parameter.getType().equals("String")) {
795                 if (parameter.getName().toLowerCase().contains("type")) {
796                     fallbackParam = parameter;
797                 }
798             }
799         }
800         return fallbackParam;
801     }
802 
803     private String calcInfoName(ServiceMethod method) {
804         String objectName = this.calcObjectName(method);
805         String infoName = objectName;
806         if (!this.isRice()) {
807             infoName = infoName + "Info";
808         }
809         return infoName;
810     }
811 
812     private String initUpper(String str) {
813         return str.substring(0, 1).toUpperCase() + str.substring(1);
814     }
815 
816     private ServiceMethodParameter findIdListParameter(ServiceMethod method) {
817         String idFieldName = calcObjectName(method) + "Ids";
818         if (this.isRice()) {
819             idFieldName = "ids";
820         }
821         for (ServiceMethodParameter parameter : method.getParameters()) {
822             if (parameter.getType().equals("StringList")) {
823                 if (parameter.getName().equals(idFieldName)) {
824                     return parameter;
825                 }
826             }
827         }
828         // can't find name exactly 
829         for (ServiceMethodParameter parameter : method.getParameters()) {
830             if (parameter.getType().equals("StringList")) {
831                 if (parameter.getName().endsWith("Ids")) {
832                     return parameter;
833                 }
834             }
835         }
836         // can't find name exactly try key 
837         for (ServiceMethodParameter parameter : method.getParameters()) {
838             if (parameter.getType().equals("StringList")) {
839                 if (parameter.getName().endsWith("Keys")) {
840                     return parameter;
841                 }
842             }
843         }
844         return null;
845     }
846 
847     private String stripList(String str) {
848         return GetterSetterNameCalculator.stripList(str);
849     }
850 
851     private String calcExceptionClassName(ServiceMethodError error) {
852         if (error.getClassName() == null) {
853             return ServiceExceptionWriter.calcClassName(error.getType());
854         }
855         return error.getClassName();
856     }
857 
858     private String calcExceptionPackageName(ServiceMethodError error) {
859         if (error.getClassName() == null) {
860             return ServiceExceptionWriter.calcPackage(rootPackage);
861         }
862         return error.getPackageName();
863     }
864 
865     private String calcType(String type, String realType) {
866         XmlType t = finder.findXmlType(this.stripList(type));
867         String retType = MessageStructureTypeCalculator.calculate(this, model, type, realType,
868                 t.getJavaPackage());
869         if (this.isRice()) {
870             if (retType.equals("Boolean")) {
871                 retType = "boolean";
872             }
873             if (retType.equals("Void")) {
874                 retType = "void";
875             }
876         }
877         return retType;
878     }
879 }