Undo last two commits. The change had some side effects, leave db connection handling as is.
This commit is contained in:
parent
dece309fce
commit
12a87c17ff
4 changed files with 86 additions and 109 deletions
|
@ -417,6 +417,7 @@ public class Server implements Runnable {
|
||||||
dbProps = new ResourceProperties();
|
dbProps = new ResourceProperties();
|
||||||
dbProps.setIgnoreCase(false);
|
dbProps.setIgnoreCase(false);
|
||||||
dbProps.addResource(new FileResource(file));
|
dbProps.addResource(new FileResource(file));
|
||||||
|
DbSource.setDefaultProps(dbProps);
|
||||||
|
|
||||||
// read apps.properties file
|
// read apps.properties file
|
||||||
String appsPropfile = sysProps.getProperty("appsPropFile");
|
String appsPropfile = sysProps.getProperty("appsPropFile");
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
package helma.objectmodel.db;
|
|
||||||
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Statement;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A thin wrapper around a java.sql.Connection, providing utility methods
|
|
||||||
* for connection validation and closing.
|
|
||||||
*/
|
|
||||||
public class DbConnection {
|
|
||||||
|
|
||||||
private final Connection connection;
|
|
||||||
private final int serialId;
|
|
||||||
|
|
||||||
public DbConnection(Connection connection, int serialId) {
|
|
||||||
if(connection == null) {
|
|
||||||
throw new NullPointerException("connection parameter null in DbConnection");
|
|
||||||
}
|
|
||||||
this.connection = connection;
|
|
||||||
this.serialId = serialId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Connection getConnection() {
|
|
||||||
return connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSerialId() {
|
|
||||||
return serialId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() {
|
|
||||||
try {
|
|
||||||
if (!connection.isClosed()) {
|
|
||||||
connection.close();
|
|
||||||
}
|
|
||||||
} catch (SQLException x) {
|
|
||||||
System.err.println("Error closing DB connection: " + x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isValid(int id) {
|
|
||||||
// test if connection is still ok
|
|
||||||
try {
|
|
||||||
if (id != serialId || connection.isClosed()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Statement stmt = connection.createStatement();
|
|
||||||
stmt.execute("SELECT 1");
|
|
||||||
stmt.close();
|
|
||||||
} catch (SQLException sx) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
return "DbConnection[" + connection.toString() + "]";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -27,18 +27,20 @@ import java.util.Properties;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class describes a relational data source (URL, driver, user and password).
|
* This class describes a releational data source (URL, driver, user and password).
|
||||||
*/
|
*/
|
||||||
public class DbSource {
|
public class DbSource {
|
||||||
|
private static ResourceProperties defaultProps = null;
|
||||||
|
private Properties conProps;
|
||||||
private String name;
|
private String name;
|
||||||
private int serialId = 0;
|
private ResourceProperties props, subProps;
|
||||||
private ResourceProperties props;
|
|
||||||
protected String url;
|
protected String url;
|
||||||
private String driver;
|
private String driver;
|
||||||
private Properties conProps;
|
|
||||||
private boolean isOracle, isMySQL, isPostgreSQL, isH2;
|
private boolean isOracle, isMySQL, isPostgreSQL, isH2;
|
||||||
private long lastRead = 0L;
|
private long lastRead = 0L;
|
||||||
private Hashtable dbmappings = new Hashtable();
|
private Hashtable dbmappings = new Hashtable();
|
||||||
|
// compute hashcode statically because it's expensive and we need it often
|
||||||
|
private int hashcode;
|
||||||
// thread local connection holder for non-transactor threads
|
// thread local connection holder for non-transactor threads
|
||||||
private ThreadLocal connection;
|
private ThreadLocal connection;
|
||||||
|
|
||||||
|
@ -66,47 +68,56 @@ public class DbSource {
|
||||||
*/
|
*/
|
||||||
public synchronized Connection getConnection()
|
public synchronized Connection getConnection()
|
||||||
throws ClassNotFoundException, SQLException {
|
throws ClassNotFoundException, SQLException {
|
||||||
DbConnection con;
|
Connection con;
|
||||||
Transactor tx = Transactor.getInstance();
|
Transactor tx = Transactor.getInstance();
|
||||||
if (props.lastModified() != lastRead) {
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
if (tx != null) {
|
if (tx != null) {
|
||||||
con = tx.getDbConnection(name, serialId);
|
con = tx.getConnection(this);
|
||||||
} else {
|
} else {
|
||||||
con = getThreadLocalDbConnection();
|
con = getThreadLocalConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (con == null) {
|
boolean fileUpdated = props.lastModified() > lastRead ||
|
||||||
con = new DbConnection(DriverManager.getConnection(url, conProps), serialId);
|
(defaultProps != null && defaultProps.lastModified() > lastRead);
|
||||||
|
|
||||||
|
if (con == null || con.isClosed() || fileUpdated) {
|
||||||
|
init();
|
||||||
|
con = DriverManager.getConnection(url, conProps);
|
||||||
|
|
||||||
// If we wanted to use SQL transactions, we'd set autoCommit to
|
// If we wanted to use SQL transactions, we'd set autoCommit to
|
||||||
// false here and make commit/rollback invocations in Transactor methods;
|
// false here and make commit/rollback invocations in Transactor methods;
|
||||||
// System.err.println ("Created new Connection to "+url);
|
// System.err.println ("Created new Connection to "+url);
|
||||||
if (tx != null) {
|
if (tx != null) {
|
||||||
tx.registerConnection(name, con);
|
tx.registerConnection(this, con);
|
||||||
} else {
|
} else {
|
||||||
connection.set(con);
|
connection.set(con);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return con.getConnection();
|
return con;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used for connections not managed by a Helma transactor
|
* Used for connections not managed by a Helma transactor
|
||||||
* @return a thread local tested connection, or null
|
* @return a thread local tested connection, or null
|
||||||
*/
|
*/
|
||||||
private DbConnection getThreadLocalDbConnection() {
|
private Connection getThreadLocalConnection() {
|
||||||
if (connection == null) {
|
if (connection == null) {
|
||||||
connection = new ThreadLocal();
|
connection = new ThreadLocal();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
DbConnection con = (DbConnection) connection.get();
|
Connection con = (Connection) connection.get();
|
||||||
if (con != null && !con.isValid(serialId)) {
|
if (con != null) {
|
||||||
con.close();
|
// test if connection is still ok
|
||||||
connection.remove();
|
try {
|
||||||
return null;
|
Statement stmt = con.createStatement();
|
||||||
|
stmt.execute("SELECT 1");
|
||||||
|
stmt.close();
|
||||||
|
} catch (SQLException sx) {
|
||||||
|
try {
|
||||||
|
con.close();
|
||||||
|
} catch (SQLException ignore) {/* nothing to do */}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return con;
|
return con;
|
||||||
}
|
}
|
||||||
|
@ -131,10 +142,13 @@ public class DbSource {
|
||||||
* @throws ClassNotFoundException if the JDBC driver couldn't be loaded
|
* @throws ClassNotFoundException if the JDBC driver couldn't be loaded
|
||||||
*/
|
*/
|
||||||
private synchronized void init() throws ClassNotFoundException {
|
private synchronized void init() throws ClassNotFoundException {
|
||||||
lastRead = props.lastModified();
|
lastRead = (defaultProps == null) ? props.lastModified()
|
||||||
serialId ++;
|
: Math.max(props.lastModified(),
|
||||||
|
defaultProps.lastModified());
|
||||||
// refresh sub-properties for this DbSource
|
// refresh sub-properties for this DbSource
|
||||||
ResourceProperties subProps = props.getSubProperties(name + '.');
|
subProps = props.getSubProperties(name + '.');
|
||||||
|
// use properties hashcode for ourselves
|
||||||
|
hashcode = subProps.hashCode();
|
||||||
// get JDBC URL and driver class name
|
// get JDBC URL and driver class name
|
||||||
url = subProps.getProperty("url");
|
url = subProps.getProperty("url");
|
||||||
driver = subProps.getProperty("driver");
|
driver = subProps.getProperty("driver");
|
||||||
|
@ -198,6 +212,15 @@ public class DbSource {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the default (server-wide) properties
|
||||||
|
*
|
||||||
|
* @param props server default db.properties
|
||||||
|
*/
|
||||||
|
public static void setDefaultProps(ResourceProperties props) {
|
||||||
|
defaultProps = props;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if this DbSource represents an Oracle database
|
* Check if this DbSource represents an Oracle database
|
||||||
*
|
*
|
||||||
|
@ -255,4 +278,17 @@ public class DbSource {
|
||||||
return (DbMapping) dbmappings.get(tablename.toUpperCase());
|
return (DbMapping) dbmappings.get(tablename.toUpperCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a hash code value for the object.
|
||||||
|
*/
|
||||||
|
public int hashCode() {
|
||||||
|
return hashcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether some other object is "equal to" this one.
|
||||||
|
*/
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
return obj instanceof DbSource && subProps.equals(((DbSource) obj).subProps);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -234,38 +234,37 @@ public class Transactor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a db connection with this transactor thread.
|
* Register a db connection with this transactor thread.
|
||||||
* @param name the db source name
|
* @param src the db source
|
||||||
* @param con the connection
|
* @param con the connection
|
||||||
*/
|
*/
|
||||||
public void registerConnection(String name, DbConnection con) {
|
public void registerConnection(DbSource src, Connection con) {
|
||||||
DbConnection previous = (DbConnection) sqlConnections.put(name, con);
|
sqlConnections.put(src, con);
|
||||||
if (previous != null) {
|
|
||||||
nmgr.app.logEvent("Closing previous connection " + con);
|
|
||||||
previous.close();
|
|
||||||
}
|
|
||||||
// we assume a freshly created connection is ok.
|
// we assume a freshly created connection is ok.
|
||||||
testedConnections.put(name, new Long(System.currentTimeMillis()));
|
testedConnections.put(src, new Long(System.currentTimeMillis()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a db connection that was previously registered with this transactor thread.
|
* Get a db connection that was previously registered with this transactor thread.
|
||||||
* @param name the db source name
|
* @param src the db source
|
||||||
* @param serialId the current serial id of the db source definition, used for validation
|
* @return the connection
|
||||||
* @return the connection, or null if no valid connection is available
|
|
||||||
*/
|
*/
|
||||||
public DbConnection getDbConnection(String name, int serialId) {
|
public Connection getConnection(DbSource src) {
|
||||||
DbConnection con = (DbConnection) sqlConnections.get(name);
|
Connection con = (Connection) sqlConnections.get(src);
|
||||||
Long tested = (Long) testedConnections.get(name);
|
Long tested = (Long) testedConnections.get(src);
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
// Check if the connection is still valid
|
if (con != null && (tested == null || now - tested.longValue() > 60000)) {
|
||||||
if (con != null
|
// Check if the connection is still alive by executing a simple statement.
|
||||||
&& (tested == null || now - tested.longValue() > 60000)
|
try {
|
||||||
&& !con.isValid(serialId)) {
|
Statement stmt = con.createStatement();
|
||||||
nmgr.app.logEvent("Closing cached connection " + con);
|
stmt.execute("SELECT 1");
|
||||||
sqlConnections.remove(name);
|
stmt.close();
|
||||||
testedConnections.remove(name);
|
testedConnections.put(src, new Long(now));
|
||||||
con.close();
|
} catch (SQLException sx) {
|
||||||
return null;
|
try {
|
||||||
|
con.close();
|
||||||
|
} catch (SQLException ignore) {/* nothing to do */}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return con;
|
return con;
|
||||||
}
|
}
|
||||||
|
@ -530,11 +529,12 @@ public class Transactor {
|
||||||
if (sqlConnections != null) {
|
if (sqlConnections != null) {
|
||||||
for (Iterator i = sqlConnections.values().iterator(); i.hasNext();) {
|
for (Iterator i = sqlConnections.values().iterator(); i.hasNext();) {
|
||||||
try {
|
try {
|
||||||
DbConnection con = (DbConnection) i.next();
|
Connection con = (Connection) i.next();
|
||||||
|
|
||||||
con.close();
|
con.close();
|
||||||
nmgr.app.logEvent("Closing DB connection: " + con);
|
nmgr.app.logEvent("Closing DB connection: " + con);
|
||||||
} catch (Exception x) {
|
} catch (Exception ignore) {
|
||||||
nmgr.app.logEvent("Error closing DB connection: " + x);
|
// exception closing db connection, ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue