001: /*
002: * sqlc 1
003: * SQL Compiler
004: * Copyright (C) 2003 Hammurapi Group
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * URL: http://www.hammurapi.biz/products/sqlc/index.html
021: * e-Mail: support@hammurapi.biz
022: */
023: package biz.hammurapi.sqlc;
024:
025: import java.sql.Connection;
026: import java.sql.ParameterMetaData;
027: import java.sql.PreparedStatement;
028: import java.sql.SQLException;
029: import java.sql.Types;
030: import java.util.ArrayList;
031: import java.util.Collection;
032: import java.util.HashSet;
033: import java.util.Iterator;
034: import java.util.LinkedList;
035: import java.util.Set;
036:
037: import org.apache.bcel.Constants;
038: import org.apache.bcel.generic.ALOAD;
039: import org.apache.bcel.generic.ASTORE;
040: import org.apache.bcel.generic.ATHROW;
041: import org.apache.bcel.generic.DUP;
042: import org.apache.bcel.generic.GOTO;
043: import org.apache.bcel.generic.ICONST;
044: import org.apache.bcel.generic.IFNONNULL;
045: import org.apache.bcel.generic.InstructionFactory;
046: import org.apache.bcel.generic.InstructionHandle;
047: import org.apache.bcel.generic.InstructionList;
048: import org.apache.bcel.generic.LDC;
049: import org.apache.bcel.generic.RETURN;
050:
051: import biz.hammurapi.codegen.Class;
052: import biz.hammurapi.codegen.ClassGeneratorBase;
053: import biz.hammurapi.codegen.Consumer;
054: import biz.hammurapi.codegen.ExceptionHandler;
055: import biz.hammurapi.codegen.GenerationException;
056: import biz.hammurapi.codegen.InterfacePool;
057: import biz.hammurapi.codegen.MethodPrototype;
058: import biz.hammurapi.sql.Parameterizer;
059: import biz.hammurapi.sql.SQLProcessor;
060: import biz.hammurapi.sql.metadata.ColumnDescriptor;
061: import biz.hammurapi.sql.metadata.DbParameter;
062: import biz.hammurapi.sql.metadata.GenerationPolicy;
063: import biz.hammurapi.sql.metadata.ParameterDescriptor;
064: import biz.hammurapi.util.Parameter;
065: import biz.hammurapi.xml.dom.DomSerializable;
066:
067: /**
068: * @author Pavel Vlasov
069: * @version $Revision: 1.12 $
070: */
071: public abstract class NamedStatement {
072:
073: private String description;
074:
075: private String engineVisibility = "public";
076: private String engineMethodsVisibility = "public";
077:
078: protected int order;
079:
080: protected String getDescription() {
081: return description == null ? "" : description;
082: }
083:
084: /**
085: * @param name
086: * @param sql
087: * @param isSingleRow
088: * @throws SQLException
089: */
090: protected NamedStatement(String name, String description,
091: String sql, SQLProcessor processor,
092: GenerationPolicy policy, boolean hasNullableParameters)
093: throws SQLException {
094: super ();
095: this .name = name;
096: this .description = description;
097: this .setSql(sql);
098: Connection con = processor.getConnection();
099: try {
100: String parsedSQL = processor.parse(sql);
101: PreparedStatement ps = con.prepareStatement(parsedSQL);
102: try {
103: processPreparedStatement(policy, hasNullableParameters,
104: ps);
105: } finally {
106: ps.close();
107: }
108: } finally {
109: processor.releaseConnection(con);
110: }
111: }
112:
113: protected NamedStatement(String name, String description,
114: String sql, Collection parameterDescriptors,
115: Collection parameterDescriptors2) {
116: super ();
117: this .name = name;
118: this .description = description;
119: this .setSql(sql);
120: if (parameterDescriptors != null) {
121: this .parameterDescriptors.addAll(parameterDescriptors);
122: }
123:
124: if (parameterDescriptors2 != null) {
125: this .parameterDescriptors2 = new ArrayList(
126: parameterDescriptors2);
127: }
128: }
129:
130: /**
131: * @param policy
132: * @param hasNullableParameters
133: * @param ps
134: * @throws SQLException
135: */
136: protected void processPreparedStatement(GenerationPolicy policy,
137: boolean hasNullableParameters, PreparedStatement ps)
138: throws SQLException {
139: ParameterMetaData pmetadata = ps.getParameterMetaData();
140: for (int i = 1, pc = pmetadata.getParameterCount(); i <= pc; i++) {
141: ParameterDescriptor pd = new ParameterDescriptor();
142: pd.setClassName(pmetadata.getParameterClassName(i));
143: pd.setDbType(pmetadata.getParameterType(i));
144: pd
145: .setNullable(hasNullableParameters
146: && pmetadata.isNullable(i) != ParameterMetaData.parameterNoNulls);
147: pd.setJavaType(policy.getJavaType(pd.getDbType()));
148: pd.setName("p" + i);
149: pd.setLabel(policy.generateLabel(pd.getName()));
150: parameterDescriptors.add(pd);
151: }
152: }
153:
154: protected boolean useSqlTypes;
155:
156: /**
157: * Tells the statement to use setObject(int, Object, int) to set
158: * object fields instead of setObject(int, Object).
159: */
160: public void setUseSqlTypes(boolean useSqlTypes) {
161: this .useSqlTypes = useSqlTypes;
162: }
163:
164: protected String name;
165: protected Collection parameterDescriptors = new ArrayList();
166: private Collection parameterDescriptors2;
167: private String sql;
168:
169: /**
170: * Sets parameter names and types. Useful with not fully compilian JDBC drivers.
171: * @param specification Comma separated list of parameters in Java format, e.g. int a, long b, java.lang.String c.
172: * Type is optional. Class names must be fully qualified. Specifications can be skipped, e.g. int a,,java.lang.String c
173: * Type can include SQL type as defined in java.sql.Types. E.g. int:INTEGER, both sides are optional. Nullability can be
174: * specified using 'nullable' and 'not nullable' modifiers.
175: * Full types grammar looks like: <pre>
176: * parameters = parameter? (, parameter)*
177: * parameter = name | (typeDefinition name ("nullable" | "not nullable")?)
178: * typeDefinition = javaType | (javaType? ":" sqlType?)
179: * </pre>
180: */
181: public void setParameters(String specification)
182: throws GenerationException {
183: String[] params = specification.split(",");
184: if (params.length > parameterDescriptors.size()) {
185: throw new GenerationException(
186: "Invalid number of parameters (" + params.length
187: + "), expected "
188: + parameterDescriptors.size());
189: }
190:
191: Iterator it = parameterDescriptors.iterator();
192: for (int i = 0; i < params.length; i++) {
193: ParameterDescriptor pd = (ParameterDescriptor) it.next();
194: String[] spec = params[i].trim().split("\\s");
195: switch (spec.length) {
196: case 0:
197: break;
198: case 1:
199: if (!blank(spec[0])) {
200: pd.setName(spec[0]);
201: }
202: break;
203: case 2:
204: case 3:
205: case 4:
206: if (blank(spec[0])) {
207: throw new GenerationException("Type is blank in '"
208: + params[i] + "'");
209: }
210:
211: String[] typeSpec = spec[0].trim().split(":");
212: switch (typeSpec.length) {
213: case 1:
214: pd.setJavaType(typeSpec[0]);
215: break;
216: case 2:
217: if (!blank(typeSpec[0])) {
218: pd.setJavaType(typeSpec[0]);
219: }
220:
221: if (!blank(typeSpec[1])) {
222: try {
223: pd.setDbType(((Number) Types.class
224: .getField(typeSpec[1].trim()).get(
225: null)).intValue());
226: } catch (IllegalAccessException e) {
227: throw new GenerationException(
228: "Cannot access SQL type: "
229: + typeSpec[1], e);
230: } catch (NoSuchFieldException e) {
231: throw new GenerationException(
232: "Invalid SQL type: " + typeSpec[1],
233: e);
234: }
235: }
236:
237: break;
238: default:
239: throw new GenerationException(
240: "Invalid parameter specification: "
241: + params[i]);
242: }
243:
244: if (blank(spec[0])) {
245: throw new GenerationException("Name is blank in '"
246: + params[i] + "'");
247: }
248: pd.setName(spec[1]);
249:
250: if (spec.length == 3 && !blank(spec[2])) {
251: if ("nullable".equals(spec[2].trim())) {
252: pd.setNullable(true);
253: } else {
254: throw new GenerationException(
255: "Invalid nullability specifier '"
256: + spec[2].trim()
257: + ", valid values are 'nullable' and 'not nullable'");
258: }
259: }
260:
261: if (spec.length == 4 && !blank(spec[2])
262: && !blank(spec[3])) {
263: if ("not".equals(spec[2].trim())
264: && "nullable".equals(spec[3].trim())) {
265: pd.setNullable(false);
266: } else {
267: throw new GenerationException(
268: "Invalid nullability specifier '"
269: + spec[2].trim()
270: + " "
271: + spec[3].trim()
272: + ", valid values are 'nullable' and 'not nullable'");
273: }
274: }
275:
276: break;
277: default:
278: throw new GenerationException(
279: "Invalid parameter specification: " + params[i]);
280: }
281: }
282: }
283:
284: /**
285: * @param spec
286: * @return
287: */
288: private boolean blank(String str) {
289: return str == null || str.trim().length() == 0;
290: }
291:
292: /**
293: * @param packageName
294: * @param consumer
295: * @param sql
296: * @throws GenerationException
297: */
298: protected void generateEngine(String packageName, Consumer consumer)
299: throws GenerationException {
300: // Factory
301: Class c = new Class(engineVisibility
302: + " class "
303: + ClassGeneratorBase.concat(packageName,
304: generateEngineName()),
305: "Engine class to execute '" + getSql() + "' query",
306: consumer.getListener());
307:
308: generateEngineFields(c, packageName);
309:
310: InstructionFactory iFactory = new InstructionFactory(c
311: .getClassGen());
312:
313: generateEngineStaticInitializer(packageName, c, iFactory);
314: generateEngineConstructor(iFactory, c,
315: getEngineMethodsVisibility());
316: generateEngineMethods(packageName, c);
317: consumer.consume(c.getJavaClass());
318: }
319:
320: protected boolean isToBeGenerated() {
321: Iterator it = columnDescriptors.iterator();
322: int count = 0;
323: while (it.hasNext()) {
324: Object o = it.next();
325: if (!(o instanceof ColumnDescriptor && isSkipColumn((ColumnDescriptor) o))) {
326: count++;
327: }
328: }
329: return count > 1;
330: }
331:
332: protected boolean isSkipColumn(ColumnDescriptor cd) {
333: return false;
334: }
335:
336: /**
337: * @param c
338: * @throws GenerationException
339: */
340: private void generateEngineFields(Class c, String packageName)
341: throws GenerationException {
342: // fields
343: c.addField("_processor", SQLProcessor.class.getName(),
344: "SQL processor", null);
345:
346: if (isToBeGenerated()) {
347: generateImplementationClassField(c, packageName);
348: }
349: }
350:
351: /**
352: * @param c
353: * @throws GenerationException
354: */
355: protected void generateImplementationClassField(Class c,
356: String packageName) throws GenerationException {
357: //Nothing
358: }
359:
360: protected void appendImplementationClassFieldInit(Class c,
361: String packageName, InstructionList target)
362: throws GenerationException {
363: //Nothing
364: }
365:
366: /**
367: * @param packageName
368: * @param c
369: * @param iFactory
370: */
371: protected abstract void generateEngineMethods(String packageName,
372: Class c) throws GenerationException;
373:
374: public abstract void generate(String packageName,
375: Consumer consumer, Class masterEngine)
376: throws GenerationException;
377:
378: private static void generateEngineConstructor(
379: InstructionFactory iFactory, Class c,
380: String engineMethodsVisibility) throws GenerationException {
381: MethodPrototype mp = new MethodPrototype(c,
382: engineMethodsVisibility + " void <init>("
383: + SQLProcessor.class.getName() + " processor)",
384: null);
385:
386: InstructionList il = new InstructionList();
387: il.append(new ALOAD(0));
388: il.append(c.createInvoke("java.lang.Object", "void <init>()",
389: null, Constants.INVOKESPECIAL));
390: il.append(new ALOAD(0));
391: il.append(mp.createVariableLoad("processor"));
392: il.append(c.createPutField("_processor"));
393: il.append(new RETURN());
394: mp.addMethod(il, null, "Constructor");
395: }
396:
397: /**
398: * @param packageName
399: * @param c
400: * @param iFactory
401: * @throws GenerationException
402: */
403: private void generateEngineStaticInitializer(String packageName,
404: Class c, InstructionFactory iFactory)
405: throws GenerationException {
406: InstructionList il = new InstructionList();
407: appendImplementationClassFieldInit(c, packageName, il);
408: il.append(new RETURN());
409: c.addStaticInitializer(il, handleClassNotFoundException(c, il),
410: "Static initializer");
411: }
412:
413: /**
414: * @param packageName
415: * @return
416: */
417: protected String getInterfaceName(String packageName) {
418: throw new UnsupportedOperationException(
419: "This operation is supported only by NamedQuery");
420: }
421:
422: /**
423: * @param packageName
424: * @param consumer
425: * @throws GenerationException
426: */
427: protected void generateParameterizer(String packageName,
428: Consumer consumer, Class engine) throws GenerationException {
429: if (!parameterDescriptors.isEmpty()) {
430: String parameterizerName;
431: if (engine == null) {
432: parameterizerName = ClassGeneratorBase
433: .concat(
434: packageName,
435: generateParameterizerName(generateEngineName()));
436: } else {
437: parameterizerName = generateParameterizerName(engine
438: .getClassGen().getClassName());
439: }
440:
441: Class c = new Class("static class " + parameterizerName
442: + " implements " + Parameterizer.class.getName(),
443: "Inner parameterizer class for '" + name
444: + "' statement", consumer.getListener());
445:
446: //init
447: MethodPrototype mp = new MethodPrototype(c,
448: "void <init>()", parametersWithProperTypes());
449: InstructionList il = new InstructionList();
450: il.append(new ALOAD(0));
451: il.append(c.createInvoke("java.lang.Object",
452: "void <init>()", null, Constants.INVOKESPECIAL));
453:
454: Collection parameters = new LinkedList();
455: Iterator it = parameterDescriptors.iterator();
456: for (int k = 1; it.hasNext(); k++) {
457: Parameter parameter = (Parameter) it.next();
458: parameters.add(parameter);
459: il.append(new ALOAD(0));
460: il.append(mp.createVariableLoad(parameter.getName()));
461: c.addField("_" + parameter.getName(), getParameterType(
462: k, parameter.getType()), "Parameterizer", null);
463: il.append(c.createPutField("_" + parameter.getName()));
464: }
465: il.append(new RETURN());
466:
467: mp.addMethod(il, null, "Constructor");
468:
469: // Parameterize
470: mp = new MethodPrototype(c, "public void parameterize("
471: + PreparedStatement.class.getName()
472: + " ps) throws " + SQLException.class.getName(),
473: null);
474: il = new InstructionList();
475:
476: GOTO[] currentGoto = { null };
477: it = (parameterDescriptors2 == null ? parameterDescriptors
478: : parameterDescriptors2).iterator();
479: for (int k = 1; it.hasNext(); k++) {
480: Parameter parameter = (Parameter) it.next();
481: String parameterType = getParameterType(k, parameter
482: .getType());
483: String setterSignature = ParameterDescriptor
484: .findSetterSignature(parameterType);
485:
486: if (ParameterDescriptor.SET_OBJECT_SIGNATURE
487: .equals(setterSignature)) {
488: if (useSqlTypes && parameter instanceof DbParameter) {
489: generateSetObjectWithSqlType(c, il,
490: currentGoto, k, parameter);
491: } else {
492: generateSetObjectWithNullCheck(c, il,
493: currentGoto, k, parameter);
494: }
495: } else {
496: InstructionHandle h = il.append(new ALOAD(1));
497:
498: if (currentGoto[0] != null) {
499: currentGoto[0].setTarget(h);
500: currentGoto[0] = null;
501: }
502:
503: if (k <= 5) {
504: il.append(new ICONST(k));
505: } else {
506: il.append(new LDC(c.getClassGen()
507: .getConstantPool().addInteger(k)));
508: }
509:
510: il.append(new ALOAD(0));
511: il.append(c.createGetField("_"
512: + parameter.getName()));
513: il.append(c.createInvoke(PreparedStatement.class
514: .getName(), setterSignature, null,
515: Constants.INVOKEINTERFACE));
516: }
517: }
518:
519: InstructionHandle rh = il.append(new RETURN());
520:
521: if (currentGoto[0] != null) {
522: currentGoto[0].setTarget(rh);
523: }
524:
525: mp.addMethod(il, null, "Parameterizes prepared statement");
526:
527: consumer.consume(c.getJavaClass());
528: }
529: }
530:
531: /**
532: * Updates parameter types with values from parameters array.
533: *
534: */
535: protected Collection parametersWithProperTypes() {
536: Collection ret = new ArrayList();
537: Iterator it = parameterDescriptors.iterator();
538: for (int i = 1; it.hasNext(); i++) {
539: final Parameter p = (Parameter) it.next();
540: final int position = i;
541: ret.add(new Parameter() {
542:
543: public String getName() {
544: return p.getName();
545: }
546:
547: public String getType() {
548: return getParameterType(position, p.getType());
549: }
550:
551: });
552: }
553: return ret;
554: }
555:
556: /**
557: * @param c
558: * @param il
559: * @param currentGoto
560: * @param k
561: * @param parameter
562: * @return
563: * @throws GenerationException
564: */
565: private void generateSetObjectWithNullCheck(Class c,
566: InstructionList il, GOTO[] currentGoto, int k,
567: Parameter parameter) throws GenerationException {
568: //* 10 22:aload_0
569: InstructionHandle h = il.append(new ALOAD(0));
570:
571: if (currentGoto[0] != null) {
572: currentGoto[0].setTarget(h);
573: currentGoto[0] = null;
574: }
575: //* 11 23:getfield #25 <Field String _Login>
576: il.append(c.createGetField("_" + parameter.getName()));
577:
578: //* 12 26:ifnonnull 40
579: IFNONNULL ifnonull = new IFNONNULL(null);
580: il.append(ifnonull);
581: // 13 29:aload_1
582: il.append(new ALOAD(1));
583:
584: // 14 30:iconst_3
585: if (k <= 5) {
586: il.append(new ICONST(k));
587: } else {
588: il.append(new LDC(c.getClassGen().getConstantPool()
589: .addInteger(k)));
590: }
591:
592: // 15 31:iconst_0
593: il.append(new LDC(c.getClassGen().getConstantPool().addInteger(
594: java.sql.Types.NULL)));
595:
596: // 16 32:invokeinterface #37 <Method void PreparedStatement.setNull(int, int)>
597: il.append(c.createInvoke(PreparedStatement.class.getName(),
598: "void setNull(int,int)", null,
599: Constants.INVOKEINTERFACE));
600:
601: //* 17 37:goto 51
602: currentGoto[0] = new GOTO(null);
603: il.append(currentGoto[0]);
604: // else
605:
606: // 18 40:aload_1
607: ifnonull.setTarget(il.append(new ALOAD(1)));
608: // 19 41:iconst_3
609: if (k <= 5) {
610: il.append(new ICONST(k));
611: } else {
612: il.append(new LDC(c.getClassGen().getConstantPool()
613: .addInteger(k)));
614: }
615:
616: // 20 42:aload_0
617: il.append(new ALOAD(0));
618: // 21 43:getfield #25 <Field String _Login>
619: il.append(c.createGetField("_" + parameter.getName()));
620: // 22 46:invokeinterface #41 <Method void PreparedStatement.setObject(int, Object)>
621: il.append(c.createInvoke(PreparedStatement.class.getName(),
622: ParameterDescriptor.SET_OBJECT_SIGNATURE, null,
623: Constants.INVOKEINTERFACE));
624: // 23 51:return
625: }
626:
627: /**
628: * @param c
629: * @param il
630: * @param currentGoto
631: * @param k
632: * @param parameter
633: * @return
634: * @throws GenerationException
635: */
636: private void generateSetObjectWithSqlType(Class c,
637: InstructionList il, GOTO[] currentGoto, int k,
638: Parameter parameter) throws GenerationException {
639: //* 10 22:aload_0
640: InstructionHandle h = il.append(new ALOAD(0));
641:
642: if (currentGoto[0] != null) {
643: currentGoto[0].setTarget(h);
644: currentGoto[0] = null;
645: }
646: //* 11 23:getfield #25 <Field String _Login>
647: il.append(c.createGetField("_" + parameter.getName()));
648:
649: //* 12 26:ifnonnull 40
650: IFNONNULL ifnonull = new IFNONNULL(null);
651: il.append(ifnonull);
652: // 13 29:aload_1
653: il.append(new ALOAD(1));
654:
655: // 14 30:iconst_3
656: if (k <= 5) {
657: il.append(new ICONST(k));
658: } else {
659: il.append(new LDC(c.getClassGen().getConstantPool()
660: .addInteger(k)));
661: }
662:
663: int dbType = ((DbParameter) parameter).getDbType();
664:
665: // 15 31:iconst_0
666: il.append(new LDC(c.getClassGen().getConstantPool().addInteger(
667: dbType)));
668:
669: // 16 32:invokeinterface #37 <Method void PreparedStatement.setNull(int, int)>
670: il.append(c.createInvoke(PreparedStatement.class.getName(),
671: "void setNull(int,int)", null,
672: Constants.INVOKEINTERFACE));
673:
674: //* 17 37:goto 51
675: currentGoto[0] = new GOTO(null);
676: il.append(currentGoto[0]);
677: // else
678:
679: // 18 40:aload_1
680: ifnonull.setTarget(il.append(new ALOAD(1)));
681: // 19 41:iconst_3
682: if (k <= 5) {
683: il.append(new ICONST(k));
684: } else {
685: il.append(new LDC(c.getClassGen().getConstantPool()
686: .addInteger(k)));
687: }
688:
689: // 20 42:aload_0
690: il.append(new ALOAD(0));
691: // 21 43:getfield #25 <Field String _Login>
692: il.append(c.createGetField("_" + parameter.getName()));
693:
694: if (dbType >= -1 && dbType <= 5) {
695: il.append(new ICONST(dbType));
696: } else {
697: il.append(new LDC(c.getClassGen().getConstantPool()
698: .addInteger(dbType)));
699: }
700:
701: // 22 46:invokeinterface #41 <Method void PreparedStatement.setObject(int, Object)>
702: il.append(c.createInvoke(PreparedStatement.class.getName(),
703: ParameterDescriptor.SET_OBJECT_SIGNATURE_WITH_TYPE,
704: null, Constants.INVOKEINTERFACE));
705: // 23 51:return
706: }
707:
708: /**
709: * @param packageName
710: * @return
711: */
712: protected String generateParameterizerName(String engineName) {
713: return engineName + "$" + name + "Parameterizer" + "_" + order;
714: }
715:
716: /**
717: * @param packageName
718: * @return
719: */
720: protected String generateEngineName() {
721: return name + "Engine";
722: }
723:
724: /**
725: * Generates classes for statements and places all engine methods in masterEngine class.
726: * @param packageName
727: * @param masterEngine
728: * @param statements
729: * @throws GenerationException
730: */
731: public static void generate(String packageName,
732: String masterEngineName, String engineVisibility,
733: String engineMethodsVisibility, Collection statements,
734: Collection interfaces, Consumer consumer)
735: throws GenerationException {
736: Class masterEngine = masterEngineName == null ? null
737: : new Class(engineVisibility
738: + " class "
739: + ClassGeneratorBase.concat(packageName,
740: masterEngineName),
741: "Master engine class", consumer.getListener());
742:
743: InterfacePool pool = new InterfacePool();
744: Iterator it = interfaces.iterator();
745: while (it.hasNext()) {
746: pool.addInterface((java.lang.Class) it.next());
747: }
748:
749: Set names = new HashSet();
750: it = statements.iterator();
751: for (int order = 0; it.hasNext(); order++) {
752: NamedStatement next = (NamedStatement) it.next();
753: next.order = order;
754:
755: if (masterEngine == null && !names.add(next.name)) {
756: throw new GenerationException(
757: "Duplicate statement name: " + next.name);
758: }
759:
760: if (next instanceof NamedInterfaceGeneratingStatement) {
761: ((NamedInterfaceGeneratingStatement) next)
762: .setInterfacePool(pool);
763: }
764: }
765:
766: pool.addInterface(DomSerializable.class);
767: pool.discoverCommonDenominators();
768:
769: if (masterEngine != null) {
770: // fields
771: masterEngine.addField("_processor", SQLProcessor.class
772: .getName(), "SQL processor", null);
773:
774: InstructionFactory iFactory = new InstructionFactory(
775: masterEngine.getClassGen());
776: generateEngineConstructor(iFactory, masterEngine,
777: engineMethodsVisibility);
778:
779: InstructionList il = new InstructionList();
780:
781: it = statements.iterator();
782: while (it.hasNext()) {
783: NamedStatement namedStatement = (NamedStatement) it
784: .next();
785: if (namedStatement.isToBeGenerated()) {
786: namedStatement.generateImplementationClassField(
787: masterEngine, packageName);
788: namedStatement.appendImplementationClassFieldInit(
789: masterEngine, packageName, il);
790: }
791: }
792: il.append(new RETURN());
793:
794: masterEngine.addStaticInitializer(il,
795: handleClassNotFoundException(masterEngine, il),
796: "Static initializer");
797:
798: il.dispose();
799: }
800:
801: pool.generateCommonDenominators(packageName, consumer);
802:
803: it = statements.iterator();
804: while (it.hasNext()) {
805: ((NamedStatement) it.next()).generate(packageName,
806: consumer, masterEngine);
807: }
808:
809: if (masterEngine != null) {
810: consumer.consume(masterEngine.getJavaClass());
811: }
812: }
813:
814: /**
815: * @param c
816: * @param il
817: * @return
818: * @throws GenerationException
819: */
820: private static Collection handleClassNotFoundException(Class c,
821: InstructionList il) throws GenerationException {
822: Collection ehc = new ArrayList();
823: ExceptionHandler eh = new ExceptionHandler(
824: ClassNotFoundException.class.getName());
825: eh.setFrom(il.getStart());
826: eh.setTo(il.getEnd());
827: //* 7 19:astore_0
828: eh.setHandler(il.append(new ASTORE(0)));
829: // 8 20:new #30 <Class NoClassDefFoundError>
830: il.append(c.getInstructionFactory().createNew(
831: NoClassDefFoundError.class.getName()));
832: // 9 23:dup
833: il.append(new DUP());
834: // 10 24:aload_0
835: il.append(new ALOAD(0));
836: // 11 25:invokevirtual #36 <Method String ClassNotFoundException.getMessage()>
837: il.append(c.createInvoke(
838: ClassNotFoundException.class.getName(),
839: "java.lang.String getMessage()", null,
840: Constants.INVOKEVIRTUAL));
841: // 12 28:invokespecial #40 <Method void NoClassDefFoundError(String)>
842: il.append(c.createInvoke(NoClassDefFoundError.class.getName(),
843: "void <init>(java.lang.String)", null,
844: Constants.INVOKESPECIAL));
845: // 13 31:athrow
846: il.append(new ATHROW());
847: ehc.add(eh);
848: return ehc;
849: }
850:
851: protected Collection columnDescriptors = new ArrayList();
852:
853: private ArrayList paramTypes = new ArrayList();
854:
855: protected String getParameterType(int position, String defaultType) {
856: if (position < paramTypes.size()) {
857: String ret = (String) paramTypes.get(position - 1);
858: return ret == null ? defaultType : ret;
859: }
860:
861: return defaultType;
862: }
863:
864: public void setParamType(int position, String type)
865: throws GenerationException {
866: if (position > 0) {
867: while (paramTypes.size() < position) {
868: paramTypes.add(null);
869: }
870: paramTypes.set(position - 1, type);
871: } else {
872: throw new GenerationException(
873: "Invalid parameter position: " + position);
874: }
875: }
876:
877: public String getEngineVisibility() {
878: return engineVisibility;
879: }
880:
881: public void setEngineVisibility(String engineVisibility) {
882: this .engineVisibility = engineVisibility;
883: }
884:
885: public String getEngineMethodsVisibility() {
886: return engineMethodsVisibility;
887: }
888:
889: public void setEngineMethodsVisibility(
890: String engineMethodsVisibility) {
891: this .engineMethodsVisibility = engineMethodsVisibility;
892: }
893:
894: /**
895: * @param sql The sql to set.
896: */
897: private void setSql(String sql) {
898: // Normalize sql - replace \t and \n and \r with spaces,
899: // remove trailing and leading spaces.
900: boolean inSpace = false;
901: StringBuffer sb = new StringBuffer();
902: for (int i = 0; i < sql.length(); i++) {
903: char curChar = sql.charAt(i);
904: switch (curChar) {
905: case '\n':
906: case '\r':
907: case '\t':
908: if (!inSpace) {
909: sb.append(" ");
910: inSpace = true;
911: }
912: break;
913: case ' ':
914: inSpace = true;
915: sb.append(curChar);
916: break;
917: default:
918: inSpace = false;
919: sb.append(curChar);
920: }
921: }
922:
923: this .sql = sb.toString().trim();
924: }
925:
926: /**
927: * @return Returns the sql.
928: */
929: protected String getSql() {
930: return sql;
931: }
932: }
|