From: <svn...@os...> - 2012-05-27 19:31:50
|
Author: aaime Date: 2012-05-27 12:31:43 -0700 (Sun, 27 May 2012) New Revision: 38768 Modified: branches/2.7.x/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/AuthorityCodes.java branches/2.7.x/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/DirectEpsgFactory.java branches/2.7.x/modules/plugin/epsg-hsql/src/main/java/org/geotools/referencing/factory/epsg/FactoryUsingHSQL.java branches/2.7.x/modules/plugin/epsg-hsql/src/main/java/org/geotools/referencing/factory/epsg/ThreadedHsqlEpsgFactory.java branches/2.7.x/modules/plugin/epsg-hsql/src/test/java/org/geotools/referencing/factory/epsg/ThreadedHsqlEpsgFactoryTest.java Log: [GEOT-4061] EPSG HSQL factories cannot recover from connection corruption Modified: branches/2.7.x/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/AuthorityCodes.java =================================================================== --- branches/2.7.x/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/AuthorityCodes.java 2012-05-27 19:10:34 UTC (rev 38767) +++ branches/2.7.x/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/AuthorityCodes.java 2012-05-27 19:31:43 UTC (rev 38768) @@ -108,12 +108,6 @@ private transient PreparedStatement querySingle; /** - * The connection to the underlying database. - */ - private Connection connection; - - - /** * The collection's size, or a negative value if not yet computed. The records will be counted * only when first needed. The special value -2 if set by {@link #isEmpty} if the size has not * yet been computed, but we know that the set is not empty. @@ -164,30 +158,48 @@ buffer.append(hasWhere ? " AND " : " WHERE ").append(table.codeColumn).append(" = ?"); sqlSingle = factory.adaptSQL(buffer.toString()); } + + protected PreparedStatement validateStatement(PreparedStatement stmt, String sql) throws SQLException { + Connection conn = null; + if (stmt != null) { + try { + conn = stmt.getConnection(); + } catch (SQLException sqle) { + // mark this invalid + stmt = null; + } + } + if(conn != null && !factory.isConnectionValid(conn)) { + stmt = null; + } + if (stmt == null) { + stmt = factory.getConnection().prepareStatement(sql); + } + return stmt; + } /** * Returns all codes. */ private ResultSet getAll() throws SQLException { assert Thread.holdsLock(this); - if (queryAll != null && factory.isConnectionValid(queryAll.getConnection())) { - try { - return queryAll.executeQuery(); - } catch (SQLException ignore) { - /* - * Failed to reuse an existing statement. This problem occurs in some occasions - * with the JDBC-ODBC bridge in Java 6 (the error message is "Invalid handle"). - * I'm not sure where the bug come from (didn't noticed it when using HSQL). We - * will try again with a new statement created in the code after this 'catch' - * clause. Note that we set 'queryAll' to null first in case of failure during - * the 'prepareStatement(...)' execution. - */ - queryAll.close(); - queryAll = null; - recoverableException("getAll", ignore); - } + queryAll = validateStatement(queryAll, sqlAll); + try { + return queryAll.executeQuery(); + } catch (SQLException ignore) { + /* + * Failed to reuse an existing statement. This problem occurs in some occasions + * with the JDBC-ODBC bridge in Java 6 (the error message is "Invalid handle"). + * I'm not sure where the bug come from (didn't noticed it when using HSQL). We + * will try again with a new statement created in the code after this 'catch' + * clause. Note that we set 'queryAll' to null first in case of failure during + * the 'prepareStatement(...)' execution. + */ + queryAll.close(); + queryAll = null; + recoverableException("getAll", ignore); } - queryAll = factory.getConnection().prepareStatement(sqlAll); + queryAll = validateStatement(queryAll, sqlAll); return queryAll.executeQuery(); } @@ -196,9 +208,7 @@ */ private ResultSet getSingle(final Object code) throws SQLException { assert Thread.holdsLock(this); - if (querySingle == null || !factory.isConnectionValid(querySingle.getConnection())) { - querySingle = factory.getConnection().prepareStatement(sqlSingle); - } + querySingle = validateStatement(querySingle, sqlSingle); querySingle.setString(1, code.toString()); return querySingle.executeQuery(); } Modified: branches/2.7.x/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/DirectEpsgFactory.java =================================================================== --- branches/2.7.x/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/DirectEpsgFactory.java 2012-05-27 19:10:34 UTC (rev 38767) +++ branches/2.7.x/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/DirectEpsgFactory.java 2012-05-27 19:31:43 UTC (rev 38768) @@ -710,14 +710,21 @@ { assert Thread.holdsLock(this); PreparedStatement stmt = statements.get(key); - if(stmt != null && !isConnectionValid(stmt.getConnection())) + Connection conn = null; + if (stmt != null) { + try { + conn = stmt.getConnection(); + } catch (SQLException sqle) { + // mark this invalid + stmt = null; + } + } + if(conn != null && !isConnectionValid(conn)) stmt = null; if (stmt == null) { stmt = getConnection().prepareStatement(adaptSQL(sql)); statements.put(key, stmt); - } else { - - } + } return stmt; } @@ -3184,7 +3191,7 @@ if (connection == null) { connection = dataSource.getConnection(); } else { - if(!isConnectionValid(connection)) { + if(connection.isClosed() || !isConnectionValid(connection)) { statements.clear(); try { // we need to send back the connection to the eventual Modified: branches/2.7.x/modules/plugin/epsg-hsql/src/main/java/org/geotools/referencing/factory/epsg/FactoryUsingHSQL.java =================================================================== --- branches/2.7.x/modules/plugin/epsg-hsql/src/main/java/org/geotools/referencing/factory/epsg/FactoryUsingHSQL.java 2012-05-27 19:10:34 UTC (rev 38767) +++ branches/2.7.x/modules/plugin/epsg-hsql/src/main/java/org/geotools/referencing/factory/epsg/FactoryUsingHSQL.java 2012-05-27 19:31:43 UTC (rev 38768) @@ -22,6 +22,7 @@ import java.sql.SQLException; import java.util.regex.Pattern; import java.util.regex.Matcher; +import javax.sql.DataSource; // Geotools dependencies import org.geotools.factory.Hints; @@ -53,7 +54,11 @@ public FactoryUsingHSQL(final Hints hints, final Connection connection) { super(hints, connection); } - + + public FactoryUsingHSQL(final Hints hints, final DataSource dataSource) { + super(hints, dataSource); + } + /** * If the query contains a "FROM (" expression, remove the parenthesis. */ Modified: branches/2.7.x/modules/plugin/epsg-hsql/src/main/java/org/geotools/referencing/factory/epsg/ThreadedHsqlEpsgFactory.java =================================================================== --- branches/2.7.x/modules/plugin/epsg-hsql/src/main/java/org/geotools/referencing/factory/epsg/ThreadedHsqlEpsgFactory.java 2012-05-27 19:10:34 UTC (rev 38767) +++ branches/2.7.x/modules/plugin/epsg-hsql/src/main/java/org/geotools/referencing/factory/epsg/ThreadedHsqlEpsgFactory.java 2012-05-27 19:31:43 UTC (rev 38768) @@ -325,7 +325,7 @@ } } - FactoryUsingHSQL factory = new FactoryUsingHSQL(hints, getDataSource().getConnection()); + FactoryUsingHSQL factory = new FactoryUsingHSQL(hints, getDataSource()); factory.setValidationQuery("CALL NOW()"); return factory; } Modified: branches/2.7.x/modules/plugin/epsg-hsql/src/test/java/org/geotools/referencing/factory/epsg/ThreadedHsqlEpsgFactoryTest.java =================================================================== --- branches/2.7.x/modules/plugin/epsg-hsql/src/test/java/org/geotools/referencing/factory/epsg/ThreadedHsqlEpsgFactoryTest.java 2012-05-27 19:10:34 UTC (rev 38767) +++ branches/2.7.x/modules/plugin/epsg-hsql/src/test/java/org/geotools/referencing/factory/epsg/ThreadedHsqlEpsgFactoryTest.java 2012-05-27 19:31:43 UTC (rev 38768) @@ -16,6 +16,7 @@ */ package org.geotools.referencing.factory.epsg; +import java.lang.reflect.Method; import static org.junit.Assert.*; import java.util.Set; @@ -62,7 +63,32 @@ if( finder == null ){ finder = factory.getIdentifiedObjectFinder(CoordinateReferenceSystem.class); } + corruptConnection(); } + + @Test + public void testConnectionCorruption() throws Exception { + corruptConnection(); + CRS.decode("EPSG:4326"); + } + + @Test + public void testConnectionCorruptionListAll() throws Exception { + Set<String> original = CRS.getSupportedCodes("EPSG"); + assertTrue(original.size() > 4000); + corruptConnection(); + Set<String> afterCorruption = CRS.getSupportedCodes("EPSG"); + assertEquals(original, afterCorruption); + } + + private void corruptConnection() throws Exception { + java.lang.reflect.Field field = org.geotools.referencing.factory.BufferedAuthorityFactory.class.getDeclaredField("backingStore"); + field.setAccessible(true); + Object def = field.get(factory); + Method getConnection = DirectEpsgFactory.class.getDeclaredMethod("getConnection"); + java.sql.Connection conn = (java.sql.Connection) getConnection.invoke( def ); + conn.close(); + } @Test public void testCreation() throws Exception { |