View Javadoc

1   package pl.aislib.tools.mapping.generators;
2   
3   import java.io.File;
4   import java.io.FileWriter;
5   import java.io.IOException;
6   import java.io.InputStream;
7   import java.io.Writer;
8   import java.util.Iterator;
9   import java.util.List;
10  
11  import org.apache.commons.io.IOUtils;
12  
13  import pl.aislib.tools.mapping.Generator;
14  import pl.aislib.tools.mapping.structure.Aggregate;
15  import pl.aislib.tools.mapping.structure.Call;
16  import pl.aislib.tools.mapping.structure.CallParam;
17  import pl.aislib.tools.mapping.structure.CallParams;
18  import pl.aislib.tools.mapping.structure.Count;
19  import pl.aislib.tools.mapping.structure.Delete;
20  import pl.aislib.tools.mapping.structure.Field;
21  import pl.aislib.tools.mapping.structure.Fields;
22  import pl.aislib.tools.mapping.structure.JavaClass;
23  import pl.aislib.tools.mapping.structure.JavaField;
24  import pl.aislib.tools.mapping.structure.JavaMethod;
25  import pl.aislib.tools.mapping.structure.Operation;
26  import pl.aislib.tools.mapping.structure.Operations;
27  import pl.aislib.tools.mapping.structure.Select;
28  import pl.aislib.tools.mapping.structure.SqlField;
29  import pl.aislib.tools.mapping.structure.SqlQuery;
30  import pl.aislib.tools.mapping.structure.SqlTable;
31  import pl.aislib.tools.mapping.structure.Structure;
32  import pl.aislib.tools.mapping.structure.Update;
33  
34  /***
35   * <code>dbhandlers</code> generator.
36   *
37   * @author <a href="mailto:milosz@ais.pl">Milosz Tylenda</a>, AIS.PL
38   * $Revision: 1.39 $
39   */
40  public class BeanHelperGenerator extends Generator {
41  
42    private File baseDir;
43    private Writer writer;
44  
45    private File initDirectory(File destinationDir) {
46      File dir = new File(destinationDir.getPath() + File.separator + dbHandlersSubdir);
47      if (!dir.exists()) {
48        dir.mkdirs();
49      }
50      return dir;
51    }
52  
53    private void initWriter(String fileName) throws IOException {
54      writer = new FileWriter(baseDir.getPath() + File.separator + fileName);
55    }
56  
57    private void closeWriter() throws IOException {
58      writer.close();
59    }
60  
61    public void generate() throws IOException {
62      baseDir = initDirectory(destinationDir);
63      MiscPutter      miscPutter      = new MiscPutter();
64      DisuPutter      disuPutter      = new DisuPutter();
65      AggregatePutter aggregatePutter = new AggregatePutter();
66      CallPutter      callPutter      = new CallPutter();
67      CountPutter     countPutter     = new CountPutter();
68      DeletePutter    deletePutter    = new DeletePutter();
69      SelectPutter    selectPutter    = new SelectPutter();
70      UpdatePutter    updatePutter    = new UpdatePutter();
71      ReadPutter      readPutter      = new ReadPutter();
72      List structureList = database.getStructureList();
73      for (int i = 0, size = structureList.size() ; i < size ; i++) {  // all structures
74        Structure structure = (Structure) structureList.get(i);
75        SqlTable  sqlTable  = structure.getSqlTable();
76        JavaClass javaClass = structure.getJavaClass();
77        Fields    fields    = structure.getFields();
78  
79        initWriter(javaClass.getName() + "Handler.java");    // open file
80        miscPutter.setWriter(writer);
81        miscPutter.setProperties(packageName, javaClass);
82        miscPutter.putHeader(); // to file
83        disuPutter.setWriter(writer);
84        disuPutter.setProperties(sqlTable, javaClass, fields);
85        disuPutter.put(); // to file
86  
87        aggregatePutter.setWriter(writer);
88        callPutter.setWriter(writer);
89        countPutter.setWriter(writer);
90        deletePutter.setWriter(writer);
91        selectPutter.setWriter(writer);
92        updatePutter.setWriter(writer);
93        Operations operations = structure.getOperations();
94        if (operations != null) {
95          List aggregateList = operations.getAggregateList();
96          for (Iterator aggregateIter = aggregateList.listIterator() ; aggregateIter.hasNext() ; ) {
97            Aggregate aggregate = (Aggregate) aggregateIter.next();
98            aggregatePutter.setProperties(aggregate, sqlTable);
99            aggregatePutter.put(); // to file
100         }
101         List callList = operations.getCallList();
102         for (Iterator callIter = callList.listIterator() ; callIter.hasNext() ; ) {
103           Call call = (Call) callIter.next();
104           callPutter.setProperties(call, javaClass, fields);
105           callPutter.put(); // to file
106         }
107         List countList = operations.getCountList();
108         for (Iterator countIter = countList.listIterator() ; countIter.hasNext() ; ) {
109           Count count = (Count) countIter.next();
110           countPutter.setProperties(count, sqlTable);
111           countPutter.put(); // to file
112         }
113         List deleteList = operations.getDeleteList();
114         for (Iterator deleteIter = deleteList.listIterator() ; deleteIter.hasNext() ; ) {
115           Delete deletee = (Delete) deleteIter.next();
116           deletePutter.setProperties(deletee, sqlTable);
117           deletePutter.put(); // to file
118         }
119         List selectList = operations.getSelectList();
120         for (Iterator selectIter = selectList.listIterator() ; selectIter.hasNext() ; ) {
121           Select select = (Select) selectIter.next();
122           selectPutter.setProperties(select, fields, sqlTable, javaClass);
123           selectPutter.put(); // to file
124         }
125         List updateList = operations.getUpdateList();
126         for (Iterator updateIter = updateList.listIterator() ; updateIter.hasNext() ; ) {
127           Update update = (Update) updateIter.next();
128           updatePutter.setProperties(update, sqlTable);
129           updatePutter.put(); // to file
130         }
131       }
132       readPutter.setWriter(writer);
133       readPutter.setProperties(javaClass, fields);
134       readPutter.put();  // to file
135       miscPutter.putClassEndBrace(); // to file
136       closeWriter();
137     }
138     putEnhancedStatement(structureList);
139     log(structureList.size() + " " + dbHandlersSubpackage + ".XHandler classes generated");
140   }
141 
142 
143   /***
144    * Puts a special implementation of PreparedStatement if a raw parameter found
145    * in operations.
146    */
147   private void putEnhancedStatement(List structureList) throws IOException {
148     boolean classFileNeeded = false;
149     
150     for (int i = 0, size = structureList.size() ; i < size ; i++) {  // all structures
151       Structure structure = (Structure) structureList.get(i);
152       Operations operations = structure.getOperations();
153       if (operations == null) {
154         continue;
155       }
156 
157       List operationList = operations.getAllOperations();
158       for (int j = 0, sizej = operationList.size(); j < sizej; j++) {
159         Operation operation = (Operation) operationList.get(j);
160         if (operation.getSqlQuery().containsRawParam()) {
161           classFileNeeded = true;
162           break;
163         }
164       }
165     }
166     
167     if (!classFileNeeded) {
168       return;
169     }
170     
171     initWriter("EnhancedStatement.java");
172     InputStream classSourceStream =
173       getClass().getClassLoader().getResourceAsStream("pl/aislib/tools/mapping/generators/EnhancedStatement.java");
174     String classSourceContent = IOUtils.toString(classSourceStream, "ISO-8859-2");
175     String classSourceContentWithoutPackage = classSourceContent.substring(classSourceContent.indexOf(';') + 2);
176     writer.write("package " + packageName + "." + dbHandlersSubpackage + ";\n");
177     writer.write(classSourceContentWithoutPackage);
178     closeWriter();
179     log("EnhancedStatement class generated.");
180   }
181 
182 
183   //#############################  D/I/S/U  ###########################
184   /***
185    * Puts <code>delete/insert/select/update</code> methods.
186    * @author Milosz Tylenda, AIS.PL
187    */
188   class DisuPutter {
189 
190     private Writer writer;
191     private SqlTable  sqlTable;
192     private JavaClass javaClass;
193     private Fields    fields;
194 
195     public void setWriter(Writer awriter) {
196       writer = awriter;
197     }
198 
199     public void put() throws IOException {
200       String className = javaClass.getName();
201       String tableName = sqlTable.getName();
202       List fieldList           = fields.getFieldList();
203       List fieldListNotOmitted = fields.getFieldListNotOmitted();
204       List primaryKeyList      = fields.getPrimaryKeyList();
205       List nonPrimaryKeyList   = fields.getNonPrimaryKeyList();
206       boolean pkDefined        = fields.hasPrimaryKey();
207 
208       // DELETE put
209       if (sqlTable.isDelete() && pkDefined) {
210         writer.write("  public static void delete(" + className);
211         writer.write(" object, Connection con) throws SQLException {\n");
212         writer.write("    SQLException sqlEx = null;\n");
213         writer.write("    try {\n");
214         writer.write("      PreparedStatement pstmt = con.prepareStatement(\"delete from ");
215         writer.write(tableName + " where \" +\n");
216         writer.write("        \"" + Utils.formatSqlListForWhere(primaryKeyList) + "\");\n");
217         writer.write("      int counter = 1;\n");
218         writer.write("      try {\n");
219         generateObjectIfs(primaryKeyList);
220         writer.write("        pstmt.executeUpdate();\n");
221         writer.write(createEndOfMethod2(false));
222       }
223 
224       // INSERT put
225       if (sqlTable.isInsert()) {
226         writer.write("  public static void insert(" + className + " object, Connection con) throws SQLException {\n");
227         writer.write("    SQLException sqlEx = null;\n");
228         writer.write("    try {\n");
229         writer.write("      int counter = 1;\n");
230         writer.write("      PreparedStatement pstmt = con.prepareStatement(\"insert into ");
231         writer.write(tableName + " (\" +\n");
232         writer.write("        " + Utils.formatSqlList(fieldListNotOmitted) + " +\n");
233         writer.write("        \") values (");
234         for (int i = 0, size = fieldListNotOmitted.size() ; i < size ; i++) {
235           if (i > 0) {
236             writer.write(", ");
237           }
238           if ((i % 10) == 0) {
239             writer.write("\" +\n");
240             writer.write("        \"");
241           }
242           writer.write ("?");
243         }
244         writer.write(")\");\n");
245         writer.write("      try {\n");
246         generateObjectIfs(fieldListNotOmitted);
247         writer.write("        pstmt.executeUpdate();\n");
248         writer.write(createEndOfMethod2(false));
249       }
250 
251       // SELECT put
252       if (sqlTable.isSelect() && pkDefined) {
253         writer.write("  public static " + className + " select(");
254         writer.write(Utils.formatArgList(primaryKeyList) + ",\n");
255         writer.write("    Connection con) throws SQLException {\n");
256         writer.write("    SQLException sqlEx = null;\n");
257         writer.write("    " + className + " result = null;\n");
258         writer.write("    try {\n");
259         writer.write("      PreparedStatement pstmt = con.prepareStatement(\"select \" +\n");
260         writer.write("        " + Utils.formatSqlList(fieldList) + " + \" \" +\n");
261         writer.write("        \"from " + tableName + " where \" +\n");
262         writer.write("        \"" + Utils.formatSqlListForWhere(primaryKeyList) + "\");\n");
263         writer.write("      int counter = 1;\n");
264         writer.write("      try {\n");
265         for (int i = 0, size = primaryKeyList.size() ; i < size ; i++) {
266           Field field         = (Field) primaryKeyList.get(i);
267           JavaField javaField = field.getJavaField();
268           String fieldName    = javaField.getName();
269           String fieldType    = javaField.getType();
270           writer.write("        pstmt.set" + Utils.mapTypeToMethod(fieldType));
271           writer.write("(counter++, " + fieldName);
272           writer.write(Utils.castMethod(fieldType));
273           writer.write(");\n");
274         }
275         writer.write("        ResultSet rs = pstmt.executeQuery();\n");
276         writer.write("        try {\n");
277         writer.write("          if (rs.next()) {\n");
278         writer.write("            return read(rs);\n");
279         writer.write("          }\n");
280         writer.write(createEndOfMethod());
281       }
282 
283       // UPDATE put
284       if (sqlTable.isUpdate() && pkDefined) {
285         writer.write("  public static void update(" + className);
286         writer.write(" object, Connection con) throws SQLException {\n");
287         writer.write("    SQLException sqlEx = null;\n");
288         writer.write("    try {\n");
289         writer.write("      PreparedStatement pstmt = con.prepareStatement(\"update ");
290         writer.write(tableName + " set \" +\n");
291         writer.write("        " + Utils.formatSqlListForUpdate(nonPrimaryKeyList) + " +\n");
292         writer.write("        \"where \" +\n");
293         writer.write("        \"" + Utils.formatSqlListForWhere(primaryKeyList) +  "\");\n");
294         writer.write("      int counter = 1;\n");
295         writer.write("      try {\n");
296         generateObjectIfs(nonPrimaryKeyList);
297         generateObjectIfs(primaryKeyList);
298         writer.write("        pstmt.executeUpdate();\n");
299         writer.write(createEndOfMethod2(false));
300       }
301     }
302 
303     private void generateObjectIfs(List fieldList) throws IOException {
304       for (int i = 0, size = fieldList.size() ; i < size ; i++) {
305         Field field         = (Field) fieldList.get(i);
306         JavaField javaField = field.getJavaField();
307         String fieldName    = javaField.getName();
308         String fieldType    = javaField.getType();
309         writer.write("        if (object." + Utils.getter(fieldName) + " != null) {\n");
310         writer.write("          pstmt.set" + Utils.mapTypeToMethod(fieldType));
311         writer.write("(counter++, object." + Utils.getter(fieldName));
312         writer.write(Utils.castMethod(fieldType));
313         writer.write(");\n");
314         writer.write("        } else {\n");
315         writer.write("          pstmt.setNull(counter++, ");
316         writer.write(Utils.getSQLType(fieldType));
317         writer.write(");\n");
318         writer.write("        }\n");
319       }
320     }
321 
322     public void setProperties(SqlTable sqlTable, JavaClass javaClass, Fields fields) {
323       this.sqlTable = sqlTable;
324       this.javaClass = javaClass;
325       this.fields = fields;
326     }
327   } // class DisuPutter
328 
329 
330   //#############################  READ  ############################
331   /***
332    * Puts <code>read</code> method.
333    * @author Milosz Tylenda, AIS.PL
334    */
335   class ReadPutter {
336 
337     private Writer writer;
338     private Fields    fields;
339     private String    className;
340 
341     public void setWriter(Writer awriter) {
342       writer = awriter;
343     }
344 
345     public void put() throws IOException {
346       List fieldList        = fields.getFieldList();
347       writer.write("  public static " + className + " read(ResultSet rs) throws SQLException {\n");
348       writer.write("    " + className + " result = new " + className + "();\n");
349       writer.write("    int counter = 1;\n");
350 
351       for (int i = 0, size = fieldList.size() ; i < size ; i++) {
352         Field field            = (Field) fieldList.get(i);
353         JavaField javaField    = field.getJavaField();
354         SqlField sqlField      = field.getSqlField();
355         if (sqlField.isClobType()) {
356           putClobFieldGetting(javaField);
357           continue;
358         }
359         String cappedFieldName = Utils.capitalize(javaField.getName());
360         String fieldType       = javaField.getType();
361         writer.write("    result.set" + cappedFieldName + "(");
362         if (Utils.isBaseType(fieldType)) {
363           writer.write("new " + fieldType + "(rs.get" + Utils.mapTypeToMethod(fieldType) + "(counter++)));\n");
364           writer.write("    if (rs.wasNull()) {\n");
365           writer.write("      result.set" + cappedFieldName + "(null);\n");
366           writer.write("    }\n");
367         } else {
368           writer.write("rs.get" + Utils.mapTypeToMethod(fieldType) + "(counter++));\n");
369         }
370       }
371       writer.write("    return result;\n");
372       writer.write("  }\n\n");
373     }
374 
375     public void setProperties(JavaClass javaClass, Fields fields) {
376       this.fields    = fields;
377       this.className = javaClass.getName();
378     }
379 
380     /***
381      * Puts Clob getting code. It is assumed than javaField is of String type.
382      * That is, the application sees field mapped to CLOB as String.
383      */
384     private void putClobFieldGetting(JavaField javaField) throws IOException {
385       String cappedFieldName = Utils.capitalize(javaField.getName());
386       writer.write("    java.sql.Clob clob" + cappedFieldName + " = rs.getClob(counter++);\n");
387       writer.write("    if (clob" + cappedFieldName + " != null) {\n");
388       writer.write("      result.set" + cappedFieldName +
389         "(clob" + cappedFieldName + ".getSubString(1L, (int) clob" + cappedFieldName + ".length()));\n");
390       writer.write("    } else {\n");
391       writer.write("      result.set" + cappedFieldName + "(null);\n");
392       writer.write("    }\n");
393     }
394 
395   } // class ReadPutter
396 
397   //#############################  OPERATIONS - AGGREGATE  ############################
398   /***
399    * Puts <code>&lt;operations&gt;</code> aggregate-methods.
400    * @author Milosz Tylenda, AIS.PL
401    */
402   class AggregatePutter {
403 
404     private Writer    writer;
405     private Aggregate aggregate;
406     private SqlTable  sqlTable;
407 
408     public void setWriter(Writer awriter) {
409       writer = awriter;
410     }
411 
412     public void put() throws IOException {
413       JavaMethod javaMethod = aggregate.getJavaMethod();
414       SqlQuery   sqlQuery   = aggregate.getSqlQuery();
415       List javaParamList    = javaMethod.getJavaParamList();
416 
417       String query = "SELECT " + sqlQuery.createDistinctClause() + sqlQuery.getColumns() +
418         sqlQuery.createFromClause(sqlTable.getName()) + sqlQuery.createWhereClause() +
419         sqlQuery.createGroupByAndHavingClause() + sqlQuery.createOrderByClause() +
420         sqlQuery.createOtherClause();
421 
422       writer.write(createJavaDoc(query, javaParamList, aggregate.createReturnForJavadoc()));
423       if (aggregate.isMultipleRows()) {
424         putMultipleRows(query);
425       } else {
426         putOneRow(query);
427       }
428     }
429 
430     public void setProperties(Aggregate aggregate, SqlTable sqlTable) {
431       this.aggregate = aggregate;
432       this.sqlTable  = sqlTable;
433     }
434 
435     private void putOneRow(String query) throws IOException {
436       JavaMethod javaMethod = aggregate.getJavaMethod();
437       String methodName     = javaMethod.getName();
438       List javaParamList    = javaMethod.getJavaParamList();
439       String returnType     = javaMethod.getReturnType();
440 
441       writer.write("  public static " + returnType + " aggregate" + Utils.capitalize(methodName) + "(");
442       writer.write(Utils.formatMethodArgs(javaParamList));
443       writer.write("Connection con) throws SQLException {\n");
444       writer.write("    SQLException sqlEx = null;\n");
445       writer.write("    " + returnType + " result = null;\n");
446       writer.write("    try {\n");
447       writer.write(Utils.createPreparedStatement(query));
448       writer.write("      try {\n");
449       writer.write(Utils.generatePstmtSets(javaParamList));
450       writer.write("        ResultSet rs = pstmt.executeQuery();\n");
451       writer.write("        try {\n");
452       writer.write("          if (rs.next()) {\n");
453       if (Utils.isBaseType(returnType)) {
454         writer.write("            result = new " + returnType + "(rs.get" + Utils.mapTypeToMethod(returnType)+ "(1));\n");
455         writer.write("            if (rs.wasNull()) {\n");
456         writer.write("              result = null;\n");
457         writer.write("            }\n");
458       } else {
459         writer.write("            result = rs.get" + Utils.mapTypeToMethod(returnType)+ "(1);\n");
460       }
461       writer.write("          }\n");
462       writer.write("          return result;\n");
463       writer.write(createEndOfMethod());
464     }
465 
466     private void putMultipleRows(String query) throws IOException {
467       JavaMethod javaMethod = aggregate.getJavaMethod();
468       String methodName     = javaMethod.getName();
469       List javaParamList    = javaMethod.getJavaParamList();
470       String returnType     = javaMethod.getReturnType();
471 
472       writer.write("  public static List aggregate" + Utils.capitalize(methodName) + "(");
473       writer.write(Utils.formatMethodArgs(javaParamList));
474       writer.write("Connection con) throws SQLException {\n");
475       writer.write("    SQLException sqlEx = null;\n");
476       writer.write("    List result = new ArrayList();\n");
477       writer.write("    try {\n");
478       writer.write(Utils.createPreparedStatement(query));
479       writer.write("      try {\n");
480       writer.write(Utils.generatePstmtSets(javaParamList));
481       writer.write("        ResultSet rs = pstmt.executeQuery();\n");
482       writer.write("        try {\n");
483       writer.write("          while (rs.next()) {\n");
484       if (Utils.isBaseType(returnType)) {
485         writer.write("            " + returnType + " element = new " + returnType + "(rs.get" + Utils.mapTypeToMethod(returnType)+ "(1));\n");
486       } else {
487         writer.write("            " + returnType + " element = rs.get" + Utils.mapTypeToMethod(returnType)+ "(1);\n");
488       }
489       writer.write("            if (!rs.wasNull()) {\n");
490       writer.write("              result.add(element);\n");
491       writer.write("            }\n");
492       writer.write("          }\n");
493       writer.write("          return result;\n");
494       writer.write(createEndOfMethod());
495     }
496 
497   } // class AggregatePutter
498 
499   //#############################  OPERATIONS - CALL  ############################
500   /***
501    * Puts <code>&lt;operations&gt;</code> call-methods.
502    * @author Milosz Tylenda, AIS.PL
503    */
504   class CallPutter {
505 
506     private Writer    writer;
507     private Call      call;
508     private JavaClass javaClass;
509     private Fields    fields;
510 
511     public void setWriter(Writer awriter) {
512       writer = awriter;
513     }
514 
515     public void put() throws IOException {
516       CallParams callParams      = call.getCallParams();
517       JavaMethod javaMethod      = call.getJavaMethod();
518       String methodName          = javaMethod.getName();
519       List extendedJavaParamList = javaMethod.createExtendedJavaParamList(javaClass);
520       SqlQuery sqlQuery          = call.getSqlQuery();
521 
522       boolean hasOutOrInoutParam = false;
523       String  returnType         = "void";
524       String  returnString       = null;
525 
526       String query       = sqlQuery.getBody();
527       CallParam outParam = callParams.findOutOrInoutParam();
528       if (outParam != null) {
529         hasOutOrInoutParam = true;
530         returnType         = outParam.determineType(fields, javaMethod);
531         returnString       = Call.JAVADOC_RETURN_STRING;
532       }
533       writer.write(createJavaDoc(query, extendedJavaParamList, returnString));
534       writer.write("  public static " + returnType + " call" + Utils.capitalize(methodName) + "(");
535       writer.write(Utils.formatMethodArgs(extendedJavaParamList));
536       writer.write("Connection con) throws SQLException {\n");
537       writer.write("    SQLException sqlEx = null;\n");
538       if (hasOutOrInoutParam) {
539         writer.write("    " + returnType + " result = null;\n");
540       }
541       writer.write("    try {\n");
542       writer.write("      CallableStatement pstmt = con.prepareCall(" + Utils.equalLengthSplit(query) + ");\n");
543       writer.write("      try {\n");
544       writer.write(generatePstmtSets(callParams, fields, javaMethod));
545       writer.write("        pstmt.executeUpdate();\n");
546       if (hasOutOrInoutParam) {
547         int outIndex = callParams.getIndexOfOutOrInoutParam() + 1;
548         String method = Utils.mapTypeToMethod(returnType) + "(" + outIndex + ")";
549         if (Utils.isBaseType(returnType)) {
550           writer.write("        result = new " + returnType + "(pstmt.get" + method + ");\n");
551           writer.write("        if (pstmt.wasNull()) {\n");
552           writer.write("          result = null;\n");
553           writer.write("        }\n");
554         } else {
555           writer.write("        result = pstmt.get" + method + ";\n");
556         }
557       }
558       writer.write(createEndOfMethod2(hasOutOrInoutParam));
559     }
560 
561     public void setProperties(Call call, JavaClass javaClass, Fields fields) {
562       this.call      = call;
563       this.javaClass = javaClass;
564       this.fields    = fields;
565     }
566 
567     /***
568      * Generates PreparedStatement.setX() code.
569      */
570     private String generatePstmtSets(CallParams callParams, Fields fields, JavaMethod javaMethod) {
571       List callParamList  = callParams.getCallParamList();
572       StringBuffer result = new StringBuffer(512);
573       for (int i = 0, size = callParamList.size() ; i < size ; i++) {  // for all callParams
574         CallParam callParam = (CallParam) callParamList.get(i);
575 
576         if (callParam.isInOrInoutParam()) {
577           Utils.generatePstmtSet(result, callParam.createJavaParam(fields, javaMethod), i + 1);
578         }
579 
580         if (callParam.isOutOrInoutParam()) {
581           String sqlType = Utils.getSQLType(callParam.determineType(fields, javaMethod));
582           result.append("        pstmt.registerOutParameter(" + (i + 1) + ", " + sqlType + ");\n");
583         }
584 
585       }
586       return result.toString();
587     }
588 
589   } // class CallPutter
590 
591   //#############################  OPERATIONS - COUNT  ############################
592   /***
593    * Puts <code>&lt;operations&gt;</code> count-methods.
594    * @author Milosz Tylenda, AIS.PL
595    */
596   class CountPutter {
597 
598     private Writer    writer;
599     private Count     count;
600     private SqlTable  sqlTable;
601 
602     public void setWriter(Writer awriter) {
603       writer = awriter;
604     }
605 
606     public void put() throws IOException {
607       JavaMethod javaMethod = count.getJavaMethod();
608       String methodName     = javaMethod.getName();
609       List javaParamList    = javaMethod.getJavaParamList();
610       SqlQuery sqlQuery     = count.getSqlQuery();
611 
612       String query = "SELECT COUNT(*) " + sqlQuery.createFromClause(sqlTable.getName()) +
613         sqlQuery.createWhereClause() + sqlQuery.createOtherClause();
614       writer.write(createJavaDoc(query, javaParamList, "number of counted rows"));
615       writer.write("  public static int count" + Utils.capitalize(methodName) + "(");
616       writer.write(Utils.formatMethodArgs(javaParamList));
617       writer.write("Connection con) throws SQLException {\n");
618       writer.write("    SQLException sqlEx = null;\n");
619       writer.write("    int result = 0;\n");
620       writer.write("    try {\n");
621       writer.write(Utils.createPreparedStatement(query));
622       writer.write("      try {\n");
623       writer.write(Utils.generatePstmtSets(javaParamList));
624       writer.write("        ResultSet rs = pstmt.executeQuery();\n");
625       writer.write("        try {\n");
626       writer.write("          if (rs.next()) {\n");
627       writer.write("            result = rs.getInt(1);\n");
628       writer.write("          }\n");
629       writer.write("          return result;\n");
630       writer.write(createEndOfMethod());
631     }
632 
633     public void setProperties(Count count, SqlTable sqlTable) {
634       this.count    = count;
635       this.sqlTable = sqlTable;
636     }
637   } // class CountPutter
638 
639   //#############################  OPERATIONS - SELECT  ############################
640   /***
641    * Puts <code>&lt;operations&gt;</code> select-methods.
642    * @author Milosz Tylenda, AIS.PL
643    */
644   class SelectPutter {
645 
646     private Writer    writer;
647     private Select    select;
648     private Fields    fields;
649     private SqlTable  sqlTable;
650     private JavaClass javaClass;
651 
652     public void setWriter(Writer awriter) {
653       writer = awriter;
654     }
655 
656     public void put() throws IOException {
657       List fieldList        = fields.getFieldList();
658       SqlQuery sqlQuery     = select.getSqlQuery();
659       JavaMethod javaMethod = select.getJavaMethod();
660       List javaParamList    = javaMethod.getJavaParamList();
661 
662       String query = "SELECT " + sqlQuery.createDistinctClause() +
663         sqlQuery.createColumnsClause(fieldList, sqlTable.getName()) +
664         sqlQuery.createFromClause(sqlTable.getName()) + sqlQuery.createWhereClause() +
665         sqlQuery.createGroupByAndHavingClause() + sqlQuery.createOrderByClause() +
666         sqlQuery.createOtherClause();
667 
668       writer.write(createJavaDoc(query, javaParamList, select.createReturnForJavadoc(javaClass)));
669       if (select.isMultipleRows()) {
670         putMultipleRows(query);
671       } else {
672         putOneRow(query);
673       }
674     }
675 
676     public void setProperties(Select select, Fields fields, SqlTable sqlTable, JavaClass javaClass) {
677       this.select    = select;
678       this.fields    = fields;
679       this.sqlTable  = sqlTable;
680       this.javaClass = javaClass;
681     }
682 
683     private void putOneRow(String query) throws IOException {
684       JavaMethod javaMethod = select.getJavaMethod();
685       String methodName     = javaMethod.getName();
686       List javaParamList    = javaMethod.getJavaParamList();
687       String className      = javaClass.getName();
688 
689       writer.write("  public static " + className + " select" + Utils.capitalize(methodName) + "(");
690       writer.write(Utils.formatMethodArgs(javaParamList));
691       writer.write("Connection con) throws SQLException {\n");
692       writer.write("    SQLException sqlEx = null;\n");
693       writer.write("    " + className + " result = null;\n");
694       writer.write("    try {\n");
695       writer.write(Utils.createPreparedStatement(query));
696       writer.write("      try {\n");
697       writer.write(Utils.generatePstmtSets(javaParamList));
698       writer.write("        ResultSet rs = pstmt.executeQuery();\n");
699       writer.write("        try {\n");
700       writer.write("          if (rs.next()) {\n");
701       writer.write("            result = read(rs);\n");
702       writer.write("          }\n");
703       writer.write("          return result;\n");
704       writer.write(createEndOfMethod());
705     }
706 
707     private void putMultipleRows(String query) throws IOException {
708       JavaMethod javaMethod = select.getJavaMethod();
709       String methodName     = javaMethod.getName();
710       List javaParamList    = javaMethod.getJavaParamList();
711 
712       writer.write("  public static List select" + Utils.capitalize(methodName) + "(");
713       writer.write(Utils.formatMethodArgs(javaParamList));
714       writer.write("Connection con) throws SQLException {\n");
715       writer.write("    SQLException sqlEx = null;\n");
716       writer.write("    List result = new ArrayList();\n");
717       writer.write("    try {\n");
718       writer.write(Utils.createPreparedStatement(query));
719       writer.write("      try {\n");
720       writer.write(Utils.generatePstmtSets(javaParamList));
721       writer.write("        ResultSet rs = pstmt.executeQuery();\n");
722       writer.write("        try {\n");
723       writer.write("          while (rs.next()) {\n");
724       writer.write("            result.add(read(rs));\n");
725       writer.write("          }\n");
726       writer.write("          return result;\n");
727       writer.write(createEndOfMethod());
728     }
729 
730   } // class SelectPutter
731 
732   //#############################  OPERATIONS - DELETE  ############################
733   /***
734    * Puts <code>&lt;operations&gt;</code> delete-methods.
735    * @author Milosz Tylenda, AIS.PL
736    */
737   class DeletePutter {
738 
739     private Writer    writer;
740     private Delete    deletee;
741     private SqlTable  sqlTable;
742 
743     public void setWriter(Writer awriter) {
744       writer = awriter;
745     }
746 
747     public void put() throws IOException {
748       JavaMethod javaMethod = deletee.getJavaMethod();
749       String methodName     = javaMethod.getName();
750       List javaParamList    = javaMethod.getJavaParamList();
751       SqlQuery sqlQuery     = deletee.getSqlQuery();
752 
753 
754       String query = "DELETE FROM " + sqlTable.getName() + sqlQuery.createWhereClause() +
755         sqlQuery.createOtherClause();
756       writer.write(createJavaDoc(query, javaParamList, "number of deleted rows"));
757       writer.write("  public static int delete" + Utils.capitalize(methodName) + "(");
758       writer.write(Utils.formatMethodArgs(javaParamList));
759       writer.write("Connection con) throws SQLException {\n");
760       writer.write("    SQLException sqlEx = null;\n");
761       writer.write("    int result = 0;\n");
762       writer.write("    try {\n");
763       writer.write(Utils.createPreparedStatement(query));
764       writer.write("      try {\n");
765       writer.write(Utils.generatePstmtSets(javaParamList));
766       writer.write("        result = pstmt.executeUpdate();\n");
767       writer.write(createEndOfMethod2(true));
768     }
769 
770     public void setProperties(Delete deletee, SqlTable sqlTable) {
771       this.deletee    = deletee;
772       this.sqlTable  = sqlTable;
773     }
774   } // class DeletePutter
775 
776   //#############################  OPERATIONS - UPDATE  ############################
777   /***
778    * Puts <code>&lt;operations&gt;</code> update-methods.
779    * @author Milosz Tylenda, AIS.PL
780    */
781   class UpdatePutter {
782 
783     private Writer    writer;
784     private Update    update;
785     private SqlTable  sqlTable;
786 
787     public void setWriter(Writer awriter) {
788       writer = awriter;
789     }
790 
791     public void put() throws IOException {
792       JavaMethod javaMethod = update.getJavaMethod();
793       String methodName     = javaMethod.getName();
794       List javaParamList    = javaMethod.getJavaParamList();
795       SqlQuery sqlQuery     = update.getSqlQuery();
796 
797       String query = "UPDATE " + sqlTable.getName() + " SET " + sqlQuery.getSet() + sqlQuery.createWhereClause() +
798         sqlQuery.createOtherClause();
799       writer.write(createJavaDoc(query, javaParamList, "number of updated rows"));
800       writer.write("  public static int update" + Utils.capitalize(methodName) + "(");
801       writer.write(Utils.formatMethodArgs(javaParamList));
802       writer.write("Connection con) throws SQLException {\n");
803       writer.write("    SQLException sqlEx = null;\n");
804       writer.write("    int result = 0;\n");
805       writer.write("    try {\n");
806       writer.write(Utils.createPreparedStatement(query));
807       writer.write("      try {\n");
808       writer.write(Utils.generatePstmtSets(javaParamList));
809       writer.write("        result = pstmt.executeUpdate();\n");
810       writer.write(createEndOfMethod2(true));
811     }
812 
813     public void setProperties(Update update, SqlTable sqlTable) {
814       this.update    = update;
815       this.sqlTable  = sqlTable;
816     }
817   } // class UpdatePutter
818 
819 
820   //#############################  MISC  ###########################
821   /***
822    * Puts some little things like <CODE>package</CODE> string and class end brace.
823    * @author Milosz Tylenda, AIS.PL
824    */
825   class MiscPutter {
826 
827     private Writer       writer;
828     privateong> String       packagePrefix;
829     private String       className;
830 
831     public void setWriter(Writer awriter) {
832       writer = awriter;
833     }
834 
835     public void setProperties(String aPackagePrefix, JavaClass javaClass) {
836       packagePrefix = aPackagePrefix;
837       className     = javaClass.getName();
838     }
839 
840     public void putHeader() throws IOException {
841       writer.write("package " + packagePrefix + "." + dbHandlersSubpackage + ";\n\n");
842       writer.write("// THIS FILE HAS BEEN GENERATED AUTOMAGICALLY. DO NOT EDIT!\n\n");
843       writer.write("import java.math.BigDecimal;\n\n");
844       writer.write("import java.sql.Connection;\n");
845       writer.write("import java.sql.CallableStatement;\n");
846       writer.write("import java.sql.PreparedStatement;\n");
847       writer.write("import java.sql.ResultSet;\n");
848       writer.write("import java.sql.SQLException;\n");
849       writer.write("import java.sql.Timestamp;\n\n");
850       writer.write("import java.util.ArrayList;\n");
851       writer.write("import java.util.List;\n\n");
852       writer.write("import " + packagePrefix + "." + objectsSubpackage + "." + className + ";\n\n");
853       writer.write("/**\n");
854       writer.write(" * <code>" + className + "</code> database handler.\n");
855       writer.write(" * @author BeanHelperGenerator\n");
856       writer.write(" */\n");
857       writer.write("public class " + className + "Handler {\n\n");
858     }
859 
860     public void putClassEndBrace() throws IOException {
861       writer.write("}\n");
862     }
863 
864   } // class MiscPutter
865 
866   /***
867    * Common code used in SELECT queries.
868    */
869   String createEndOfMethod() {
870     return
871     "        } catch (SQLException sqle1) {\n" +
872     "          sqlEx = sqle1;\n" +
873     "        } finally {\n" +
874     "          rs.close();\n" +
875     "        }\n" +
876     "      } catch (SQLException sqle2) {\n" +
877     "        if (sqlEx == null) {\n" +
878     "          sqlEx = sqle2;\n" +
879     "        }\n" +
880     "      } finally {\n" +
881     "        pstmt.close();\n" +
882     "      }\n" +
883     "    } catch (SQLException sqle3) {\n" +
884     "      if (sqlEx == null) {\n" +
885     "        sqlEx = sqle3;\n" +
886     "      }\n" +
887     "    } finally {\n" +
888     "      if (sqlEx != null) {\n" +
889     "        throw sqlEx;\n" +
890     "      }\n" +
891     "    }\n" +
892     "    return result;\n" +
893     "  }\n\n";
894   }
895 
896   /***
897    * Common code used in DELETE/INSERT/UPDATE/SP queries.
898    */
899   String createEndOfMethod2(boolean createReturn) {
900     StringBuffer result = new StringBuffer(512);
901     result.append(
902     "      } catch (SQLException sqle1) {\n" +
903     "        sqlEx = sqle1;\n" +
904     "      } finally {\n" +
905     "        pstmt.close();\n" +
906     "      }\n" +
907     "    } catch (SQLException sqle2) {\n" +
908     "      if (sqlEx == null) {\n" +
909     "        sqlEx = sqle2;\n" +
910     "      }\n" +
911     "    } finally {\n" +
912     "      if (sqlEx != null) {\n" +
913     "        throw sqlEx;\n" +
914     "      }\n" +
915     "    }\n"
916     );
917     if (createReturn) {
918       result.append("    return result;\n");
919     }
920     result.append("  }\n\n");
921     return result.toString();
922   }
923 
924   /***
925    * JavaDoc before method.
926    */
927   String createJavaDoc(String query, List javaParamList, String returnString) {
928     StringBuffer result = new StringBuffer(512);
929     result.append("  /**\n");
930     result.append("   * <code>" + Utils.protectHTML(query) + "</code>.\n");
931     result.append(Utils.formatMethodArgsForJavaDoc(javaParamList));
932     result.append("   * @param con the <code>Connection</code> to database\n");
933     if (returnString != null) {
934       result.append("   * @return " + returnString + "\n");
935     }
936     result.append("   * @throws SQLException when operation failed\n");
937     result.append("   */\n");
938     return result.toString();
939   }
940 
941 }
942 
943 /***
944  * $Log: BeanHelperGenerator.java,v $
945  * Revision 1.39  2004/09/27 10:34:54  milosz
946  * SelectPutter: call to static method from Utils replaced with SqlQuery.createColumnsClause adding support of columns attribute to select element.
947  *
948  * Revision 1.38  2004/09/13 13:32:34  milosz
949  * putEnhancedStatement: logging added.
950  *
951  * Revision 1.37  2004/09/10 16:15:12  milosz
952  * Support for raw params added: putEnhancedStatement method added; uses method from Utils to generate suitable code for PreparedStatement creation.
953  *
954  * Revision 1.36  2004/09/08 11:37:11  milosz
955  * Removed empty constructors, changed scopes of some methods to default to decrease the number of compiler warnings.
956  *
957  * Revision 1.35  2004/08/11 12:41:01  wswiatek
958  * Database and map handlers location are now parametrizable.
959  * Maven plugin version changed to 1.0.1
960  *
961  * Revision 1.34  2004/07/02 07:39:52  milosz
962  * Support for 'group-by', 'having' and 'other' attributes added to 'sql-query.' Removed unnecessary line from generated code in aggregate method.
963  *
964  * Revision 1.33  2004/06/17 07:33:00  milosz
965  * Generated read method now public and always generated.
966  *
967  * Revision 1.32  2003/10/29 11:47:02  pikus
968  * use ant logger where possible
969  *
970  * Revision 1.31  2003/10/29 10:32:06  milosz
971  * Support for CLOB <-> String mapping added.
972  *
973  * Revision 1.30  2003/09/12 13:22:19  milosz
974  * Refactoring: syntax checking moved from generators to DatabaseChecker and other classes in structure package.
975  *
976  * Revision 1.29  2003/09/10 07:35:19  milosz
977  * CallPutter.generatePstmtSets method simplified.
978  *
979  * Revision 1.28  2003/09/09 13:25:39  milosz
980  * Support for operations/call element added.
981  *
982  * Revision 1.27  2003/09/02 13:33:07  milosz
983  * java.sql.Statement import was unnecessary.
984  *
985  * Revision 1.26  2003/09/02 11:06:29  milosz
986  * Generic UPDATE generator changed to complain when a table has all columns marked as primary keys and update method wanted.
987  *
988  * Revision 1.25  2003/09/02 10:40:56  milosz
989  * Generic UPDATE generator corrected to generate compilable code (although not SQL parseable) when a table has all columns marked as primary keys.
990  *
991  * Revision 1.24  2003/09/02 10:15:00  milosz
992  * Some of generated String constants are splitted, so Jalopy can break more lines.
993  *
994  * Revision 1.23  2003/07/11 13:08:14  milosz
995  * objectsSubpackage property added.
996  *
997  * Revision 1.22  2003/06/04 07:58:10  milosz
998  * 'multipleRows' attribute added to operations/select element.
999  *
1000  * Revision 1.21  2003/05/28 13:10:09  milosz
1001  * Support for 'from' attribute added in 'sql-query' element.
1002  *
1003  * Revision 1.20  2003/05/28 08:27:57  milosz
1004  * Generated read method optimized - ResulSet.wasNull() checks are necessary for objects.
1005  *
1006  * Revision 1.19  2003/05/26 08:36:03  pikus
1007  * cleanup imports
1008  *
1009  * Revision 1.18  2003/05/20 08:12:12  milosz
1010  * Support for 'multipleRows' attribute in 'aggregate' element added.
1011  *
1012  * Revision 1.17  2003/05/20 07:25:44  milosz
1013  * Refactoring: createJavaDoc method extracted.
1014  *
1015  * Revision 1.16  2003/05/19 11:49:20  milosz
1016  * Refactoring: createEndOfMethodX methods extracted.
1017  *
1018  * Revision 1.15  2003/05/19 08:57:54  milosz
1019  * Added createXClause methods to SqlQuery.
1020  *
1021  * Revision 1.14  2003/05/16 13:04:00  milosz
1022  * Forgotten order-by support added to operations/aggregate.
1023  *
1024  * Revision 1.13  2003/05/14 13:55:45  milosz
1025  * Dead code removed (was introduced by Array support).
1026  *
1027  * Revision 1.12  2003/05/14 13:39:03  milosz
1028  * operations/aggregate element added.
1029  *
1030  * Revision 1.11  2003/04/08 09:54:24  milosz
1031  * Removed unnecessary <code> tag from @throws tag in JavaDoc.
1032  *
1033  * Revision 1.10  2002/12/05 09:37:54  milosz
1034  * DML strings displayed correctly in JavaDocs.
1035  *
1036  * Revision 1.9  2002/12/05 09:24:29  milosz
1037  * count element code was not correct.
1038  *
1039  * Revision 1.8  2002/12/03 11:53:12  milosz
1040  * Added JavaDoc generation to operations/select.
1041  *
1042  * Revision 1.7  2002/12/03 11:09:20  milosz
1043  * operations/count element added.
1044  *
1045  * Revision 1.6  2002/12/03 09:10:50  milosz
1046  * operations/update element added.
1047  *
1048  * Revision 1.5  2002/12/02 14:28:13  milosz
1049  * operations/delete element added.
1050  *
1051  * Revision 1.4  2002/11/04 07:31:32  wswiatek
1052  * Added oracle.sql.ARRAY type
1053  *
1054  * Revision 1.3  2002/10/09 10:03:31  milosz
1055  * Better messages and behaviour for structure without primary keys.
1056  *
1057  * Revision 1.2  2002/10/08 08:27:10  milosz
1058  * Generators became AntTasks(?). Ufff...
1059  *
1060  * Revision 1.1  2002/10/04 13:07:22  milosz
1061  * Reaching old mapping's functionality.
1062  *
1063  */
1064