package railo.runtime.db; import java.sql.Connection; import java.sql.SQLException; import railo.runtime.PageContext; import railo.runtime.PageContextImpl; import railo.runtime.config.ConfigImpl; import railo.runtime.engine.ThreadLocalPageContext; import railo.runtime.exp.DatabaseException; import railo.runtime.exp.DeprecatedException; import railo.runtime.exp.ExceptionHandler; import railo.runtime.exp.PageException; import railo.runtime.exp.PageRuntimeException; import railo.runtime.orm.ORMDatasourceConnection; import railo.runtime.orm.ORMSession; /** * this class handle multible db connection, transaction and logging */ public final class DatasourceManagerImpl implements DataSourceManager { public static final String QOQ_DATASOURCE_NAME = "_queryofquerydb"; private ConfigImpl config; boolean autoCommit=true; private int isolation=Connection.TRANSACTION_NONE; private DatasourceConnection transConn; /** * constructor of the class * @param pc */ public DatasourceManagerImpl(ConfigImpl c) { this.config=c; } @Override public DatasourceConnection getConnection(PageContext pc,String _datasource, String user, String pass) throws PageException { return getConnection(pc,((PageContextImpl)pc).getDataSource(_datasource), user, pass); } @Override public DatasourceConnection getConnection(PageContext pc,DataSource ds, String user, String pass) throws PageException { if(autoCommit) return config.getDatasourceConnectionPool().getDatasourceConnection(pc,ds,user,pass); pc=ThreadLocalPageContext.get(pc); DatasourceConnection dc=((PageContextImpl)pc)._getConnection(ds,user,pass); // transaction //if(!autoCommit) { try { if(transConn==null) { dc.getConnection().setAutoCommit(false); if(isolation!=Connection.TRANSACTION_NONE) dc.getConnection().setTransactionIsolation(isolation); transConn=dc; } else if(!transConn.equals(dc)) { if(QOQ_DATASOURCE_NAME.equalsIgnoreCase(ds.getName())) return dc; throw new DatabaseException( "can't use different connections inside a transaction",null,null,dc); } else if(dc.getConnection().getAutoCommit()) { dc.getConnection().setAutoCommit(false); } } catch (SQLException e) { ExceptionHandler.printStackTrace(e); } //} return dc; } public void add(PageContext pc,ORMSession session) throws PageException { // transaction if(!autoCommit) { try { if(transConn==null) { ORMDatasourceConnection dc=new ORMDatasourceConnection(pc,session); if(isolation!=Connection.TRANSACTION_NONE) dc.getConnection().setTransactionIsolation(isolation); transConn=dc; } else if(!(transConn instanceof ORMDatasourceConnection)){ /*if(transConn.getDatasource().equals(session.getEngine().getDataSource())){ ORMDatasourceConnection dc=new ORMDatasourceConnection(pc,session); if(isolation!=Connection.TRANSACTION_NONE) dc.getConnection().setTransactionIsolation(isolation); transConn=dc; } else*/ throw new DatabaseException( "can't use transaction for datasource and orm at the same time",null,null,null); } } catch (SQLException e) { ExceptionHandler.printStackTrace(e); } } } @Override public void releaseConnection(PageContext pc,DatasourceConnection dc) { if(autoCommit) config.getDatasourceConnectionPool().releaseDatasourceConnection(dc); } /*private void releaseConnection(int pid,DatasourceConnection dc) { config.getDatasourceConnectionPool().releaseDatasourceConnection(pid,dc); }*/ @Override public void begin() { this.autoCommit=false; this.isolation=Connection.TRANSACTION_NONE; } @Override public void begin(String isolation) { this.autoCommit=false; if(isolation.equalsIgnoreCase("read_uncommitted")) this.isolation=Connection.TRANSACTION_READ_UNCOMMITTED; else if(isolation.equalsIgnoreCase("read_committed")) this.isolation=Connection.TRANSACTION_READ_COMMITTED; else if(isolation.equalsIgnoreCase("repeatable_read")) this.isolation=Connection.TRANSACTION_REPEATABLE_READ; else if(isolation.equalsIgnoreCase("serializable")) this.isolation=Connection.TRANSACTION_SERIALIZABLE; else this.isolation=Connection.TRANSACTION_NONE; } @Override public void begin(int isolation) { //print.out("begin:"+autoCommit); this.autoCommit=false; this.isolation=isolation; } @Override public void rollback() throws DatabaseException { if(autoCommit)return; //autoCommit=true; if(transConn!=null) { try { transConn.getConnection().rollback(); //transConn.setAutoCommit(true); } catch (SQLException e) { throw new DatabaseException(e,transConn); } //transConn=null; } } @Override public void savepoint() throws DatabaseException { if(autoCommit)return; //autoCommit=true; if(transConn!=null) { try { transConn.getConnection().setSavepoint(); } catch (SQLException e) { throw new DatabaseException(e,transConn); } } } @Override public void commit() throws DatabaseException { //print.out("commit:"+autoCommit); if(autoCommit)return ; //autoCommit=true; if(transConn!=null) { try { transConn.getConnection().commit(); //transConn.setAutoCommit(true); } catch (SQLException e) { throw new DatabaseException(e,transConn); } //transConn=null; } } @Override public boolean isAutoCommit() { return autoCommit; } @Override public void end() { autoCommit=true; if(transConn!=null) { try { transConn.getConnection().setAutoCommit(true); } catch (SQLException e) { ExceptionHandler.printStackTrace(e); } transConn=null; } } public void remove(DataSource datasource) { config.getDatasourceConnectionPool().remove(datasource); } public void remove(String datasource) { throw new PageRuntimeException(new DeprecatedException("method no longer supported!")); //config.getDatasourceConnectionPool().remove(datasource); } public void release() { this.transConn=null; this.isolation=Connection.TRANSACTION_NONE; } }