0001: /*
0002: * Distributed as part of c3p0 v.0.9.1.2
0003: *
0004: * Copyright (C) 2005 Machinery For Change, Inc.
0005: *
0006: * Author: Steve Waldman <swaldman@mchange.com>
0007: *
0008: * This library is free software; you can redistribute it and/or modify
0009: * it under the terms of the GNU Lesser General Public License version 2.1, as
0010: * published by the Free Software Foundation.
0011: *
0012: * This software is distributed in the hope that it will be useful,
0013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0015: * GNU Lesser General Public License for more details.
0016: *
0017: * You should have received a copy of the GNU Lesser General Public License
0018: * along with this software; see the file LICENSE. If not, write to the
0019: * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
0020: * Boston, MA 02111-1307, USA.
0021: */
0022:
0023: package com.mchange.v2.c3p0.codegen;
0024:
0025: import java.io.*;
0026: import java.lang.reflect.*;
0027: import java.sql.*;
0028: import com.mchange.v2.codegen.*;
0029: import com.mchange.v2.codegen.intfc.*;
0030: import com.mchange.v2.c3p0.C3P0ProxyConnection;
0031: import com.mchange.v2.c3p0.C3P0ProxyStatement;
0032:
0033: public abstract class JdbcProxyGenerator extends DelegatorGenerator {
0034: final static boolean PREMATURE_DETACH_DEBUG = false;
0035:
0036: JdbcProxyGenerator() {
0037: this .setGenerateInnerSetter(false);
0038: this .setGenerateInnerGetter(false);
0039: this .setGenerateNoArgConstructor(false);
0040: this .setGenerateWrappingConstructor(true);
0041: this .setClassModifiers(Modifier.PUBLIC | Modifier.FINAL);
0042: this .setMethodModifiers(Modifier.PUBLIC | Modifier.FINAL);
0043: }
0044:
0045: abstract String getInnerTypeName();
0046:
0047: static final class NewProxyMetaDataGenerator extends
0048: JdbcProxyGenerator {
0049: String getInnerTypeName() {
0050: return "DatabaseMetaData";
0051: }
0052:
0053: protected void generateDelegateCode(Class intfcl,
0054: String genclass, Method method, IndentedWriter iw)
0055: throws IOException {
0056: String mname = method.getName();
0057: Class retType = method.getReturnType();
0058:
0059: if (ResultSet.class.isAssignableFrom(retType)) {
0060: iw.println("ResultSet innerResultSet = inner."
0061: + CodegenUtils.methodCall(method) + ";");
0062: iw.println("if (innerResultSet == null) return null;");
0063: iw
0064: .println("return new NewProxyResultSet( innerResultSet, parentPooledConnection, inner, this );");
0065: } else if (mname.equals("getConnection")) {
0066: iw.println("return this.proxyCon;");
0067: } else
0068: super
0069: .generateDelegateCode(intfcl, genclass, method,
0070: iw);
0071: }
0072:
0073: protected void generatePreDelegateCode(Class intfcl,
0074: String genclass, Method method, IndentedWriter iw)
0075: throws IOException {
0076: if (method.getExceptionTypes().length > 0)
0077: super .generatePreDelegateCode(intfcl, genclass, method,
0078: iw);
0079: }
0080:
0081: protected void generatePostDelegateCode(Class intfcl,
0082: String genclass, Method method, IndentedWriter iw)
0083: throws IOException {
0084: if (method.getExceptionTypes().length > 0)
0085: super .generatePostDelegateCode(intfcl, genclass,
0086: method, iw);
0087: }
0088:
0089: protected void generateExtraDeclarations(Class intfcl,
0090: String genclass, IndentedWriter iw) throws IOException {
0091: super .generateExtraDeclarations(intfcl, genclass, iw);
0092: iw.println();
0093: iw.println("NewProxyConnection proxyCon;");
0094: iw.println();
0095: iw.print(CodegenUtils.fqcnLastElement(genclass));
0096: iw
0097: .println("( "
0098: + CodegenUtils.simpleClassName(intfcl)
0099: + " inner, NewPooledConnection parentPooledConnection, NewProxyConnection proxyCon )");
0100: iw.println("{");
0101: iw.upIndent();
0102: iw.println("this( inner, parentPooledConnection );");
0103: iw.println("this.proxyCon = proxyCon;");
0104: iw.downIndent();
0105: iw.println("}");
0106: }
0107: }
0108:
0109: static final class NewProxyResultSetGenerator extends
0110: JdbcProxyGenerator {
0111: String getInnerTypeName() {
0112: return "ResultSet";
0113: }
0114:
0115: protected void generateDelegateCode(Class intfcl,
0116: String genclass, Method method, IndentedWriter iw)
0117: throws IOException {
0118: iw
0119: .println("if (proxyConn != null) proxyConn.maybeDirtyTransaction();");
0120: iw.println();
0121: String mname = method.getName();
0122: Class retType = method.getReturnType();
0123:
0124: if (mname.equals("close")) {
0125: iw.println("if (! this.isDetached())");
0126: iw.println("{");
0127: iw.upIndent();
0128:
0129: iw.println("if (creator instanceof Statement)");
0130: iw.upIndent();
0131: iw
0132: .println("parentPooledConnection.markInactiveResultSetForStatement( (Statement) creator, inner );");
0133: iw.downIndent();
0134: iw
0135: .println("else if (creator instanceof DatabaseMetaData)");
0136: iw.upIndent();
0137: iw
0138: .println("parentPooledConnection.markInactiveMetaDataResultSet( inner );");
0139: iw.downIndent();
0140: iw.println("else if (creator instanceof Connection)");
0141: iw.upIndent();
0142: iw
0143: .println("parentPooledConnection.markInactiveRawConnectionResultSet( inner );");
0144: iw.downIndent();
0145: iw
0146: .println("else throw new InternalError(\042Must be Statement or DatabaseMetaData -- Bad Creator: \042 + creator);");
0147:
0148: iw.println("this.detach();");
0149: iw.println("inner.close();");
0150: iw.println("this.inner = null;");
0151:
0152: iw.downIndent();
0153: iw.println("}");
0154: } else if (mname.equals("getStatement")) {
0155: iw.println("if (creator instanceof Statement)");
0156: iw.upIndent();
0157: iw.println("return (Statement) creatorProxy;");
0158: iw.downIndent();
0159: iw
0160: .println("else if (creator instanceof DatabaseMetaData)");
0161: iw.upIndent();
0162: iw.println("return null;");
0163: iw.downIndent();
0164: iw
0165: .println("else throw new InternalError(\042Must be Statement or DatabaseMetaData -- Bad Creator: \042 + creator);");
0166: } else if (mname.equals("isClosed")) {
0167: iw.println("return this.isDetached();");
0168: } else
0169: super
0170: .generateDelegateCode(intfcl, genclass, method,
0171: iw);
0172: }
0173:
0174: protected void generateExtraDeclarations(Class intfcl,
0175: String genclass, IndentedWriter iw) throws IOException {
0176: super .generateExtraDeclarations(intfcl, genclass, iw);
0177: iw.println();
0178: iw.println("Object creator;");
0179: iw.println("Object creatorProxy;");
0180: iw.println("NewProxyConnection proxyConn;");
0181: iw.println();
0182: iw.print(CodegenUtils.fqcnLastElement(genclass));
0183: iw
0184: .println("( "
0185: + CodegenUtils.simpleClassName(intfcl)
0186: + " inner, NewPooledConnection parentPooledConnection, Object c, Object cProxy )");
0187: iw.println("{");
0188: iw.upIndent();
0189: iw.println("this( inner, parentPooledConnection );");
0190: iw.println("this.creator = c;");
0191: iw.println("this.creatorProxy = cProxy;");
0192: iw
0193: .println("if (creatorProxy instanceof NewProxyConnection) this.proxyConn = (NewProxyConnection) cProxy;");
0194: iw.downIndent();
0195: iw.println("}");
0196: }
0197:
0198: protected void generatePreDelegateCode(Class intfcl,
0199: String genclass, Method method, IndentedWriter iw)
0200: throws IOException {
0201: super .generatePreDelegateCode(intfcl, genclass, method, iw);
0202: }
0203: }
0204:
0205: static final class NewProxyAnyStatementGenerator extends
0206: JdbcProxyGenerator {
0207: String getInnerTypeName() {
0208: return "Statement";
0209: }
0210:
0211: private final static boolean CONCURRENT_ACCESS_DEBUG = false;
0212:
0213: {
0214: this
0215: .setExtraInterfaces(new Class[] { C3P0ProxyStatement.class });
0216: }
0217:
0218: protected void generateDelegateCode(Class intfcl,
0219: String genclass, Method method, IndentedWriter iw)
0220: throws IOException {
0221: iw.println("maybeDirtyTransaction();");
0222: iw.println();
0223:
0224: String mname = method.getName();
0225: Class retType = method.getReturnType();
0226:
0227: if (ResultSet.class.isAssignableFrom(retType)) {
0228: iw.println("ResultSet innerResultSet = inner."
0229: + CodegenUtils.methodCall(method) + ";");
0230: iw.println("if (innerResultSet == null) return null;");
0231: iw
0232: .println("parentPooledConnection.markActiveResultSetForStatement( inner, innerResultSet );");
0233: iw
0234: .println("return new NewProxyResultSet( innerResultSet, parentPooledConnection, inner, this );");
0235: } else if (mname.equals("getConnection")) {
0236: iw.println("if (! this.isDetached())");
0237: iw.upIndent();
0238: iw.println("return creatorProxy;");
0239: iw.downIndent();
0240: iw.println("else");
0241: iw.upIndent();
0242: iw
0243: .println("throw new SQLException(\"You cannot operate on a closed Statement!\");");
0244: iw.downIndent();
0245: } else if (mname.equals("close")) {
0246: iw.println("if (! this.isDetached())");
0247: iw.println("{");
0248: iw.upIndent();
0249:
0250: iw.println("if ( is_cached )");
0251: iw.upIndent();
0252: iw
0253: .println("parentPooledConnection.checkinStatement( inner );");
0254: iw.downIndent();
0255: iw.println("else");
0256: iw.println("{");
0257: iw.upIndent();
0258: iw
0259: .println("parentPooledConnection.markInactiveUncachedStatement( inner );");
0260:
0261: iw.println("try{ inner.close(); }");
0262: iw.println("catch (Exception e )");
0263: iw.println("{");
0264: iw.upIndent();
0265:
0266: iw.println("if (logger.isLoggable( MLevel.WARNING ))");
0267: iw.upIndent();
0268: iw
0269: .println("logger.log( MLevel.WARNING, \042Exception on close of inner statement.\042, e);");
0270: iw.downIndent();
0271:
0272: iw
0273: .println("SQLException sqle = SqlUtils.toSQLException( e );");
0274: iw.println("throw sqle;");
0275: iw.downIndent();
0276: iw.println("}");
0277: iw.downIndent();
0278: iw.println("}");
0279:
0280: iw.println();
0281: iw.println("this.detach();");
0282: iw.println("this.inner = null;");
0283: iw.println("this.creatorProxy = null;");
0284:
0285: iw.downIndent();
0286: iw.println("}");
0287: } else if (mname.equals("isClosed")) {
0288: iw.println("return this.isDetached();");
0289: } else
0290: super
0291: .generateDelegateCode(intfcl, genclass, method,
0292: iw);
0293: }
0294:
0295: protected void generatePreDelegateCode(Class intfcl,
0296: String genclass, Method method, IndentedWriter iw)
0297: throws IOException {
0298: // concurrent-access-debug only
0299: if (CONCURRENT_ACCESS_DEBUG) {
0300: iw.println("Object record;");
0301: iw.println("synchronized (concurrentAccessRecorder)");
0302: iw.println("{");
0303: iw.upIndent();
0304:
0305: iw
0306: .println("record = concurrentAccessRecorder.record();");
0307: iw
0308: .println("int num_concurrent_clients = concurrentAccessRecorder.size();");
0309: iw.println("if (num_concurrent_clients != 1)");
0310: iw.upIndent();
0311: iw
0312: .println("logger.log(MLevel.WARNING, "
0313: + "concurrentAccessRecorder.getDump(\042Apparent concurrent access! (\042 + num_concurrent_clients + \042 clients.\042) );");
0314: iw.downIndent();
0315: iw.downIndent();
0316: iw.println("}");
0317: iw.println();
0318: }
0319: // end concurrent-access-debug only
0320:
0321: super .generatePreDelegateCode(intfcl, genclass, method, iw);
0322: }
0323:
0324: protected void generatePostDelegateCode(Class intfcl,
0325: String genclass, Method method, IndentedWriter iw)
0326: throws IOException {
0327: super
0328: .generatePostDelegateCode(intfcl, genclass, method,
0329: iw);
0330:
0331: // concurrent-access-debug only
0332: if (CONCURRENT_ACCESS_DEBUG) {
0333: iw.println("finally");
0334: iw.println("{");
0335: iw.upIndent();
0336: iw
0337: .println("concurrentAccessRecorder.remove( record );");
0338: iw.downIndent();
0339: iw.println("}");
0340: }
0341: // end concurrent-access-debug only
0342: }
0343:
0344: protected void generateExtraDeclarations(Class intfcl,
0345: String genclass, IndentedWriter iw) throws IOException {
0346: super .generateExtraDeclarations(intfcl, genclass, iw);
0347: iw.println();
0348:
0349: // concurrent-access-debug only!
0350: if (CONCURRENT_ACCESS_DEBUG) {
0351: iw
0352: .println("com.mchange.v2.debug.ThreadNameStackTraceRecorder concurrentAccessRecorder");
0353: iw.upIndent();
0354: iw
0355: .println("= new com.mchange.v2.debug.ThreadNameStackTraceRecorder(\042Concurrent Access Recorder\042);");
0356: iw.downIndent();
0357: }
0358: // end concurrent-access-debug only!
0359:
0360: iw.println("boolean is_cached;");
0361: iw.println("NewProxyConnection creatorProxy;");
0362: iw.println();
0363: iw.print(CodegenUtils.fqcnLastElement(genclass));
0364: iw
0365: .println("( "
0366: + CodegenUtils.simpleClassName(intfcl)
0367: + " inner, NewPooledConnection parentPooledConnection, boolean cached, NewProxyConnection cProxy )");
0368: iw.println("{");
0369: iw.upIndent();
0370: iw.println("this( inner, parentPooledConnection );");
0371: iw.println("this.is_cached = cached;");
0372: iw.println("this.creatorProxy = cProxy;");
0373: iw.downIndent();
0374: iw.println("}");
0375: iw.println();
0376: iw
0377: .println("public Object rawStatementOperation(Method m, Object target, Object[] args) "
0378: + "throws IllegalAccessException, InvocationTargetException, SQLException");
0379: iw.println("{");
0380: iw.upIndent();
0381: iw.println("maybeDirtyTransaction();");
0382: iw.println();
0383: iw
0384: .println("if (target == C3P0ProxyStatement.RAW_STATEMENT) target = inner;");
0385: iw
0386: .println("for (int i = 0, len = args.length; i < len; ++i)");
0387: iw.upIndent();
0388: iw
0389: .println("if (args[i] == C3P0ProxyStatement.RAW_STATEMENT) args[i] = inner;");
0390: iw.downIndent();
0391: iw.println("Object out = m.invoke(target, args);");
0392: iw.println("if (out instanceof ResultSet)");
0393: iw.println("{");
0394: iw.upIndent();
0395: iw.println("ResultSet innerResultSet = (ResultSet) out;");
0396: iw
0397: .println("parentPooledConnection.markActiveResultSetForStatement( inner, innerResultSet );");
0398: iw
0399: .println("out = new NewProxyResultSet( innerResultSet, parentPooledConnection, inner, this );");
0400: iw.downIndent();
0401: iw.println("}");
0402: iw.println();
0403: iw.println("return out;");
0404: iw.downIndent();
0405: iw.println("}");
0406: iw.println();
0407: iw.println("void maybeDirtyTransaction()");
0408: iw.println("{ creatorProxy.maybeDirtyTransaction(); }");
0409: }
0410:
0411: protected void generateExtraImports(IndentedWriter iw)
0412: throws IOException {
0413: super .generateExtraImports(iw);
0414: iw
0415: .println("import java.lang.reflect.InvocationTargetException;");
0416: }
0417:
0418: }
0419:
0420: // protected void generateExtraDeclarations( Class intfcl, String genclass, IndentedWriter iw ) throws IOException
0421: // {
0422: // super.generateExtraDeclarations( intfcl, genclass, iw );
0423: // iw.println();
0424: // iw.println("Statement creatingStatement;");
0425: // iw.println();
0426: // iw.print( CodegenUtils.fqcnLastElement( genclass ) );
0427: // iw.println("( " + CodegenUtils.simpleClassName( intfcl.getClass() ) + " inner, NewPooledConnection parentPooledConnection, Statement stmt )");
0428: // iw.println("{");
0429: // iw.upIndent();
0430: // iw.println("this( inner, parentPooledConnection );");
0431: // iw.println("this.creatingStatement = stmt;");
0432: // iw.downIndent();
0433: // iw.println("}");
0434: // }
0435:
0436: static final class NewProxyConnectionGenerator extends
0437: JdbcProxyGenerator {
0438: String getInnerTypeName() {
0439: return "Connection";
0440: }
0441:
0442: {
0443: this .setMethodModifiers(Modifier.PUBLIC
0444: | Modifier.SYNCHRONIZED);
0445: this
0446: .setExtraInterfaces(new Class[] { C3P0ProxyConnection.class });
0447: }
0448:
0449: protected void generateDelegateCode(Class intfcl,
0450: String genclass, Method method, IndentedWriter iw)
0451: throws IOException {
0452: String mname = method.getName();
0453: if (mname.equals("createStatement")) {
0454: iw.println("txn_known_resolved = false;");
0455: iw.println();
0456: iw.println("Statement innerStmt = inner."
0457: + CodegenUtils.methodCall(method) + ";");
0458: iw
0459: .println("parentPooledConnection.markActiveUncachedStatement( innerStmt );");
0460: iw
0461: .println("return new NewProxyStatement( innerStmt, parentPooledConnection, false, this );");
0462: } else if (mname.equals("prepareStatement")) {
0463: iw.println("txn_known_resolved = false;");
0464: iw.println();
0465: iw.println("PreparedStatement innerStmt;");
0466: iw.println();
0467: iw
0468: .println("if ( parentPooledConnection.isStatementCaching() )");
0469: iw.println("{");
0470: iw.upIndent();
0471:
0472: iw.println("try");
0473: iw.println("{");
0474: iw.upIndent();
0475:
0476: generateFindMethodAndArgs(method, iw);
0477: iw
0478: .println("innerStmt = (PreparedStatement) parentPooledConnection.checkoutStatement( method, args );");
0479: iw
0480: .println("return new NewProxyPreparedStatement( innerStmt, parentPooledConnection, true, this );");
0481:
0482: iw.downIndent();
0483: iw.println("}");
0484: iw.println("catch (ResourceClosedException e)");
0485: iw.println("{");
0486: iw.upIndent();
0487:
0488: iw.println("if ( logger.isLoggable( MLevel.FINE ) )");
0489: iw.upIndent();
0490: iw
0491: .println("logger.log( MLevel.FINE, "
0492: + "\042A Connection tried to prepare a Statement via a Statement cache that is already closed. "
0493: + "This can happen -- rarely -- if a DataSource is closed or reset() while Connections are checked-out and in use.\042, e );");
0494: iw.downIndent();
0495:
0496: // repeated code... any changes probably need to be duplicated below
0497: iw.println("innerStmt = inner."
0498: + CodegenUtils.methodCall(method) + ";");
0499: iw
0500: .println("parentPooledConnection.markActiveUncachedStatement( innerStmt );");
0501: iw
0502: .println("return new NewProxyPreparedStatement( innerStmt, parentPooledConnection, false, this );");
0503:
0504: iw.downIndent();
0505: iw.println("}");
0506:
0507: iw.downIndent();
0508: iw.println("}");
0509: iw.println("else");
0510: iw.println("{");
0511: iw.upIndent();
0512:
0513: // repeated code... any changes probably need to be duplicated above
0514: iw.println("innerStmt = inner."
0515: + CodegenUtils.methodCall(method) + ";");
0516: iw
0517: .println("parentPooledConnection.markActiveUncachedStatement( innerStmt );");
0518: iw
0519: .println("return new NewProxyPreparedStatement( innerStmt, parentPooledConnection, false, this );");
0520:
0521: iw.downIndent();
0522: iw.println("}");
0523:
0524: } else if (mname.equals("prepareCall")) {
0525: iw.println("txn_known_resolved = false;");
0526: iw.println();
0527: iw.println("CallableStatement innerStmt;");
0528: iw.println();
0529: iw
0530: .println("if ( parentPooledConnection.isStatementCaching() )");
0531: iw.println("{");
0532: iw.upIndent();
0533:
0534: iw.println("try");
0535: iw.println("{");
0536: iw.upIndent();
0537:
0538: generateFindMethodAndArgs(method, iw);
0539: iw
0540: .println("innerStmt = (CallableStatement) parentPooledConnection.checkoutStatement( method, args );");
0541: iw
0542: .println("return new NewProxyCallableStatement( innerStmt, parentPooledConnection, true, this );");
0543:
0544: iw.downIndent();
0545: iw.println("}");
0546: iw.println("catch (ResourceClosedException e)");
0547: iw.println("{");
0548: iw.upIndent();
0549:
0550: iw.println("if ( logger.isLoggable( MLevel.FINE ) )");
0551: iw.upIndent();
0552: iw
0553: .println("logger.log( MLevel.FINE, "
0554: + "\042A Connection tried to prepare a CallableStatement via a Statement cache that is already closed. "
0555: + "This can happen -- rarely -- if a DataSource is closed or reset() while Connections are checked-out and in use.\042, e );");
0556: iw.downIndent();
0557:
0558: // repeated code... any changes probably need to be duplicated below
0559: iw.println("innerStmt = inner."
0560: + CodegenUtils.methodCall(method) + ";");
0561: iw
0562: .println("parentPooledConnection.markActiveUncachedStatement( innerStmt );");
0563: iw
0564: .println("return new NewProxyCallableStatement( innerStmt, parentPooledConnection, false, this );");
0565:
0566: iw.downIndent();
0567: iw.println("}");
0568:
0569: iw.downIndent();
0570: iw.println("}");
0571: iw.println("else");
0572: iw.println("{");
0573: iw.upIndent();
0574:
0575: // repeated code... any changes probably need to be duplicated above
0576: iw.println("innerStmt = inner."
0577: + CodegenUtils.methodCall(method) + ";");
0578: iw
0579: .println("parentPooledConnection.markActiveUncachedStatement( innerStmt );");
0580: iw
0581: .println("return new NewProxyCallableStatement( innerStmt, parentPooledConnection, false, this );");
0582:
0583: iw.downIndent();
0584: iw.println("}");
0585:
0586: } else if (mname.equals("getMetaData")) {
0587: iw.println("txn_known_resolved = false;");
0588: iw.println();
0589: iw.println("if (this.metaData == null)");
0590: iw.println("{");
0591: iw.upIndent();
0592: iw.println("DatabaseMetaData innerMetaData = inner."
0593: + CodegenUtils.methodCall(method) + ";");
0594: iw
0595: .println("this.metaData = new NewProxyDatabaseMetaData( innerMetaData, parentPooledConnection, this );");
0596: iw.downIndent();
0597: iw.println("}");
0598: iw.println("return this.metaData;");
0599: } else if (mname.equals("setTransactionIsolation")) {
0600: //do nothing with txn_known_resolved
0601:
0602: super
0603: .generateDelegateCode(intfcl, genclass, method,
0604: iw);
0605: iw
0606: .println("parentPooledConnection.markNewTxnIsolation( "
0607: + CodegenUtils.generatedArgumentName(0)
0608: + " );");
0609: } else if (mname.equals("setCatalog")) {
0610: //do nothing with txn_known_resolved
0611:
0612: super
0613: .generateDelegateCode(intfcl, genclass, method,
0614: iw);
0615: iw
0616: .println("parentPooledConnection.markNewCatalog( "
0617: + CodegenUtils.generatedArgumentName(0)
0618: + " );");
0619: } else if (mname.equals("setHoldability")) {
0620: //do nothing with txn_known_resolved
0621:
0622: super
0623: .generateDelegateCode(intfcl, genclass, method,
0624: iw);
0625: iw
0626: .println("parentPooledConnection.markNewHoldability( "
0627: + CodegenUtils.generatedArgumentName(0)
0628: + " );");
0629: } else if (mname.equals("setReadOnly")) {
0630: //do nothing with txn_known_resolved
0631:
0632: super
0633: .generateDelegateCode(intfcl, genclass, method,
0634: iw);
0635: iw
0636: .println("parentPooledConnection.markNewReadOnly( "
0637: + CodegenUtils.generatedArgumentName(0)
0638: + " );");
0639: } else if (mname.equals("setTypeMap")) {
0640: //do nothing with txn_known_resolved
0641:
0642: super
0643: .generateDelegateCode(intfcl, genclass, method,
0644: iw);
0645: iw
0646: .println("parentPooledConnection.markNewTypeMap( "
0647: + CodegenUtils.generatedArgumentName(0)
0648: + " );");
0649: } else if (mname.equals("close")) {
0650: iw.println("if (! this.isDetached())");
0651: iw.println("{");
0652: iw.upIndent();
0653: iw
0654: .println("NewPooledConnection npc = parentPooledConnection;");
0655: iw.println("this.detach();");
0656: iw
0657: .println("npc.markClosedProxyConnection( this, txn_known_resolved );");
0658: iw.println("this.inner = null;");
0659: iw.downIndent();
0660: iw.println("}");
0661: iw
0662: .println("else if (Debug.DEBUG && logger.isLoggable( MLevel.FINE ))");
0663: iw.println("{");
0664: iw.upIndent();
0665: iw
0666: .println("logger.log( MLevel.FINE, this + \042: close() called more than once.\042 );");
0667:
0668: // premature-detach-debug-debug only!
0669: if (PREMATURE_DETACH_DEBUG) {
0670: iw.println("prematureDetachRecorder.record();");
0671: iw
0672: .println("logger.warning( prematureDetachRecorder.getDump(\042Apparent multiple close of "
0673: + getInnerTypeName() + ".\042) );");
0674: }
0675: // end-premature-detach-debug-only!
0676:
0677: iw.downIndent();
0678: iw.println("}");
0679: } else if (mname.equals("isClosed")) {
0680: iw.println("return this.isDetached();");
0681: } else {
0682: iw.println("txn_known_resolved = "
0683: + (mname.equals("commit")
0684: || mname.equals("rollback") || mname
0685: .equals("setAutoCommit")) + ';');
0686: iw.println();
0687: super
0688: .generateDelegateCode(intfcl, genclass, method,
0689: iw);
0690: }
0691: }
0692:
0693: protected void generateExtraDeclarations(Class intfcl,
0694: String genclass, IndentedWriter iw) throws IOException {
0695: iw.println("boolean txn_known_resolved = true;");
0696: iw.println();
0697: iw.println("DatabaseMetaData metaData = null;");
0698: iw.println();
0699:
0700: // We've nothing to do with preferredTestQuery here... the stuff below was unnecessary
0701:
0702: // iw.println("String preferredTestQuery = null;");
0703: // iw.println();
0704: // iw.print( CodegenUtils.fqcnLastElement( genclass ) );
0705: // iw.println("( " + CodegenUtils.simpleClassName( intfcl ) + " inner, NewPooledConnection parentPooledConnection, String preferredTestQuery )");
0706: // iw.println("{");
0707: // iw.upIndent();
0708: // iw.println("this( inner, parentPooledConnection );");
0709: // iw.println("this.preferredTestQuery = preferredTestQuery;");
0710: // iw.downIndent();
0711: // iw.println("}");
0712: // iw.println();
0713:
0714: iw
0715: .println("public Object rawConnectionOperation(Method m, Object target, Object[] args)");
0716: iw.upIndent();
0717: iw
0718: .println("throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, SQLException");
0719: iw.downIndent();
0720: iw.println("{");
0721: iw.upIndent();
0722: iw.println("maybeDirtyTransaction();");
0723: iw.println();
0724: iw.println("if (inner == null)");
0725: iw.upIndent();
0726: iw
0727: .println("throw new SQLException(\"You cannot operate on a closed Connection!\");");
0728: iw.downIndent();
0729:
0730: iw
0731: .println("if ( target == C3P0ProxyConnection.RAW_CONNECTION)");
0732: iw.upIndent();
0733: iw.println("target = inner;");
0734: iw.downIndent();
0735:
0736: iw
0737: .println("for (int i = 0, len = args.length; i < len; ++i)");
0738: iw.upIndent();
0739: iw
0740: .println("if (args[i] == C3P0ProxyConnection.RAW_CONNECTION)");
0741: iw.upIndent();
0742: iw.println("args[i] = inner;");
0743: iw.downIndent();
0744: iw.downIndent();
0745:
0746: iw.println("Object out = m.invoke( target, args );");
0747: iw.println();
0748: iw
0749: .println("// we never cache Statements generated by an operation on the raw Connection");
0750: iw.println("if (out instanceof CallableStatement)");
0751: iw.println("{");
0752: iw.upIndent();
0753: iw
0754: .println("CallableStatement innerStmt = (CallableStatement) out;");
0755: iw
0756: .println("parentPooledConnection.markActiveUncachedStatement( innerStmt );");
0757: iw
0758: .println("out = new NewProxyCallableStatement( innerStmt, parentPooledConnection, false, this );");
0759: iw.downIndent();
0760: iw.println("}");
0761: iw.println("else if (out instanceof PreparedStatement)");
0762: iw.println("{");
0763: iw.upIndent();
0764: iw
0765: .println("PreparedStatement innerStmt = (PreparedStatement) out;");
0766: iw
0767: .println("parentPooledConnection.markActiveUncachedStatement( innerStmt );");
0768: iw
0769: .println("out = new NewProxyPreparedStatement( innerStmt, parentPooledConnection, false, this );");
0770: iw.downIndent();
0771: iw.println("}");
0772: iw.println("else if (out instanceof Statement)");
0773: iw.println("{");
0774: iw.upIndent();
0775: iw.println("Statement innerStmt = (Statement) out;");
0776: iw
0777: .println("parentPooledConnection.markActiveUncachedStatement( innerStmt );");
0778: iw
0779: .println("out = new NewProxyStatement( innerStmt, parentPooledConnection, false, this );");
0780: iw.downIndent();
0781: iw.println("}");
0782: iw.println("else if (out instanceof ResultSet)");
0783: iw.println("{");
0784: iw.upIndent();
0785: iw.println("ResultSet innerRs = (ResultSet) out;");
0786: iw
0787: .println("parentPooledConnection.markActiveRawConnectionResultSet( innerRs );");
0788: iw
0789: .println("out = new NewProxyResultSet( innerRs, parentPooledConnection, inner, this );");
0790: iw.downIndent();
0791: iw.println("}");
0792: iw.println("else if (out instanceof DatabaseMetaData)");
0793: iw.upIndent();
0794: iw
0795: .println("out = new NewProxyDatabaseMetaData( (DatabaseMetaData) out, parentPooledConnection );");
0796: iw.downIndent();
0797: iw.println("return out;");
0798: iw.downIndent();
0799: iw.println("}");
0800: iw.println();
0801: iw.println("synchronized void maybeDirtyTransaction()");
0802: iw.println("{ txn_known_resolved = false; }");
0803:
0804: super .generateExtraDeclarations(intfcl, genclass, iw);
0805: }
0806:
0807: void generateFindMethodAndArgs(Method method, IndentedWriter iw)
0808: throws IOException {
0809: iw.println("Class[] argTypes = ");
0810: iw.println("{");
0811: iw.upIndent();
0812:
0813: Class[] argTypes = method.getParameterTypes();
0814: for (int i = 0, len = argTypes.length; i < len; ++i) {
0815: if (i != 0)
0816: iw.println(",");
0817: iw.print(CodegenUtils.simpleClassName(argTypes[i])
0818: + ".class");
0819: }
0820: iw.println();
0821: iw.downIndent();
0822: iw.println("};");
0823: iw
0824: .println("Method method = Connection.class.getMethod( \042"
0825: + method.getName() + "\042 , argTypes );");
0826: iw.println();
0827: iw.println("Object[] args = ");
0828: iw.println("{");
0829: iw.upIndent();
0830:
0831: for (int i = 0, len = argTypes.length; i < len; ++i) {
0832: if (i != 0)
0833: iw.println(",");
0834: String argName = CodegenUtils.generatedArgumentName(i);
0835: Class argType = argTypes[i];
0836: if (argType.isPrimitive()) {
0837: if (argType == boolean.class)
0838: iw.print("Boolean.valueOf( " + argName + " )");
0839: else if (argType == byte.class)
0840: iw.print("new Byte( " + argName + " )");
0841: else if (argType == char.class)
0842: iw.print("new Character( " + argName + " )");
0843: else if (argType == short.class)
0844: iw.print("new Short( " + argName + " )");
0845: else if (argType == int.class)
0846: iw.print("new Integer( " + argName + " )");
0847: else if (argType == long.class)
0848: iw.print("new Long( " + argName + " )");
0849: else if (argType == float.class)
0850: iw.print("new Float( " + argName + " )");
0851: else if (argType == double.class)
0852: iw.print("new Double( " + argName + " )");
0853: } else
0854: iw.print(argName);
0855: }
0856:
0857: iw.downIndent();
0858: iw.println("};");
0859: }
0860:
0861: protected void generateExtraImports(IndentedWriter iw)
0862: throws IOException {
0863: super .generateExtraImports(iw);
0864: iw
0865: .println("import java.lang.reflect.InvocationTargetException;");
0866: iw
0867: .println("import com.mchange.v2.util.ResourceClosedException;");
0868: }
0869: }
0870:
0871: protected void generatePreDelegateCode(Class intfcl,
0872: String genclass, Method method, IndentedWriter iw)
0873: throws IOException {
0874: generateTryOpener(iw);
0875: }
0876:
0877: protected void generatePostDelegateCode(Class intfcl,
0878: String genclass, Method method, IndentedWriter iw)
0879: throws IOException {
0880: generateTryCloserAndCatch(intfcl, genclass, method, iw);
0881: }
0882:
0883: void generateTryOpener(IndentedWriter iw) throws IOException {
0884: iw.println("try");
0885: iw.println("{");
0886: iw.upIndent();
0887: }
0888:
0889: void generateTryCloserAndCatch(Class intfcl, String genclass,
0890: Method method, IndentedWriter iw) throws IOException {
0891: iw.downIndent();
0892: iw.println("}");
0893: iw.println("catch (NullPointerException exc)");
0894: iw.println("{");
0895: iw.upIndent();
0896: iw.println("if ( this.isDetached() )");
0897: iw.println("{");
0898: iw.upIndent();
0899: //iw.println( "System.err.print(\042probably 'cuz we're closed -- \042);" );
0900: //iw.println( "exc.printStackTrace();" );
0901: if ("close".equals(method.getName())) {
0902: iw
0903: .println("if (Debug.DEBUG && logger.isLoggable( MLevel.FINE ))");
0904: iw.println("{");
0905: iw.upIndent();
0906: iw
0907: .println("logger.log( MLevel.FINE, this + \042: close() called more than once.\042 );");
0908:
0909: // premature-detach-debug-debug only!
0910: if (PREMATURE_DETACH_DEBUG) {
0911: iw.println("prematureDetachRecorder.record();");
0912: iw
0913: .println("logger.warning( prematureDetachRecorder.getDump(\042Apparent multiple close of "
0914: + getInnerTypeName() + ".\042) );");
0915: }
0916: // end-premature-detach-debug-only!
0917:
0918: iw.downIndent();
0919: iw.println("}");
0920: } else {
0921: // premature-detach-debug-debug only!
0922: if (PREMATURE_DETACH_DEBUG) {
0923: iw.println("prematureDetachRecorder.record();");
0924: iw
0925: .println("logger.warning( prematureDetachRecorder.getDump(\042Use of already detached "
0926: + getInnerTypeName() + ".\042) );");
0927: }
0928: // end-premature-detach-debug-only!
0929:
0930: iw
0931: .println("throw SqlUtils.toSQLException(\042You can't operate on a closed "
0932: + getInnerTypeName() + "!!!\042, exc);");
0933: }
0934: iw.downIndent();
0935: iw.println("}");
0936: iw.println("else throw exc;");
0937: iw.downIndent();
0938: iw.println("}");
0939: iw.println("catch (Exception exc)");
0940: iw.println("{");
0941: iw.upIndent();
0942: iw.println("if (! this.isDetached())");
0943: iw.println("{");
0944: iw.upIndent();
0945: //iw.println( "exc.printStackTrace();" );
0946: iw
0947: .println("throw parentPooledConnection.handleThrowable( exc );");
0948: iw.downIndent();
0949: iw.println("}");
0950: iw.println("else throw SqlUtils.toSQLException( exc );");
0951: iw.downIndent();
0952: iw.println("}");
0953: }
0954:
0955: protected void generateExtraDeclarations(Class intfcl,
0956: String genclass, IndentedWriter iw) throws IOException {
0957: // premature-detach-debug-debug only!
0958: if (PREMATURE_DETACH_DEBUG) {
0959: iw
0960: .println("com.mchange.v2.debug.ThreadNameStackTraceRecorder prematureDetachRecorder");
0961: iw.upIndent();
0962: iw
0963: .println("= new com.mchange.v2.debug.ThreadNameStackTraceRecorder(\042Premature Detach Recorder\042);");
0964: iw.downIndent();
0965: }
0966: // end-premature-detach-debug-only!
0967:
0968: iw
0969: .println("private final static MLogger logger = MLog.getLogger( \042"
0970: + genclass + "\042 );");
0971: iw.println();
0972:
0973: iw
0974: .println("volatile NewPooledConnection parentPooledConnection;");
0975: iw.println();
0976:
0977: iw
0978: .println("ConnectionEventListener cel = new ConnectionEventListener()");
0979: iw.println("{");
0980: iw.upIndent();
0981:
0982: iw
0983: .println("public void connectionErrorOccurred(ConnectionEvent evt)");
0984: iw
0985: .println("{ /* DON'T detach()... IGNORE -- this could be an ordinary error. Leave it to the PooledConnection to test, but leave proxies intact */ }");
0986: //BAD puppy -- iw.println("{ detach(); }");
0987:
0988: iw.println();
0989: iw.println("public void connectionClosed(ConnectionEvent evt)");
0990: iw.println("{ detach(); }");
0991:
0992: iw.downIndent();
0993: iw.println("};");
0994: iw.println();
0995:
0996: iw
0997: .println("void attach( NewPooledConnection parentPooledConnection )");
0998: iw.println("{");
0999: iw.upIndent();
1000: iw
1001: .println("this.parentPooledConnection = parentPooledConnection;");
1002: iw
1003: .println("parentPooledConnection.addConnectionEventListener( cel );");
1004: iw.downIndent();
1005: iw.println("}");
1006: iw.println();
1007: iw.println("private void detach()");
1008: iw.println("{");
1009: iw.upIndent();
1010:
1011: // factored out so we could define debug versions...
1012: writeDetachBody(iw);
1013:
1014: iw.downIndent();
1015: iw.println("}");
1016: iw.println();
1017: iw.print(CodegenUtils.fqcnLastElement(genclass));
1018: iw
1019: .println("( "
1020: + CodegenUtils.simpleClassName(intfcl)
1021: + " inner, NewPooledConnection parentPooledConnection )");
1022: iw.println("{");
1023: iw.upIndent();
1024: iw.println("this( inner );");
1025: iw.println("attach( parentPooledConnection );");
1026: generateExtraConstructorCode(intfcl, genclass, iw);
1027: iw.downIndent();
1028: iw.println("}");
1029: iw.println();
1030: iw.println("boolean isDetached()");
1031: iw.println("{ return (this.parentPooledConnection == null); }");
1032: }
1033:
1034: protected void writeDetachBody(IndentedWriter iw)
1035: throws IOException {
1036: // premature-detach-debug only
1037: if (PREMATURE_DETACH_DEBUG) {
1038: iw.println("prematureDetachRecorder.record();");
1039: iw.println("if (this.isDetached())");
1040: iw.upIndent();
1041: iw
1042: .println("logger.warning( prematureDetachRecorder.getDump(\042Double Detach.\042) );");
1043: iw.downIndent();
1044: }
1045: // end premature-detach-debug only
1046:
1047: iw
1048: .println("parentPooledConnection.removeConnectionEventListener( cel );");
1049: iw.println("parentPooledConnection = null;");
1050: }
1051:
1052: protected void generateExtraImports(IndentedWriter iw)
1053: throws IOException {
1054: iw.println("import java.sql.*;");
1055: iw.println("import javax.sql.*;");
1056: iw.println("import com.mchange.v2.log.*;");
1057: iw.println("import java.lang.reflect.Method;");
1058: iw.println("import com.mchange.v2.sql.SqlUtils;");
1059: }
1060:
1061: void generateExtraConstructorCode(Class intfcl, String genclass,
1062: IndentedWriter iw) throws IOException {
1063: }
1064:
1065: public static void main(String[] argv) {
1066: try {
1067: if (argv.length != 1) {
1068: System.err.println("java "
1069: + JdbcProxyGenerator.class.getName()
1070: + " <source-root-directory>");
1071: return;
1072: }
1073:
1074: File srcroot = new File(argv[0]);
1075: if (!srcroot.exists() || !srcroot.canWrite()) {
1076: System.err.println(JdbcProxyGenerator.class.getName()
1077: + " -- sourceroot: " + argv[0]
1078: + " must exist and be writable");
1079: return;
1080: }
1081:
1082: DelegatorGenerator mdgen = new NewProxyMetaDataGenerator();
1083: DelegatorGenerator rsgen = new NewProxyResultSetGenerator();
1084: DelegatorGenerator stgen = new NewProxyAnyStatementGenerator();
1085: DelegatorGenerator cngen = new NewProxyConnectionGenerator();
1086:
1087: genclass(cngen, Connection.class,
1088: "com.mchange.v2.c3p0.impl.NewProxyConnection",
1089: srcroot);
1090: genclass(stgen, Statement.class,
1091: "com.mchange.v2.c3p0.impl.NewProxyStatement",
1092: srcroot);
1093: genclass(
1094: stgen,
1095: PreparedStatement.class,
1096: "com.mchange.v2.c3p0.impl.NewProxyPreparedStatement",
1097: srcroot);
1098: genclass(
1099: stgen,
1100: CallableStatement.class,
1101: "com.mchange.v2.c3p0.impl.NewProxyCallableStatement",
1102: srcroot);
1103: genclass(rsgen, ResultSet.class,
1104: "com.mchange.v2.c3p0.impl.NewProxyResultSet",
1105: srcroot);
1106: genclass(
1107: mdgen,
1108: DatabaseMetaData.class,
1109: "com.mchange.v2.c3p0.impl.NewProxyDatabaseMetaData",
1110: srcroot);
1111: } catch (Exception e) {
1112: e.printStackTrace();
1113: }
1114: }
1115:
1116: static void genclass(DelegatorGenerator dg, Class intfcl,
1117: String fqcn, File srcroot) throws IOException {
1118: File genDir = new File(srcroot, dirForFqcn(fqcn));
1119: if (!genDir.exists()) {
1120: System.err.println(JdbcProxyGenerator.class.getName()
1121: + " -- creating directory: "
1122: + genDir.getAbsolutePath());
1123: genDir.mkdirs();
1124: }
1125: String fileName = CodegenUtils.fqcnLastElement(fqcn) + ".java";
1126: Writer w = null;
1127: try {
1128: w = new BufferedWriter(new FileWriter(new File(genDir,
1129: fileName)));
1130: dg.writeDelegator(intfcl, fqcn, w);
1131: w.flush();
1132: System.err.println("Generated " + fileName);
1133: } finally {
1134: try {
1135: if (w != null)
1136: w.close();
1137: } catch (Exception e) {
1138: e.printStackTrace();
1139: }
1140: }
1141: }
1142:
1143: static String dirForFqcn(String fqcn) {
1144: int last_dot = fqcn.lastIndexOf('.');
1145: StringBuffer sb = new StringBuffer(fqcn.substring(0,
1146: last_dot + 1));
1147: for (int i = 0, len = sb.length(); i < len; ++i)
1148: if (sb.charAt(i) == '.')
1149: sb.setCharAt(i, '/');
1150: return sb.toString();
1151: }
1152: }
|