001/**
002 * Copyright 2004-2014 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.student.jpa.mojo;
017
018import org.kuali.student.contract.model.Service;
019import org.kuali.student.contract.model.ServiceContractModel;
020import org.kuali.student.contract.model.ServiceMethod;
021import org.kuali.student.contract.model.ServiceMethodError;
022import org.kuali.student.contract.model.ServiceMethodParameter;
023import org.kuali.student.contract.model.XmlType;
024import org.kuali.student.contract.model.util.ModelFinder;
025import org.kuali.student.contract.writer.JavaClassWriter;
026import org.kuali.student.contract.writer.service.GetterSetterNameCalculator;
027import org.kuali.student.contract.writer.service.MessageStructureTypeCalculator;
028import org.kuali.student.contract.writer.service.ServiceExceptionWriter;
029import org.slf4j.Logger;
030import org.slf4j.LoggerFactory;
031
032import java.util.*;
033import javax.persistence.Entity;
034import javax.persistence.NamedQueries;
035import javax.persistence.NamedQuery;
036import javax.persistence.Table;
037import org.kuali.rice.core.api.criteria.CriteriaLookupService;
038import org.kuali.student.contract.model.MessageStructure;
039
040/**
041 *
042 * @author nwright
043 */
044public class JpaAttributeEntityWriter extends JavaClassWriter {
045
046    private static final Logger log = LoggerFactory.getLogger(JpaAttributeEntityWriter.class);
047
048    //////////////////////////////
049    // Constants
050    //////////////////////////////
051    /**
052     * The standard type of methods used in our Service contract.
053     */
054    protected static enum MethodType {
055
056        VALIDATE,
057        CREATE,
058        CREATE_BULK,
059        ADD,
060        UPDATE,
061        UPDATE_OTHER,
062        DELETE,
063        REMOVE,
064        DELETE_OTHER,
065        GET_CREATE,
066        GET_BY_ID,
067        GET_BY_IDS,
068        RICE_GET_BY_NAMESPACE_AND_NAME,
069        GET_IDS_BY_TYPE,
070        GET_IDS_BY_OTHER,
071        GET_INFOS_BY_OTHER,
072        GET_TYPE,
073        GET_TYPES,
074        SEARCH_FOR_IDS,
075        SEARCH_FOR_INFOS,
076        UNKNOWN
077    };
078
079    //////////////////////////////
080    // Data Variables
081    //////////////////////////////
082    protected ServiceContractModel model;
083    protected ModelFinder finder;
084    private String directory;
085    private XmlType xmlType;
086    /**
087     * The package name is stored in the service object itself (the package spec
088     * kept moving around so I assumed the actual service name was unique but
089     * ran into a problem when we included rice because they have a StateService
090     * meaning US states and we have a StateService meaning the state of the
091     * object so I added logic to detect rice and prepend that "RICE." to it
092     */
093    private String rootPackage;
094
095    /**
096     * Name of the service being operated on. If it is a RICE service it is
097     * prefixed with RICE. [11:32:18 AM] Norman Wright: short name... I think it
098     * gets it by taking the java class SimpleName and stripping off the word
099     * "Service" and I think making it lower case. [11:32:24 AM] Norman Wright:
100     * so OrganizationService becomes organization
101     */
102    protected String servKey;
103    /**
104     * A flag that holds if the service is an R1 service.
105     */
106    private boolean isR1;
107    private List<ServiceMethod> methods;
108    private String mainEntityName;
109
110    //////////////////////////
111    // Constructor
112    //////////////////////////
113    public JpaAttributeEntityWriter(ServiceContractModel model,
114            String directory,
115            String rootPackage,
116            String servKey,
117            List<ServiceMethod> methods,
118            XmlType xmlType,
119            boolean isR1,
120            String mainEntityName) {
121        super(directory, calcPackage(servKey, rootPackage), calcClassName(servKey, xmlType));
122        this.model = model;
123        this.finder = new ModelFinder(model);
124        this.directory = directory;
125        this.rootPackage = rootPackage;
126        this.servKey = servKey;
127        this.methods = methods;
128        this.xmlType = xmlType;
129        this.isR1 = isR1;
130        this.mainEntityName = mainEntityName;
131        
132    }
133
134    public JpaAttributeEntityWriter(ServiceContractModel model,
135            String directory,
136            String rootPackage,
137            String servKey,
138            List<ServiceMethod> methods,
139            XmlType xmlType,
140            boolean isR1,
141            String packageName,
142            String className) {
143        super(directory, packageName, className);
144        this.model = model;
145        this.finder = new ModelFinder(model);
146        this.directory = directory;
147        this.rootPackage = rootPackage;
148        this.servKey = servKey;
149        this.methods = methods;
150        this.xmlType = xmlType;
151        this.isR1 = isR1;
152    }
153
154    /////////////////////////
155    // Functional Methods
156    /////////////////////////
157    /**
158     * Returns the jpa implementation package name.
159     *
160     * @param servKey
161     * @param rootPackage
162     * @return
163     */
164    public static String calcPackage(String servKey, String rootPackage) {
165        String pack = rootPackage + ".";
166//        String pack = rootPackage + "." + servKey.toLowerCase() + ".";
167//  StringBuffer buf = new StringBuffer (service.getVersion ().length ());
168//  for (int i = 0; i < service.getVersion ().length (); i ++)
169//  {
170//   char c = service.getVersion ().charAt (i);
171//   c = Character.toLowerCase (c);
172//   if (Character.isLetter (c))
173//   {
174//    buf.append (c);
175//    continue;
176//   }
177//   if (Character.isDigit (c))
178//   {
179//    buf.append (c);
180//   }
181//  }
182//  pack = pack + buf.toString ();
183        pack = pack + "service.impl.jpa." + servKey.toLowerCase();
184        return pack;
185    }
186
187    /**
188     * Checks if this is a RICE service.
189     *
190     * @return true if this is a RICE service.
191     */
192    private boolean isRice() {
193        if (this.servKey.startsWith("RICE.")) {
194            return true;
195        }
196        return false;
197    }
198
199    protected static String fixServKey(String servKey) {
200        if (servKey.startsWith("RICE.")) {
201            return servKey.substring("RICE.".length());
202        }
203        return servKey;
204    }
205
206    /**
207     * Given the service key (name), returns a calculated class name for the jpa
208     * impl.
209     */
210    public static String calcClassName(String servKey, XmlType xmlType) {
211        String name = GetterSetterNameCalculator.calcInitUpper(xmlType.getName());
212        if (name.endsWith ("Info")) {
213            name = name.substring(0, name.length() - "Info".length());
214        }
215        name = name + "AttributeEntity";
216        return name;
217    }
218
219    /**
220     * Analyses the method and returns a MethodType enum that describes what
221     * type of method this is.
222     */
223    protected MethodType calcMethodType(ServiceMethod method) {
224        if (this.isRice()) {
225            if (method.getName().contains("ByNamespaceCodeAndName")) {
226                return MethodType.RICE_GET_BY_NAMESPACE_AND_NAME;
227            }
228            if (method.getName().contains("ByNameAndNamespace")) {
229                return MethodType.RICE_GET_BY_NAMESPACE_AND_NAME;
230            }
231            if (method.getName().startsWith("get")) {
232                if (method.getParameters().size() == 1) {
233                    if (!method.getReturnValue().getType().endsWith("List")) {
234                        if (method.getParameters().get(0).getName().equals("id")) {
235                            return MethodType.GET_BY_ID;
236                        }
237
238                    } else {
239                        if (method.getParameters().get(0).getName().equals("ids")) {
240                            return MethodType.GET_BY_IDS;
241                        }
242                    }
243                }
244            }
245        }
246        if (method.getName().startsWith("validate")) {
247            return MethodType.VALIDATE;
248        }
249        if (method.getName().startsWith("create")) {
250            if (this.findInfoParameter(method) != null) {
251                return MethodType.CREATE;
252            }
253            return MethodType.CREATE_BULK;
254        }
255        if (method.getName().startsWith("add")) {
256            return MethodType.ADD;
257        }
258        if (method.getName().startsWith("update")) {
259            if (this.findInfoParameter(method) != null) {
260                return MethodType.UPDATE;
261            }
262            return MethodType.UPDATE_OTHER;
263        }
264        if (method.getName().startsWith("delete")) {
265            if (method.getName().contains("By")) {
266                if (!method.getName().startsWith("deleteBy")) {
267                    return MethodType.DELETE_OTHER;
268                }
269            }
270            if (method.getName().contains("For")) {
271                if (!method.getName().startsWith("deleteFor")) {
272                    return MethodType.DELETE_OTHER;
273                }
274            }
275            return MethodType.DELETE;
276        }
277        if (method.getName().startsWith("remove")) {
278            return MethodType.REMOVE;
279        }
280
281        if (method.getName().startsWith("getCreate")) {
282            return MethodType.GET_CREATE;
283        }
284
285        if (method.getName().startsWith("get")) {
286            if (method.getName().endsWith("ByIds")) {
287                return MethodType.GET_BY_IDS;
288            }
289            if (method.getName().endsWith("ByKeys")) {
290                return MethodType.GET_BY_IDS;
291            }
292            if (method.getName().endsWith("ByType")) {
293                return MethodType.GET_IDS_BY_TYPE;
294            }
295            if (method.getReturnValue().getType().endsWith("TypeInfo")) {
296                return MethodType.GET_TYPE;
297            }
298            if (method.getReturnValue().getType().endsWith("TypeInfoList")) {
299                return MethodType.GET_TYPES;
300            }
301            if (method.getName().endsWith("ByType")) {
302                return MethodType.GET_IDS_BY_TYPE;
303            }
304            if (method.getParameters().size() >= 1 && method.getParameters().size() <= 2) {
305                if (!method.getReturnValue().getType().endsWith("List")) {
306//                    if (method.getParameters().get(0).getName().endsWith("Id")) {
307                    return MethodType.GET_BY_ID;
308//                    }
309                }
310            }
311            if (method.getName().contains("By")) {
312                if (method.getReturnValue().getType().equals("StringList")) {
313                    return MethodType.GET_IDS_BY_OTHER;
314                }
315                if (method.getReturnValue().getType().endsWith("InfoList")) {
316                    return MethodType.GET_INFOS_BY_OTHER;
317                }
318            }
319        }
320        if (method.getName().startsWith("searchFor")) {
321            if (method.getName().endsWith("Ids")) {
322                return MethodType.SEARCH_FOR_IDS;
323            }
324            if (method.getName().endsWith("Keys")) {
325                return MethodType.SEARCH_FOR_IDS;
326            }
327            return MethodType.SEARCH_FOR_INFOS;
328        }
329
330        return MethodType.UNKNOWN;
331    }
332
333    private String calcTableName(XmlType xmlType) {
334        String tableName = xmlType.getTableName();
335        if (tableName != null) {
336            return tableName;
337        }
338        return calcTableName(xmlType.getName());
339    }
340
341    private String calcTableName(String name) {
342        if (name.endsWith("Info")) {
343            name = name.substring(0, name.length() - "Info".length());
344        }
345        String tableName = "KSEN_" + splitCamelCase(name) + "_ATTR";
346        return tableName.toUpperCase();
347    }
348
349    // got this from
350    // http://stackoverflow.com/questions/2559759/how-do-i-convert-camelcase-into-human-readable-names-in-java
351    private static String splitCamelCase(String s) {
352        if (s == null) {
353            return null;
354        }
355        return s.replaceAll(String.format("%s|%s|%s",
356                "(?<=[A-Z])(?=[A-Z][a-z])", "(?<=[^A-Z])(?=[A-Z])",
357                "(?<=[A-Za-z])(?=[^A-Za-z])"), "_");
358    }
359
360    /**
361     * Write out the entire file
362     */
363    public void write() {
364        String className = calcClassName (servKey, xmlType);
365        indentPrintln("@Entity");
366        importsAdd(Entity.class.getName());
367        String tableName = calcTableName(xmlType);
368        indentPrintln("@Table(name = \"" + tableName + "\")");
369        importsAdd(Table.class.getName());
370        indentPrint("public class " + calcClassName(servKey, xmlType));
371        println (" extends BaseAttributeEntity<" + mainEntityName + "> ");
372        importsAdd ("org.kuali.student.r2.common.entity.BaseAttributeEntity");
373        openBrace();
374        println ("");
375        indentPrintln ("public " + className + "() {");
376        indentPrintln ("    super();");
377        indentPrintln ("}");
378        
379        println ("");
380        importsAdd("org.kuali.student.r2.common.infc.Attribute");
381        indentPrintln ("public " + className + "(Attribute att, " + mainEntityName + " owner) {");
382        indentPrintln ("    super(att, owner);");
383        indentPrintln ("}");
384
385        closeBrace();
386
387        this.writeJavaClassAndImportsOutToFile();
388        this.getOut().close();
389    }
390
391    private String getInvalidParameterException() {
392        if (this.isRice()) {
393            return "RiceIllegalArgumentException";
394        }
395        return "InvalidParameterException";
396    }
397
398    private String getOperationFailedException() {
399        if (this.isRice()) {
400            return "RiceIllegalArgumentException";
401        }
402        return "OperationFailedException";
403    }
404
405    private String getDoesNotExistException() {
406        if (this.isRice()) {
407            return "RiceIllegalArgumentException";
408        }
409        return "DoesNotExistException";
410    }
411
412    private String getVersionMismatchException() {
413        if (this.isRice()) {
414            return "RiceIllegalStateException";
415        }
416        return "VersionMismatchException";
417    }
418
419    private void writeThrowsNotImplemented(ServiceMethod method) {
420        indentPrintln("throw new " + this.getOperationFailedException() + " (\"" + method.getName() + " has not been implemented\");");
421    }
422
423    protected String initLower(String str) {
424        return str.substring(0, 1).toLowerCase() + str.substring(1);
425    }
426
427    private void writeBoilerPlate() {
428        if (this.isRice()) {
429            return;
430        }
431        println("");
432        indentPrintln("private StatusInfo newStatus() {");
433        indentPrintln("     StatusInfo status = new StatusInfo();");
434        indentPrintln("     status.setSuccess(Boolean.TRUE);");
435        indentPrintln("     return status;");
436        indentPrintln("}");
437
438        this.writeBoilerPlateR2();
439    }
440
441    private void writeBoilerPlateR2() {
442        importsAdd("org.kuali.student.r2.common.dto.MetaInfo");
443        println("");
444
445        indentPrintln("private MetaInfo newMeta(ContextInfo context) {");
446        indentPrintln("     MetaInfo meta = new MetaInfo();");
447        indentPrintln("     meta.setCreateId(context.getPrincipalId());");
448        importsAdd(Date.class.getName());
449        indentPrintln("     meta.setCreateTime(new Date());");
450        indentPrintln("     meta.setUpdateId(context.getPrincipalId());");
451        indentPrintln("     meta.setUpdateTime(meta.getCreateTime());");
452        indentPrintln("     meta.setVersionInd(\"0\");");
453        indentPrintln("     return meta;");
454        indentPrintln("}");
455        println("");
456        indentPrintln("private MetaInfo updateMeta(MetaInfo old, ContextInfo context) {");
457        indentPrintln("     MetaInfo meta = new MetaInfo(old);");
458        indentPrintln("     meta.setUpdateId(context.getPrincipalId());");
459        indentPrintln("     meta.setUpdateTime(new Date());");
460        indentPrintln("     meta.setVersionInd((Integer.parseInt(meta.getVersionInd()) + 1) + \"\");");
461        indentPrintln("     return meta;");
462        indentPrintln("}");
463        println("");
464
465    }
466
467    private String calcCriteriaLookupServiceVariableName(ServiceMethod method) {
468        String objectName = calcObjectName(method);
469        String variableName = initLower(objectName) + "CriteriaLookupService";
470        return variableName;
471    }
472
473    private void writeValidate(ServiceMethod method) {
474        indentPrintln("return new ArrayList<ValidationResultInfo> ();");
475        this.importsAdd(ArrayList.class.getName());
476    }
477    private final Set<String> jpaEntitiesWritten = new HashSet<String>();
478
479    private void writeDaoVariable(ServiceMethod method) {
480        String objectName = calcObjectName(method);
481        String className = objectName + "Dao";
482        String variableName = calcDaoVariableName(method);
483        if (jpaEntitiesWritten.add(variableName)) {
484            println("");
485            indentPrintln("private " + className + " " + variableName + ";");
486            println("");
487            indentPrintln("public void set" + className + "(" + className + " " + variableName + ") {");
488            incrementIndent();
489            indentPrintln("this." + variableName + " = " + variableName + ";");
490            decrementIndent();
491            indentPrintln("}");
492            println("");
493            indentPrintln("public " + className + " get" + className + "() {");
494            incrementIndent();
495            indentPrintln("return this." + variableName + ";");
496            decrementIndent();
497            indentPrintln("}");
498
499            variableName = calcCriteriaLookupServiceVariableName(method);
500            importsAdd(CriteriaLookupService.class.getName());
501            className = "CriteriaLookupService";
502            println("");
503            indentPrintln("// Criteria Lookup for this object");
504            indentPrintln("private " + className + " " + variableName + ";");
505            println("");
506            indentPrintln("public void set" + className + "(" + className + " " + variableName + ") {");
507            incrementIndent();
508            indentPrintln("this." + variableName + " = " + variableName + ";");
509            decrementIndent();
510            indentPrintln("}");
511            println("");
512            indentPrintln("public " + className + " get" + className + "() {");
513            incrementIndent();
514            indentPrintln("return this." + variableName + ";");
515            decrementIndent();
516            indentPrintln("}");
517
518        }
519    }
520
521
522    private ServiceMethodParameter findIdParameter(ServiceMethod method) {
523        String idFieldName = calcObjectName(method) + "Id";
524        for (ServiceMethodParameter parameter : method.getParameters()) {
525            if (parameter.getType().equals("String")) {
526                if (parameter.getName().equals(idFieldName)) {
527                    return parameter;
528                }
529            }
530        }
531
532        // if only one parameter and it is a string then grab that
533        if (method.getParameters().size() == 1) {
534            for (ServiceMethodParameter parameter : method.getParameters()) {
535                if (parameter.getType().equals("String")) {
536                    return parameter;
537                }
538            }
539        }
540        // can't find name exactly 
541        for (ServiceMethodParameter parameter : method.getParameters()) {
542            if (parameter.getType().equals("String")) {
543                if (parameter.getName().endsWith("Id")) {
544                    return parameter;
545                }
546            }
547        }
548        // can't find name exactly try key 
549        for (ServiceMethodParameter parameter : method.getParameters()) {
550            if (parameter.getType().equals("String")) {
551                if (!parameter.getName().endsWith("TypeKey")) {
552                    if (parameter.getName().endsWith("Key")) {
553                        return parameter;
554                    }
555                }
556            }
557        }
558        log.warn("Could not find the Id paramter for {}.{} so returning the first one", method.getService(), method.getName());
559        return method.getParameters().get(0);
560    }
561
562    private ServiceMethodParameter findContextParameter(ServiceMethod method) {
563        for (ServiceMethodParameter parameter : method.getParameters()) {
564            if (parameter.getType().equals("ContextInfo")) {
565                return parameter;
566            }
567        }
568        return null;
569    }
570
571    private ServiceMethodParameter findInfoParameter(ServiceMethod method) {
572        String objectName = calcObjectName(method);
573        if (!this.isRice()) {
574            objectName = objectName + "Info";
575        }
576        for (ServiceMethodParameter parameter : method.getParameters()) {
577            if (parameter.getType().equals(objectName)) {
578                return parameter;
579            }
580        }
581        if (method.getParameters().size() >= 1) {
582            return method.getParameters().get(0);
583        }
584        return null;
585    }
586
587    private ServiceMethodParameter findTypeParameter(ServiceMethod method) {
588        for (ServiceMethodParameter parameter : method.getParameters()) {
589            if (parameter.getType().equals("String")) {
590                if (parameter.getName().endsWith("TypeKey")) {
591                    return parameter;
592                }
593                if (parameter.getName().endsWith("Type")) {
594                    return parameter;
595                }
596            }
597        }
598        return null;
599    }
600
601    private String calcDaoVariableName(ServiceMethod method) {
602        String daoVariableName = this.calcObjectName(method);
603        daoVariableName = this.initLower(daoVariableName) + "Dao";
604        return daoVariableName;
605    }
606
607    private String calcEntityClassName(ServiceMethod method) {
608        String objectName = this.calcObjectName(method);
609        objectName = objectName + "Entity";
610        return objectName;
611    }
612
613    protected String calcObjectName(ServiceMethod method) {
614        if (method.getName().startsWith("create")) {
615            return method.getName().substring("create".length());
616        }
617        if (method.getName().startsWith("update")) {
618            return method.getName().substring("update".length());
619        }
620        if (method.getName().startsWith("validate")) {
621            return method.getName().substring("validate".length());
622        }
623        if (method.getName().startsWith("delete")) {
624            return method.getName().substring("delete".length());
625        }
626        if (method.getName().startsWith("get")) {
627            if (method.getReturnValue().getType().equals("StringList")) {
628                if (method.getName().contains("IdsBy")) {
629                    return method.getName().substring("get".length(),
630                            method.getName().indexOf("IdsBy"));
631                }
632                if (method.getName().contains("KeysBy")) {
633                    return method.getName().substring("get".length(),
634                            method.getName().indexOf("KeysBy"));
635                }
636                if (method.getName().contains("IdsFor")) {
637                    return method.getName().substring("get".length(),
638                            method.getName().indexOf("IdsFor"));
639                }
640                if (method.getName().contains("With")) {
641                    return method.getName().substring("get".length(),
642                            method.getName().indexOf("With"));
643                }
644                if (method.getName().contains("By")) {
645                    return method.getName().substring("get".length(),
646                            method.getName().indexOf("By"));
647                }
648                return method.getName().substring("get".length());
649            }
650            String name = method.getReturnValue().getType();
651            if (name.endsWith("List")) {
652                name = name.substring(0, name.length() - "List".length());
653            }
654            if (name.endsWith("Info")) {
655                name = name.substring(0, name.length() - "Info".length());
656            }
657            return name;
658        }
659
660        if (method.getName().startsWith("searchFor")) {
661            if (method.getReturnValue().getType().equals("StringList")) {
662                if (method.getName().endsWith("Ids")) {
663                    return method.getName().substring("searchFor".length(),
664                            method.getName().indexOf("Ids"));
665                }
666                if (method.getName().endsWith("Keys")) {
667                    return method.getName().substring("get".length(),
668                            method.getName().indexOf("Keys"));
669                }
670                return method.getName().substring("searchFor".length());
671            }
672            String name = method.getReturnValue().getType();
673            if (name.endsWith("List")) {
674                name = name.substring(0, name.length() - "List".length());
675            }
676            if (name.endsWith("Info")) {
677                name = name.substring(0, name.length() - "Info".length());
678            }
679            return name;
680        }
681        if (method.getName().startsWith("add")) {
682            return method.getName().substring("add".length());
683        }
684        if (method.getName().startsWith("remove")) {
685            return method.getName().substring("remove".length());
686        }
687        String returnType = this.stripList(method.getReturnValue().getType());
688        XmlType type = this.finder.findXmlType(returnType);
689        if (type.getPrimitive().equals(XmlType.COMPLEX)) {
690            return returnType;
691        }
692        throw new IllegalArgumentException(method.getName());
693    }
694
695    private String calcNamedQuery(ServiceMethod method) {
696        String objectName = calcObjectName(method);
697        String name = method.getName();
698        if (name.startsWith("get")) {
699            name = name.substring("get".length());
700        }
701        if (name.startsWith(objectName)) {
702            name = name.substring(objectName.length());
703        }
704//        if (name.startsWith("Ids")) {
705//            name = name.substring("Ids".length());
706//        }
707//        if (name.isEmpty()) {
708//            throw new RuntimeException (method.getName());
709//        }
710        // remove plural
711        if (!method.getReturnValue().getType().equals("StringList")) {
712            if (name.startsWith("s")) {
713                name = name.substring("s".length());
714            }
715        }
716        // add back the get
717        name = "get" + name;
718        return name;
719    }
720
721
722    private ServiceMethodParameter findCriteriaParam(ServiceMethod method) {
723        for (ServiceMethodParameter param : method.getParameters()) {
724            if (param.getType().equals("QueryByCriteria")) {
725                return param;
726            }
727        }
728        return null;
729    }
730
731    private ServiceMethodParameter getTypeParameter(ServiceMethod method) {
732        ServiceMethodParameter fallbackParam = null;
733        for (ServiceMethodParameter parameter : method.getParameters()) {
734            if (parameter.getName().endsWith("TypeKey")) {
735                return parameter;
736            }
737            if (parameter.getType().equals("String")) {
738                if (parameter.getName().toLowerCase().contains("type")) {
739                    fallbackParam = parameter;
740                }
741            }
742        }
743        return fallbackParam;
744    }
745
746    private String calcInfoName(ServiceMethod method) {
747        String objectName = this.calcObjectName(method);
748        String infoName = objectName;
749        if (!this.isRice()) {
750            infoName = infoName + "Info";
751        }
752        return infoName;
753    }
754
755    private void writeGetIdsByType(ServiceMethod method) {
756        String objectName = this.calcObjectName(method);
757        String infoName = this.calcInfoName(method);
758        String daoVariable = calcDaoVariableName(method);
759        ServiceMethodParameter typeParam = this.getTypeParameter(method);
760        if (typeParam == null) {
761
762        }
763        indentPrintln("return " + daoVariable + ".getIdsByType(" + typeParam.getName() + ");");
764    }
765
766    private String initUpper(String str) {
767        return str.substring(0, 1).toUpperCase() + str.substring(1);
768    }
769
770    private ServiceMethodParameter findIdListParameter(ServiceMethod method) {
771        String idFieldName = calcObjectName(method) + "Ids";
772        if (this.isRice()) {
773            idFieldName = "ids";
774        }
775        for (ServiceMethodParameter parameter : method.getParameters()) {
776            if (parameter.getType().equals("StringList")) {
777                if (parameter.getName().equals(idFieldName)) {
778                    return parameter;
779                }
780            }
781        }
782        // can't find name exactly 
783        for (ServiceMethodParameter parameter : method.getParameters()) {
784            if (parameter.getType().equals("StringList")) {
785                if (parameter.getName().endsWith("Ids")) {
786                    return parameter;
787                }
788            }
789        }
790        // can't find name exactly try key 
791        for (ServiceMethodParameter parameter : method.getParameters()) {
792            if (parameter.getType().equals("StringList")) {
793                if (parameter.getName().endsWith("Keys")) {
794                    return parameter;
795                }
796            }
797        }
798        return null;
799    }
800
801    private String stripList(String str) {
802        return GetterSetterNameCalculator.stripList(str);
803    }
804
805    private String calcExceptionClassName(ServiceMethodError error) {
806        if (error.getClassName() == null) {
807            return ServiceExceptionWriter.calcClassName(error.getType());
808        }
809        return error.getClassName();
810    }
811
812    private String calcExceptionPackageName(ServiceMethodError error) {
813        if (error.getClassName() == null) {
814            return ServiceExceptionWriter.calcPackage(rootPackage);
815        }
816        return error.getPackageName();
817    }
818
819    private String calcType(String type, String realType) {
820        XmlType t = finder.findXmlType(this.stripList(type));
821        String retType = MessageStructureTypeCalculator.calculate(this, model, type, realType,
822                t.getJavaPackage());
823        if (this.isRice()) {
824            if (retType.equals("Boolean")) {
825                retType = "boolean";
826            }
827            if (retType.equals("Void")) {
828                retType = "void";
829            }
830        }
831        return retType;
832    }
833}