You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@velocity.apache.org by cb...@apache.org on 2017/06/26 13:37:42 UTC
svn commit: r1799917 -
/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/DataSourceResourceLoader.java
Author: cbrisson
Date: Mon Jun 26 13:37:42 2017
New Revision: 1799917
URL: http://svn.apache.org/viewvc?rev=1799917&view=rev
Log:
[engine] Review DataSourceResourceLoader connection, statement and resultset lifecycle
Modified:
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/DataSourceResourceLoader.java
Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/DataSourceResourceLoader.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/DataSourceResourceLoader.java?rev=1799917&r1=1799916&r2=1799917&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/DataSourceResourceLoader.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/DataSourceResourceLoader.java Mon Jun 26 13:37:42 2017
@@ -29,6 +29,7 @@ import org.apache.commons.lang3.StringUt
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
+import java.io.FilterReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
@@ -137,6 +138,44 @@ public class DataSourceResourceLoader ex
private InitialContext ctx;
private DataSource dataSource;
+ /*
+ Keep connection and prepared statements open. It's not just an optimization:
+ For several engines, the connection, and/or the statement, and/or the result set
+ must be kept open for the reader to be valid.
+ */
+ private Connection connection = null;
+ private PreparedStatement templatePrepStatement = null;
+ private PreparedStatement timestampPrepStatement = null;
+
+ private static class SelfCleaningReader extends FilterReader
+ {
+ private ResultSet resultSet;
+
+ public SelfCleaningReader(Reader reader, ResultSet resultSet)
+ {
+ super(reader);
+ this.resultSet = resultSet;
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ super.close();
+ try
+ {
+ resultSet.close();
+ }
+ catch (RuntimeException re)
+ {
+ throw re;
+ }
+ catch (Exception e)
+ {
+ // ignore
+ }
+ }
+ }
+
/**
* @see ResourceLoader#init(org.apache.velocity.util.ExtProperties)
*/
@@ -215,14 +254,11 @@ public class DataSourceResourceLoader ex
throw new ResourceNotFoundException("DataSourceResourceLoader: Template name was empty or null");
}
- Connection conn = null;
ResultSet rs = null;
- PreparedStatement ps = null;
try
{
- conn = openDbConnection();
- ps = getStatement(conn, templateColumn, tableName, keyColumn, name);
- rs = ps.executeQuery();
+ checkDBConnection();
+ rs = fetchResult(templatePrepStatement, name);
if (rs.next())
{
@@ -233,7 +269,7 @@ public class DataSourceResourceLoader ex
+ "template column for '"
+ name + "' is null");
}
- return reader;
+ return new SelfCleaningReader(reader, rs);
}
else
{
@@ -250,11 +286,6 @@ public class DataSourceResourceLoader ex
log.error(msg, sqle);
throw new ResourceNotFoundException(msg);
- } finally
- {
- closeResultSet(rs);
- closeStatement(ps);
- closeDbConnection(conn);
}
}
@@ -280,15 +311,12 @@ public class DataSourceResourceLoader ex
}
else
{
- Connection conn = null;
ResultSet rs = null;
- PreparedStatement ps = null;
try
{
- conn = openDbConnection();
- ps = getStatement(conn, timestampColumn, tableName, keyColumn, name);
- rs = ps.executeQuery();
+ checkDBConnection();
+ rs = fetchResult(timestampPrepStatement, name);
if (rs.next())
{
@@ -314,8 +342,6 @@ public class DataSourceResourceLoader ex
finally
{
closeResultSet(rs);
- closeStatement(ps);
- closeDbConnection(conn);
}
}
return timeStamp;
@@ -325,83 +351,126 @@ public class DataSourceResourceLoader ex
* Gets connection to the datasource specified through the configuration
* parameters.
*
- * @return connection
*/
- private Connection openDbConnection() throws NamingException, SQLException
+ private void openDBConnection() throws NamingException, SQLException
{
- if (dataSource != null)
- {
- return dataSource.getConnection();
- }
+ if (dataSource == null)
+ {
+ if (ctx == null)
+ {
+ ctx = new InitialContext();
+ }
- if (ctx == null)
- {
- ctx = new InitialContext();
- }
+ dataSource = (DataSource) ctx.lookup(dataSourceName);
+ }
- dataSource = (DataSource) ctx.lookup(dataSourceName);
+ if (connection != null)
+ {
+ closeDBConnection();
+ }
+
+ connection = dataSource.getConnection();
+ templatePrepStatement = prepareStatement(connection, templateColumn, tableName, keyColumn);
+ timestampPrepStatement = prepareStatement(connection, timestampColumn, tableName, keyColumn);
+ }
- return dataSource.getConnection();
- }
+ /**
+ * Checks the connection is valid
+ *
+ */
+ private void checkDBConnection() throws NamingException, SQLException
+ {
+ if (connection == null || !connection.isValid(0))
+ {
+ openDBConnection();
+ }
+ }
+
+ /**
+ * Close DB connection on finalization
+ *
+ * @throws Throwable
+ */
+ protected void finalize()
+ throws Throwable
+ {
+ closeDBConnection();
+ }
/**
- * Closes connection to the datasource
+ * Closes the prepared statements and the connection to the datasource
*/
- private void closeDbConnection(final Connection conn)
+ private void closeDBConnection()
{
- if (conn != null)
+ if (templatePrepStatement != null)
{
try
{
- conn.close();
+ templatePrepStatement.close();
}
catch (RuntimeException re)
{
throw re;
}
- catch (Exception e)
+ catch (SQLException e)
+ {
+ // ignore
+ }
+ finally
{
- String msg = "DataSourceResourceLoader: problem when closing connection";
- log.error(msg, e);
- throw new VelocityException(msg, e);
+ templatePrepStatement = null;
}
}
- }
-
- /**
- * Closes the result set.
- */
- private void closeResultSet(final ResultSet rs)
- {
- if (rs != null)
+ if (timestampPrepStatement != null)
{
try
{
- rs.close();
+ timestampPrepStatement.close();
}
catch (RuntimeException re)
{
throw re;
}
- catch (Exception e)
+ catch (SQLException e)
+ {
+ // ignore
+ }
+ finally
+ {
+ timestampPrepStatement = null;
+ }
+ }
+ if (connection != null)
+ {
+ try
+ {
+ connection.close();
+ }
+ catch (RuntimeException re)
{
- String msg = "DataSourceResourceLoader: problem when closing result set";
- log.error(msg, e);
- throw new VelocityException(msg, e);
+ throw re;
+ }
+ catch (SQLException e)
+ {
+ // ignore
+ }
+ finally
+ {
+ connection = null;
}
}
}
/**
- * Closes the PreparedStatement.
+ * Closes the result set.
*/
- private void closeStatement(PreparedStatement ps)
+ private void closeResultSet(final ResultSet rs)
{
- if (ps != null)
+ if (rs != null)
{
try
{
- ps.close();
+// rs.close();
}
catch (RuntimeException re)
{
@@ -409,14 +478,11 @@ public class DataSourceResourceLoader ex
}
catch (Exception e)
{
- String msg = "DataSourceResourceLoader: problem when closing PreparedStatement ";
- log.error(msg, e);
- throw new VelocityException(msg, e);
+ // ignore
}
}
}
-
/**
* Creates the following PreparedStatement query :
* <br>
@@ -429,18 +495,35 @@ public class DataSourceResourceLoader ex
* @param columnNames columns to fetch from datasource
* @param tableName table to fetch from
* @param keyColumn column whose value should match templateName
- * @param templateName name of template to fetch
* @return PreparedStatement
*/
- protected PreparedStatement getStatement(final Connection conn,
- final String columnNames,
- final String tableName,
- final String keyColumn,
- final String templateName) throws SQLException
+ protected PreparedStatement prepareStatement(
+ final Connection conn,
+ final String columnNames,
+ final String tableName,
+ final String keyColumn
+ ) throws SQLException
{
PreparedStatement ps = conn.prepareStatement("SELECT " + columnNames + " FROM "+ tableName + " WHERE " + keyColumn + " = ?");
- ps.setString(1, templateName);
return ps;
}
+ /**
+ * Fetches the result for a given template name.
+ * Inherit this method if there is any calculation to perform on the template name.
+ *
+ * @param ps target prepared statement
+ * @param templateName input template name
+ * @return result set
+ * @throws SQLException
+ */
+ protected ResultSet fetchResult(
+ final PreparedStatement ps,
+ final String templateName
+ ) throws SQLException
+ {
+ ps.setString(1, templateName);
+ return ps.executeQuery();
+ }
+
}