From 2377a67bbbc441c50e0d6c53a278b42ef92c8c2e Mon Sep 17 00:00:00 2001 From: "Brian S. O'Neill" Date: Fri, 9 May 2008 04:03:04 +0000 Subject: Hide JDBCRepository class. --- .../amazon/carbonado/repo/jdbc/JDBCBlobLoader.java | 2 +- .../amazon/carbonado/repo/jdbc/JDBCClobLoader.java | 2 +- .../amazon/carbonado/repo/jdbc/JDBCRepository.java | 17 +- .../carbonado/repo/jdbc/JDBCRepositoryBuilder.java | 12 +- .../carbonado/repo/jdbc/JDBCStorableGenerator.java | 197 +++++++++++---------- .../repo/jdbc/JDBCStorableIntrospector.java | 36 +++- .../amazon/carbonado/repo/jdbc/JDBCSupport.java | 6 +- .../carbonado/repo/jdbc/SupportResolver.java | 43 +++++ 8 files changed, 197 insertions(+), 118 deletions(-) create mode 100644 src/main/java/com/amazon/carbonado/repo/jdbc/SupportResolver.java diff --git a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCBlobLoader.java b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCBlobLoader.java index cd818c0..e8464e3 100644 --- a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCBlobLoader.java +++ b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCBlobLoader.java @@ -29,5 +29,5 @@ public interface JDBCBlobLoader { /** * @return Blob or null if missing */ - java.sql.Blob load(JDBCRepository jdbcRepo) throws FetchException; + java.sql.Blob load(JDBCConnectionCapability cap) throws FetchException; } diff --git a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCClobLoader.java b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCClobLoader.java index 9e3470a..0a980bb 100644 --- a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCClobLoader.java +++ b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCClobLoader.java @@ -29,5 +29,5 @@ public interface JDBCClobLoader { /** * @return Clob or null if missing */ - java.sql.Clob load(JDBCRepository jdbcRepo) throws FetchException; + java.sql.Clob load(JDBCConnectionCapability cap) throws FetchException; } diff --git a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCRepository.java b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCRepository.java index 250b54e..870ab34 100644 --- a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCRepository.java +++ b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCRepository.java @@ -51,6 +51,7 @@ import com.amazon.carbonado.capability.IndexInfo; import com.amazon.carbonado.capability.IndexInfoCapability; import com.amazon.carbonado.capability.ShutdownCapability; import com.amazon.carbonado.capability.StorableInfoCapability; +import com.amazon.carbonado.info.StorableIntrospector; import com.amazon.carbonado.info.StorableProperty; import com.amazon.carbonado.sequence.SequenceCapability; import com.amazon.carbonado.sequence.SequenceValueProducer; @@ -70,8 +71,7 @@ import com.amazon.carbonado.util.ThrowUnchecked; * @author bcastill * @see JDBCRepositoryBuilder */ -// Note: this class must be public because auto-generated code needs access to it -public class JDBCRepository extends AbstractRepository +class JDBCRepository extends AbstractRepository implements Repository, IndexInfoCapability, ShutdownCapability, @@ -195,6 +195,8 @@ public class JDBCRepository extends AbstractRepository private final JDBCSupportStrategy mSupportStrategy; private JDBCExceptionTransformer mExceptionTransformer; + private final SupportResolver mResolver; + private final JDBCTransactionManager mTxnMgr; // Mappings from IsolationLevel to best matching supported level. @@ -224,7 +226,8 @@ public class JDBCRepository extends AbstractRepository Integer fetchSize, Map autoVersioningMap, Map suppressReloadMap, - String sequenceSelectStatement, boolean forceStoredSequence) + String sequenceSelectStatement, boolean forceStoredSequence, + SupportResolver resolver) throws RepositoryException { super(name); @@ -243,6 +246,8 @@ public class JDBCRepository extends AbstractRepository mAutoVersioningMap = autoVersioningMap; mSuppressReloadMap = suppressReloadMap; + mResolver = resolver; + mOpenConnections = new IdentityHashMap(); mOpenConnectionsLock = new ReentrantLock(true); @@ -327,7 +332,6 @@ public class JDBCRepository extends AbstractRepository /** * Returns true if a transaction is in progress and it is for update. */ - // Is called by auto-generated code and must be public. public boolean isTransactionForUpdate() { return localTransactionScope().isForUpdate(); } @@ -344,7 +348,8 @@ public class JDBCRepository extends AbstractRepository throws RepositoryException, SupportException { try { - return JDBCStorableIntrospector.examine(type, mDataSource, mCatalog, mSchema); + return JDBCStorableIntrospector + .examine(type, mDataSource, mCatalog, mSchema, mResolver); } catch (SQLException e) { throw toRepositoryException(e); } @@ -417,7 +422,6 @@ public class JDBCRepository extends AbstractRepository * Any connection returned by this method must be closed by calling * yieldConnection on this repository. */ - // Note: This method must be public for auto-generated code to access it. public Connection getConnection() throws FetchException { try { if (mOpenConnections == null) { @@ -493,7 +497,6 @@ public class JDBCRepository extends AbstractRepository * Gives up a connection returned from getConnection. Connection must be * yielded in same thread that retrieved it. */ - // Note: This method must be public for auto-generated code to access it. public void yieldConnection(Connection con) throws FetchException { try { if (con.getAutoCommit()) { diff --git a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCRepositoryBuilder.java b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCRepositoryBuilder.java index 9996aac..9117884 100644 --- a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCRepositoryBuilder.java +++ b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCRepositoryBuilder.java @@ -75,7 +75,9 @@ public class JDBCRepositoryBuilder extends AbstractRepositoryBuilder { private Map mSuppressReloadMap; private String mSequenceSelectStatement; private boolean mForceStoredSequence; - + + private SupportResolver mResolver; + public JDBCRepositoryBuilder() { } @@ -88,7 +90,8 @@ public class JDBCRepositoryBuilder extends AbstractRepositoryBuilder { mFetchSize, getAutoVersioningMap(), getSuppressReloadMap(), - mSequenceSelectStatement, mForceStoredSequence); + mSequenceSelectStatement, mForceStoredSequence, + mResolver); rootRef.set(repo); return repo; } @@ -408,4 +411,9 @@ public class JDBCRepositoryBuilder extends AbstractRepositoryBuilder { } } } + + // Experimental feature. + void setSupportResolver(SupportResolver resolver) { + mResolver = resolver; + } } diff --git a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCStorableGenerator.java b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCStorableGenerator.java index 933817e..5207452 100644 --- a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCStorableGenerator.java +++ b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCStorableGenerator.java @@ -181,7 +181,6 @@ class JDBCStorableGenerator { final Map, Class> lobLoaderMap = generateLobLoaders(); // Declare some types. - final TypeDesc jdbcRepoType = TypeDesc.forClass(JDBCRepository.class); final TypeDesc jdbcSupportType = TypeDesc.forClass(JDBCSupport.class); final TypeDesc resultSetType = TypeDesc.forClass(ResultSet.class); final TypeDesc connectionType = TypeDesc.forClass(Connection.class); @@ -299,34 +298,34 @@ class JDBCStorableGenerator { mi.addException(TypeDesc.forClass(FetchException.class)); CodeBuilder b = new CodeBuilder(mi); - LocalVariable repoVar = getJDBCRepository(b); + LocalVariable supportVar = getJDBCSupport(b); Label tryBeforeCon = b.createLabel().setLocation(); - LocalVariable conVar = getConnection(b, repoVar); + LocalVariable conVar = getConnection(b, supportVar); Label tryAfterCon = b.createLabel().setLocation(); b.loadThis(); - b.loadLocal(repoVar); + b.loadLocal(supportVar); b.loadLocal(conVar); b.loadNull(); // No Lobs to update b.invokeVirtual(MasterStorableGenerator.DO_TRY_LOAD_MASTER_METHOD_NAME, TypeDesc.BOOLEAN, - new TypeDesc[] {jdbcRepoType, connectionType, lobArrayType}); + new TypeDesc[] {jdbcSupportType, connectionType, lobArrayType}); LocalVariable resultVar = b.createLocalVariable("result", TypeDesc.BOOLEAN); b.storeLocal(resultVar); - yieldConAndHandleException(b, repoVar, tryBeforeCon, conVar, tryAfterCon, false); + yieldConAndHandleException(b, supportVar, tryBeforeCon, conVar, tryAfterCon, false); b.loadLocal(resultVar); b.returnValue(TypeDesc.BOOLEAN); } - // Now define doTryLoad(JDBCRepositry, Connection, Lob[]). The Lob array argument + // Now define doTryLoad(JDBCSupport, Connection, Lob[]). The Lob array argument // is optional, and it indicates which (large) Lobs should be updated upon load. { MethodInfo mi = mClassFile.addMethod (Modifiers.PROTECTED, MasterStorableGenerator.DO_TRY_LOAD_MASTER_METHOD_NAME, TypeDesc.BOOLEAN, - new TypeDesc[] {jdbcRepoType, connectionType, lobArrayType}); + new TypeDesc[] {jdbcSupportType, connectionType, lobArrayType}); mi.addException(TypeDesc.forClass(Exception.class)); CodeBuilder b = new CodeBuilder(mi); @@ -418,13 +417,16 @@ class JDBCStorableGenerator { Label tryEnd = b.createLabel().setLocation(); b.returnVoid(); + b.exceptionHandler(tryStart, tryEnd, RuntimeException.class.getName()); + b.throwObject(); + b.exceptionHandler(tryStart, tryEnd, Exception.class.getName()); - pushJDBCRepository(b); - // Swap exception object and JDBCRepository instance. + pushJDBCSupport(b); + // Swap exception object and JDBCSupport instance. b.swap(); TypeDesc[] params = {TypeDesc.forClass(Throwable.class)}; - b.invokeVirtual(jdbcRepoType, "toPersistException", - TypeDesc.forClass(PersistException.class), params); + b.invokeInterface(jdbcSupportType, "toPersistException", + TypeDesc.forClass(PersistException.class), params); b.throwObject(); } @@ -444,11 +446,11 @@ class JDBCStorableGenerator { b.exceptionHandler(tryStart, innerTryEnd, SQLException.class.getName()); b.dup(); // dup the SQLException - pushJDBCRepository(b); + pushJDBCSupport(b); b.swap(); // swap the dup'ed SQLException to pass to method - b.invokeVirtual(jdbcRepoType, "isUniqueConstraintError", - TypeDesc.BOOLEAN, - new TypeDesc[] {TypeDesc.forClass(SQLException.class)}); + b.invokeInterface(jdbcSupportType, "isUniqueConstraintError", + TypeDesc.BOOLEAN, + new TypeDesc[] {TypeDesc.forClass(SQLException.class)}); Label notConstraint = b.createLabel(); b.ifZeroComparisonBranch(notConstraint, "=="); // Return false to indicate unique constraint violation. @@ -461,13 +463,16 @@ class JDBCStorableGenerator { Label outerTryEnd = b.createLabel().setLocation(); + b.exceptionHandler(tryStart, outerTryEnd, RuntimeException.class.getName()); + b.throwObject(); + b.exceptionHandler(tryStart, outerTryEnd, Exception.class.getName()); - pushJDBCRepository(b); - // Swap exception object and JDBCRepository instance. + pushJDBCSupport(b); + // Swap exception object and JDBCSupport instance. b.swap(); TypeDesc[] params = {TypeDesc.forClass(Throwable.class)}; - b.invokeVirtual(jdbcRepoType, "toPersistException", - TypeDesc.forClass(PersistException.class), params); + b.invokeInterface(jdbcSupportType, "toPersistException", + TypeDesc.forClass(PersistException.class), params); b.throwObject(); } @@ -479,8 +484,8 @@ class JDBCStorableGenerator { mi.addException(TypeDesc.forClass(PersistException.class)); CodeBuilder b = new CodeBuilder(mi); - LocalVariable repoVar = getJDBCRepository(b); - LocalVariable conVar = getConnection(b, repoVar); + LocalVariable supportVar = getJDBCSupport(b); + LocalVariable conVar = getConnection(b, supportVar); Label tryAfterCon = b.createLabel().setLocation(); // Push connection in preparation for preparing a statement. @@ -752,7 +757,7 @@ class JDBCStorableGenerator { // progress at this point. b.loadThis(); - b.loadLocal(repoVar); + b.loadLocal(supportVar); b.loadLocal(conVar); if (lobArrayVar == null) { b.loadNull(); @@ -761,13 +766,13 @@ class JDBCStorableGenerator { } b.invokeVirtual(MasterStorableGenerator.DO_TRY_LOAD_MASTER_METHOD_NAME, TypeDesc.BOOLEAN, - new TypeDesc[] {jdbcRepoType, connectionType, lobArrayType}); + new TypeDesc[] {jdbcSupportType, connectionType, lobArrayType}); b.pop(); } // Note: yieldConAndHandleException is not called, allowing any // SQLException to be thrown. The insert or tryInsert methods must handle it. - yieldCon(b, repoVar, conVar, tryAfterCon); + yieldCon(b, supportVar, conVar, tryAfterCon); b.loadConstant(true); b.returnValue(TypeDesc.BOOLEAN); @@ -786,9 +791,9 @@ class JDBCStorableGenerator { // Only update properties with state DIRTY. Therefore, update // statement is always dynamic. - LocalVariable repoVar = getJDBCRepository(b); + LocalVariable supportVar = getJDBCSupport(b); Label tryBeforeCon = b.createLabel().setLocation(); - LocalVariable conVar = getConnection(b, repoVar); + LocalVariable conVar = getConnection(b, supportVar); Label tryAfterCon = b.createLabel().setLocation(); // Load connection in preparation for creating statement. @@ -1105,7 +1110,7 @@ class JDBCStorableGenerator { // progress at this point. b.loadThis(); - b.loadLocal(repoVar); + b.loadLocal(supportVar); b.loadLocal(conVar); if (lobArrayVar == null) { b.loadNull(); @@ -1114,7 +1119,7 @@ class JDBCStorableGenerator { } b.invokeVirtual(MasterStorableGenerator.DO_TRY_LOAD_MASTER_METHOD_NAME, TypeDesc.BOOLEAN, - new TypeDesc[] {jdbcRepoType, connectionType, lobArrayType}); + new TypeDesc[] {jdbcSupportType, connectionType, lobArrayType}); // Even though a boolean is returned, the actual value for true and // false is an int, 1 or 0. b.storeLocal(updateCount); @@ -1122,7 +1127,7 @@ class JDBCStorableGenerator { skipReload.setLocation(); - yieldConAndHandleException(b, repoVar, tryBeforeCon, conVar, tryAfterCon, true); + yieldConAndHandleException(b, supportVar, tryBeforeCon, conVar, tryAfterCon, true); b.loadLocal(updateCount); b.returnValue(TypeDesc.BOOLEAN); @@ -1140,9 +1145,9 @@ class JDBCStorableGenerator { deleteBuilder.append("DELETE FROM "); deleteBuilder.append(mInfo.getQualifiedTableName()); - LocalVariable repoVar = getJDBCRepository(b); + LocalVariable supportVar = getJDBCSupport(b); Label tryBeforeCon = b.createLabel().setLocation(); - LocalVariable conVar = getConnection(b, repoVar); + LocalVariable conVar = getConnection(b, supportVar); Label tryAfterCon = b.createLabel().setLocation(); LocalVariable psVar = b.createLocalVariable("ps", preparedStatementType); @@ -1160,7 +1165,7 @@ class JDBCStorableGenerator { b.storeLocal(resultVar); closeStatement(b, psVar, tryAfterPs); - yieldConAndHandleException(b, repoVar, tryBeforeCon, conVar, tryAfterCon, true); + yieldConAndHandleException(b, supportVar, tryBeforeCon, conVar, tryAfterCon, true); b.loadLocal(resultVar); b.returnValue(TypeDesc.BOOLEAN); @@ -1212,24 +1217,15 @@ class JDBCStorableGenerator { } /** - * Generates code to get the JDBCRepository instance and store it in a - * local variable. + * Generates code to get the JDBCSupport instance and store it in a local + * variable. */ - private LocalVariable getJDBCRepository(CodeBuilder b) { - pushJDBCRepository(b); - LocalVariable repoVar = - b.createLocalVariable("repo", TypeDesc.forClass(JDBCRepository.class)); - b.storeLocal(repoVar); - return repoVar; - } - - /** - * Generates code to push the JDBCRepository instance on the stack. - */ - private void pushJDBCRepository(CodeBuilder b) { + private LocalVariable getJDBCSupport(CodeBuilder b) { pushJDBCSupport(b); - b.invokeInterface(TypeDesc.forClass(JDBCSupport.class), "getJDBCRepository", - TypeDesc.forClass(JDBCRepository.class), null); + LocalVariable supportVar = + b.createLocalVariable("support", TypeDesc.forClass(JDBCSupport.class)); + b.storeLocal(supportVar); + return supportVar; } /** @@ -1242,14 +1238,15 @@ class JDBCStorableGenerator { } /** - * Generates code to get connection from JDBCRepository and store it in a local variable. + * Generates code to get connection from JDBCConnectionCapability and store + * it in a local variable. * - * @param repoVar reference to JDBCRepository + * @param capVar reference to JDBCConnectionCapability */ - private LocalVariable getConnection(CodeBuilder b, LocalVariable repoVar) { - b.loadLocal(repoVar); - b.invokeVirtual(TypeDesc.forClass(JDBCRepository.class), - "getConnection", TypeDesc.forClass(Connection.class), null); + private LocalVariable getConnection(CodeBuilder b, LocalVariable capVar) { + b.loadLocal(capVar); + b.invokeInterface(TypeDesc.forClass(JDBCConnectionCapability.class), + "getConnection", TypeDesc.forClass(Connection.class), null); LocalVariable conVar = b.createLocalVariable("con", TypeDesc.forClass(Connection.class)); b.storeLocal(conVar); return conVar; @@ -1259,18 +1256,18 @@ class JDBCStorableGenerator { * Generates code which emulates this: * * // May throw FetchException - * JDBCRepository.yieldConnection(con); + * JDBCConnectionCapability.yieldConnection(con); * - * @param repoVar required reference to JDBCRepository + * @param capVar required reference to JDBCConnectionCapability * @param conVar optional connection to yield */ - private void yieldConnection(CodeBuilder b, LocalVariable repoVar, LocalVariable conVar) { + private void yieldConnection(CodeBuilder b, LocalVariable capVar, LocalVariable conVar) { if (conVar != null) { - b.loadLocal(repoVar); + b.loadLocal(capVar); b.loadLocal(conVar); - b.invokeVirtual(TypeDesc.forClass(JDBCRepository.class), - "yieldConnection", null, - new TypeDesc[] {TypeDesc.forClass(Connection.class)}); + b.invokeInterface(TypeDesc.forClass(JDBCConnectionCapability.class), + "yieldConnection", null, + new TypeDesc[] {TypeDesc.forClass(Connection.class)}); } } @@ -1282,7 +1279,7 @@ class JDBCStorableGenerator { * @param sqlBuilder contains SQL statement right before the WHERE clause * @param conVar local variable referencing connection * @param psVar declared local variable which will receive PreparedStatement - * @param jdbcRepoVar when non-null, check transaction if SELECT should be FOR UPDATE + * @param capVar when non-null, check transaction if SELECT should be FOR UPDATE * @param instanceVar when null, assume properties are contained in * "this". Otherwise, invoke property access methods on storable referenced * in var. @@ -1295,7 +1292,7 @@ class JDBCStorableGenerator { StringBuilder sqlBuilder, LocalVariable conVar, LocalVariable psVar, - LocalVariable jdbcRepoVar, + LocalVariable capVar, LocalVariable instanceVar) throws SupportException { @@ -1332,10 +1329,10 @@ class JDBCStorableGenerator { b.loadConstant(sqlBuilder.toString()); // Determine at runtime if SELECT should be " FOR UPDATE". - if (jdbcRepoVar != null) { - b.loadLocal(jdbcRepoVar); - b.invokeVirtual - (jdbcRepoVar.getType(), "isTransactionForUpdate", TypeDesc.BOOLEAN, null); + if (capVar != null) { + b.loadLocal(capVar); + b.invokeInterface(TypeDesc.forClass(JDBCConnectionCapability.class), + "isTransactionForUpdate", TypeDesc.BOOLEAN, null); Label notForUpdate = b.createLabel(); b.ifZeroComparisonBranch(notForUpdate, "=="); @@ -1406,10 +1403,10 @@ class JDBCStorableGenerator { } // Determine at runtime if SELECT should be " FOR UPDATE". - if (jdbcRepoVar != null) { - b.loadLocal(jdbcRepoVar); - b.invokeVirtual - (jdbcRepoVar.getType(), "isTransactionForUpdate", TypeDesc.BOOLEAN, null); + if (capVar != null) { + b.loadLocal(capVar); + b.invokeInterface(TypeDesc.forClass(JDBCConnectionCapability.class), + "isTransactionForUpdate", TypeDesc.BOOLEAN, null); Label notForUpdate = b.createLabel(); b.ifZeroComparisonBranch(notForUpdate, "=="); @@ -1669,27 +1666,27 @@ class JDBCStorableGenerator { * * ... * } finally { - * JDBCRepository.yieldConnection(con); + * JDBCConnectionCapability.yieldConnection(con); * } * - * @param repoVar required reference to JDBCRepository + * @param capVar required reference to JDBCConnectionCapability * @param conVar optional connection variable * @param tryAfterCon label right after connection acquisition */ private void yieldCon (CodeBuilder b, - LocalVariable repoVar, + LocalVariable capVar, LocalVariable conVar, Label tryAfterCon) { Label endFinallyLabel = b.createLabel().setLocation(); Label contLabel = b.createLabel(); - yieldConnection(b, repoVar, conVar); + yieldConnection(b, capVar, conVar); b.branch(contLabel); b.exceptionHandler(tryAfterCon, endFinallyLabel, null); - yieldConnection(b, repoVar, conVar); + yieldConnection(b, capVar, conVar); b.throwObject(); contLabel.setLocation(); @@ -1700,13 +1697,15 @@ class JDBCStorableGenerator { * * ... * } finally { - * JDBCRepository.yieldConnection(con); + * JDBCConnectionCapability.yieldConnection(con); * } + * } catch (RuntimeException e) { + * throw e; * } catch (Exception e) { - * throw JDBCRepository.toFetchException(e); + * throw JDBCConnectionCapability.toFetchException(e); * } * - * @param repoVar required reference to JDBCRepository + * @param capVar required reference to JDBCConnectionCapability * @param txnVar optional transaction variable to commit/exit * @param tryBeforeCon label right before connection acquisition * @param conVar optional connection variable @@ -1714,32 +1713,38 @@ class JDBCStorableGenerator { */ private void yieldConAndHandleException (CodeBuilder b, - LocalVariable repoVar, + LocalVariable capVar, Label tryBeforeCon, LocalVariable conVar, Label tryAfterCon, boolean forPersist) { Label endFinallyLabel = b.createLabel().setLocation(); Label contLabel = b.createLabel(); - yieldConnection(b, repoVar, conVar); + yieldConnection(b, capVar, conVar); b.branch(contLabel); b.exceptionHandler(tryAfterCon, endFinallyLabel, null); - yieldConnection(b, repoVar, conVar); + yieldConnection(b, capVar, conVar); + b.throwObject(); + + b.exceptionHandler + (tryBeforeCon, b.createLabel().setLocation(), RuntimeException.class.getName()); b.throwObject(); b.exceptionHandler (tryBeforeCon, b.createLabel().setLocation(), Exception.class.getName()); - b.loadLocal(repoVar); - // Swap exception object and JDBCRepository instance. + b.loadLocal(capVar); + // Swap exception object and JDBCConnectionCapability instance. b.swap(); TypeDesc[] params = {TypeDesc.forClass(Throwable.class)}; if (forPersist) { - b.invokeVirtual(TypeDesc.forClass(JDBCRepository.class), "toPersistException", - TypeDesc.forClass(PersistException.class), params); + b.invokeInterface(TypeDesc.forClass(JDBCConnectionCapability.class), + "toPersistException", + TypeDesc.forClass(PersistException.class), params); } else { - b.invokeVirtual(TypeDesc.forClass(JDBCRepository.class), "toFetchException", - TypeDesc.forClass(FetchException.class), params); + b.invokeInterface(TypeDesc.forClass(JDBCConnectionCapability.class), + "toFetchException", + TypeDesc.forClass(FetchException.class), params); } b.throwObject(); @@ -1971,7 +1976,7 @@ class JDBCStorableGenerator { // The Lob in the array represents the new value. What is // currently on the stack (as converted above) is the old - // value currently in the database. Call the JDBCRepository + // value currently in the database. Call the JDBCSupport // updateXlob method, which stuffs the new blob contents // into the old blob, thus updating it. @@ -2131,7 +2136,7 @@ class JDBCStorableGenerator { boolean isClob = loaderType == JDBCClobLoader.class; - final TypeDesc jdbcRepoType = TypeDesc.forClass(JDBCRepository.class); + final TypeDesc capType = TypeDesc.forClass(JDBCConnectionCapability.class); final TypeDesc resultSetType = TypeDesc.forClass(ResultSet.class); final TypeDesc preparedStatementType = TypeDesc.forClass(PreparedStatement.class); final TypeDesc sqlLobType = TypeDesc.forClass @@ -2155,14 +2160,14 @@ class JDBCStorableGenerator { } MethodInfo mi = cf.addMethod - (Modifiers.PUBLIC, "load", sqlLobType, new TypeDesc[] {jdbcRepoType}); + (Modifiers.PUBLIC, "load", sqlLobType, new TypeDesc[] {capType}); mi.addException(TypeDesc.forClass(FetchException.class)); CodeBuilder b = new CodeBuilder(mi); - LocalVariable repoVar = b.getParameter(0); + LocalVariable capVar = b.getParameter(0); Label tryBeforeCon = b.createLabel().setLocation(); - LocalVariable conVar = getConnection(b, repoVar); + LocalVariable conVar = getConnection(b, capVar); Label tryAfterCon = b.createLabel().setLocation(); StringBuilder selectBuilder = new StringBuilder(); @@ -2179,7 +2184,7 @@ class JDBCStorableGenerator { b.storeLocal(instanceVar); Label tryAfterPs = buildWhereClauseAndPreparedStatement - (b, selectBuilder, conVar, psVar, repoVar, instanceVar); + (b, selectBuilder, conVar, psVar, capVar, instanceVar); b.loadLocal(psVar); b.invokeInterface(preparedStatementType, "executeQuery", resultSetType, null); @@ -2209,7 +2214,7 @@ class JDBCStorableGenerator { closeResultSet(b, rsVar, tryAfterRs); closeStatement(b, psVar, tryAfterPs); - yieldConAndHandleException(b, repoVar, tryBeforeCon, conVar, tryAfterCon, false); + yieldConAndHandleException(b, capVar, tryBeforeCon, conVar, tryAfterCon, false); b.loadLocal(resultVar); b.returnValue(sqlLobType); diff --git a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCStorableIntrospector.java b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCStorableIntrospector.java index b5d7bd8..0b1492c 100644 --- a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCStorableIntrospector.java +++ b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCStorableIntrospector.java @@ -96,6 +96,13 @@ public class JDBCStorableIntrospector extends StorableIntrospector { public static JDBCStorableInfo examine (Class type, DataSource ds, String catalog, String schema) throws SQLException, SupportException + { + return examine(type, ds, catalog, schema, null); + } + + public static JDBCStorableInfo examine + (Class type, DataSource ds, String catalog, String schema, SupportResolver resolver) + throws SQLException, SupportException { Object key = KeyFactory.createKey(new Object[] {type, ds, catalog, schema}); @@ -109,7 +116,15 @@ public class JDBCStorableIntrospector extends StorableIntrospector { StorableInfo mainInfo = examine(type); Connection con = ds.getConnection(); try { - jInfo = examine(mainInfo, con, catalog, schema); + try { + jInfo = examine(mainInfo, con, catalog, schema, resolver); + } catch (SupportException e) { + if (resolver != null && resolver.resolve(mainInfo, con, catalog, schema)) { + jInfo = examine(mainInfo, con, catalog, schema, resolver); + } else { + throw e; + } + } } finally { try { con.close(); @@ -124,8 +139,8 @@ public class JDBCStorableIntrospector extends StorableIntrospector { // added to cache. This makes it possible for joins to (directly or // indirectly) reference their own enclosing type. for (JDBCStorableProperty jProperty : jInfo.getAllProperties().values()) { - ((JProperty) jProperty).fillInternalJoinElements(ds, catalog, schema); - ((JProperty) jProperty).fillExternalJoinElements(ds, catalog, schema); + ((JProperty) jProperty).fillInternalJoinElements(ds, catalog, schema, resolver); + ((JProperty) jProperty).fillExternalJoinElements(ds, catalog, schema, resolver); } return jInfo; @@ -140,7 +155,8 @@ public class JDBCStorableIntrospector extends StorableIntrospector { */ private static JDBCStorableInfo examine (StorableInfo mainInfo, Connection con, - final String searchCatalog, final String searchSchema) + final String searchCatalog, final String searchSchema, + SupportResolver resolver) throws SQLException, SupportException { DatabaseMetaData meta = con.getMetaData(); @@ -850,6 +866,8 @@ public class JDBCStorableIntrospector extends StorableIntrospector { addToSet(aliases, derived.toUpperCase()); addToSet(aliases, derived.toLowerCase()); addToSet(aliases, derived); + addToSet(aliases, base.toUpperCase()); + addToSet(aliases, base.toLowerCase()); addToSet(aliases, base); return aliases.toArray(new String[aliases.size()]); @@ -1403,7 +1421,8 @@ public class JDBCStorableIntrospector extends StorableIntrospector { } @SuppressWarnings("unchecked") - void fillInternalJoinElements(DataSource ds, String catalog, String schema) + void fillInternalJoinElements(DataSource ds, String catalog, String schema, + SupportResolver resolver) throws SQLException, SupportException { StorableProperty[] mainInternal = mMainProperty.getInternalJoinElements(); @@ -1412,7 +1431,7 @@ public class JDBCStorableIntrospector extends StorableIntrospector { return; } - JDBCStorableInfo info = examine(getEnclosingType(), ds, catalog, schema); + JDBCStorableInfo info = examine(getEnclosingType(), ds, catalog, schema, resolver); JDBCStorableProperty[] internal = new JDBCStorableProperty[mainInternal.length]; for (int i=mainInternal.length; --i>=0; ) { @@ -1421,7 +1440,8 @@ public class JDBCStorableIntrospector extends StorableIntrospector { mInternal = internal; } - void fillExternalJoinElements(DataSource ds, String catalog, String schema) + void fillExternalJoinElements(DataSource ds, String catalog, String schema, + SupportResolver resolver) throws SQLException, SupportException { StorableProperty[] mainExternal = mMainProperty.getExternalJoinElements(); @@ -1430,7 +1450,7 @@ public class JDBCStorableIntrospector extends StorableIntrospector { return; } - JDBCStorableInfo info = examine(getJoinedType(), ds, catalog, schema); + JDBCStorableInfo info = examine(getJoinedType(), ds, catalog, schema, resolver); JDBCStorableProperty[] external = new JDBCStorableProperty[mainExternal.length]; for (int i=mainExternal.length; --i>=0; ) { diff --git a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCSupport.java b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCSupport.java index 7c212cc..c3f85fa 100644 --- a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCSupport.java +++ b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCSupport.java @@ -19,6 +19,7 @@ package com.amazon.carbonado.repo.jdbc; import java.sql.PreparedStatement; +import java.sql.SQLException; import com.amazon.carbonado.Storable; import com.amazon.carbonado.FetchException; @@ -31,9 +32,8 @@ import com.amazon.carbonado.gen.MasterSupport; * * @author Brian S O'Neill */ -public interface JDBCSupport extends MasterSupport { - public JDBCRepository getJDBCRepository(); - +public interface JDBCSupport extends MasterSupport, JDBCConnectionCapability +{ // FIXME: Lob convert methods need to take Storable and property name. With // this, the optional Lob adapting trigger must be invoked. diff --git a/src/main/java/com/amazon/carbonado/repo/jdbc/SupportResolver.java b/src/main/java/com/amazon/carbonado/repo/jdbc/SupportResolver.java new file mode 100644 index 0000000..3c99b54 --- /dev/null +++ b/src/main/java/com/amazon/carbonado/repo/jdbc/SupportResolver.java @@ -0,0 +1,43 @@ +/* + * Copyright 2008 Amazon Technologies, Inc. or its affiliates. + * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks + * of Amazon Technologies, Inc. or its affiliates. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.amazon.carbonado.repo.jdbc; + +import java.sql.Connection; +import java.sql.SQLException; + +import com.amazon.carbonado.RepositoryException; +import com.amazon.carbonado.Storable; +import com.amazon.carbonado.SupportException; +import com.amazon.carbonado.info.StorableInfo; + +/** + * Experimental interface for allowing tables to be created or altered when the + * Storable definition doesn't match the table or the table doesn't + * exist. Currently only used by unit tests. + * + * @author Brian S O'Neill + */ +interface SupportResolver { + /** + * @return true if support has been resolved + */ + boolean resolve(StorableInfo info, + Connection con, String catalog, String schema) + throws SQLException; +} -- cgit v1.2.3