From: David J. <d_j...@us...> - 2001-06-14 04:48:04
|
Update of /cvsroot/firebird/client-java/src/org/firebirdsql/jca In directory usw-pr-cvs1:/tmp/cvs-serv7418/org/firebirdsql/jca Modified Files: FBConnectionRequestInfo.java FBLocalTransaction.java FBManagedConnection.java FBManagedConnectionFactory.java FBStandAloneConnectionManager.java TestFBManagedConnectionFactory.java Added Files: TestFBConnection.java TestFBResultSet.java TestFBStandAloneConnectionManager.java TestFBXAResource.java TestXABase.java Log Message: Checkin of partly working hybrid jca/jdbc driver. Datasource as ConnectionFactory for managed connection factory works, connections obtained are nearly jdbc connections: statement and prepared statement work, resultset works except for fancy fields like blobs, however transactions must be managed via connection.getLocalTransaction() similar to a javax.resource.cci.Connection. TestDBStandAloneConnectionManager shows how to set up and use the datasource. --- TestFBConnection.java ADDED --- --- TestFBResultSet.java ADDED --- --- TestFBStandAloneConnectionManager.java ADDED --- --- TestFBXAResource.java ADDED --- --- TestXABase.java ADDED --- Index: FBConnectionRequestInfo.java =================================================================== RCS file: /cvsroot/firebird/client-java/src/org/firebirdsql/jca/FBConnectionRequestInfo.java,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -U3 -r1.1.1.1 -r1.2 --- FBConnectionRequestInfo.java 2001/05/09 14:28:33 1.1.1.1 +++ FBConnectionRequestInfo.java 2001/06/14 04:48:01 1.2 @@ -30,7 +30,11 @@ import javax.resource.ResourceException; +import org.firebirdsql.gds.Clumplet; +import org.firebirdsql.gds.GDS; +import org.firebirdsql.gds.GDSFactory; + /** * * @see <related> @@ -53,6 +57,52 @@ **/ public class FBConnectionRequestInfo implements ConnectionRequestInfo { + + private Clumplet c = null; + + public FBConnectionRequestInfo() { + } + + public FBConnectionRequestInfo(FBConnectionRequestInfo src) { + c = GDSFactory.cloneClumplet(src.c); + } + + Clumplet getDpb() { + return c; + } + + public void setProperty(int type, String content) { + append(GDSFactory.newClumplet(type, content)); + } + + public void setProperty(int type) { + append(GDSFactory.newClumplet(type)); + } + + public void setProperty(int type, int content) { + append(GDSFactory.newClumplet(type, content)); + } + + public void setProperty(int type, byte[] content) { + append(GDSFactory.newClumplet(type, content)); + } + + private void append(Clumplet newc) { + if (c == null) { + c = newc; + } + else { + c.append(newc); + } + } + + public void setUser(String user) { + setProperty(GDS.isc_dpb_user_name, user); + } + + public void setPassword(String password) { + setProperty(GDS.isc_dpb_password, password); + } /** Checks whether this instance is equal to another. Since connectionRequestInfo is defined @@ -65,8 +115,15 @@ **/ - public boolean equals(java.lang.Object other) { - return false;//not yet implemented + public boolean equals(Object other) { + if ((other == null) || !(other instanceof FBConnectionRequestInfo)) { + return false; + } + Clumplet otherc = ((FBConnectionRequestInfo)other).c; + if (c == null) { + return (otherc == null); + } + return c.equals(otherc); } /** @@ -78,7 +135,10 @@ **/ public int hashCode() { - return 0;//not yet implemented; + if (c == null) { + return 0; + } + return c.hashCode(); } } Index: FBLocalTransaction.java =================================================================== RCS file: /cvsroot/firebird/client-java/src/org/firebirdsql/jca/FBLocalTransaction.java,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -U3 -r1.1.1.1 -r1.2 --- FBLocalTransaction.java 2001/05/09 14:28:29 1.1.1.1 +++ FBLocalTransaction.java 2001/06/14 04:48:01 1.2 @@ -27,19 +27,41 @@ // imports -------------------------------------- +import javax.resource.spi.ConnectionEvent; import javax.resource.spi.LocalTransaction; import javax.resource.ResourceException; +import javax.transaction.xa.XAException; +import javax.transaction.xa.XAResource; +import javax.transaction.xa.Xid; +import org.firebirdsql.jdbc.FBConnection; + + /** * * @see <related> * @author David Jencks (dav...@ea...) * @version $ $ */ + + public class FBLocalTransaction implements LocalTransaction, javax.resource.cci.LocalTransaction { + + private FBManagedConnection mc; + + private Xid xid = null; - public class FBLocalTransaction implements LocalTransaction { + //used to determine if local transaction events notify ConnectionEventListeners + //see jca spec section 6.8. Basically not null means this is cci LocalTransaction, + //null means spi.LocalTransaction. + private FBConnection c = null; + + //should be package!!! perhaps reorganize and eliminate jdbc!!! + public FBLocalTransaction(FBManagedConnection mc, FBConnection c) { + this.mc = mc; + this.c = c; + } @@ -52,7 +74,19 @@ EISSystemException - EIS instance specific error condition **/ public void begin() throws ResourceException { - throw new ResourceException("Not yet implemented"); + if (xid != null) { + throw new ResourceException("local transaction active: can't begin another"); + } + xid = new FBLocalXid(); + try { + mc.start(xid, XAResource.TMNOFLAGS); //FBManagedConnection is its own XAResource + } + catch (XAException e) { + throw new ResourceException("couldn't start local transaction: " + e); + } + if (c != null) { + mc.notify(ConnectionEvent.LOCAL_TRANSACTION_STARTED, c, null); + } } @@ -65,7 +99,22 @@ EISSystemException - EIS instance specific error condition **/ public void commit() throws ResourceException { - throw new ResourceException("Not yet implemented"); + if (xid == null) { + throw new ResourceException("no local transaction active: can't commit"); + } + try { + mc.end(xid, XAResource.TMNOFLAGS); //FBManagedConnection is its own XAResource + mc.commit(xid, true); + } + catch (XAException e) { + throw new ResourceException("couldn't commit local transaction: " + e); + } + finally { + xid = null; + } + if (c != null) { + mc.notify(ConnectionEvent.LOCAL_TRANSACTION_COMMITTED, c, null); + } } @@ -81,7 +130,60 @@ **/ public void rollback() throws ResourceException { - throw new ResourceException("Not yet implemented"); + if (xid == null) { + throw new ResourceException("no local transaction active: can't rollback"); + } + try { + mc.end(xid, XAResource.TMNOFLAGS); //??? on flags --FBManagedConnection is its own XAResource + mc.rollback(xid); + } + catch (XAException e) { + throw new ResourceException("couldn't commit local transaction: " + e); + } + finally { + xid = null; + } + if (c != null) { + mc.notify(ConnectionEvent.LOCAL_TRANSACTION_ROLLEDBACK, c, null); + } } + + + //This is an intentionally non-implemented xid, so if prepare is called with it, it won't work. + //Only object identity works for equals! + static class FBLocalXid implements Xid { + + private static final int formatId = 0x0102;//???????????? + + public FBLocalXid() { + } + + /** + * Return the global transaction id of this transaction. + */ + public byte[] getGlobalTransactionId() + { + return null; + } + + /** + * Return the branch qualifier of this transaction. + */ + public byte[] getBranchQualifier() + { + return null; + } + + /** + * Return the format identifier of this transaction. + * + * The format identifier augments the global id and specifies + * how the global id and branch qualifier should be interpreted. + */ + public int getFormatId() { + return formatId; + } + } + } Index: FBManagedConnection.java =================================================================== RCS file: /cvsroot/firebird/client-java/src/org/firebirdsql/jca/FBManagedConnection.java,v retrieving revision 1.3 retrieving revision 1.4 diff -U3 -r1.3 -r1.4 --- FBManagedConnection.java 2001/05/25 19:58:17 1.3 +++ FBManagedConnection.java 2001/06/14 04:48:01 1.4 @@ -31,10 +31,13 @@ import javax.resource.spi.ManagedConnection; import javax.resource.spi.ManagedConnectionMetaData; import javax.resource.spi.LocalTransaction; +import javax.resource.spi.ConnectionEvent; import javax.resource.spi.ConnectionEventListener; import javax.resource.spi.ConnectionRequestInfo; +import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Iterator; import javax.transaction.xa.XAException; import javax.transaction.xa.XAResource; import javax.transaction.xa.Xid; @@ -42,12 +45,14 @@ import javax.security.auth.Subject; import org.firebirdsql.gds.isc_db_handle; +import org.firebirdsql.gds.isc_stmt_handle; import org.firebirdsql.gds.isc_tr_handle; import org.firebirdsql.gds.GDS; import org.firebirdsql.gds.GDSException; import org.firebirdsql.gds.XSQLDA; import org.firebirdsql.gds.XSQLVAR; import org.firebirdsql.jdbc.FBConnection; +import org.firebirdsql.jdbc.FBStatement; /** * @@ -70,18 +75,26 @@ private ArrayList connectionEventListeners = new ArrayList(); + private ArrayList connectionHandles = new ArrayList(); + + private PrintWriter log; + private int timeout = 0; private Subject s; + private FBConnectionRequestInfo cri; + private isc_tr_handle currentTr; private isc_db_handle currentDbHandle; - FBManagedConnection(Subject s, FBManagedConnectionFactory mcf) { + FBManagedConnection(Subject s, FBConnectionRequestInfo cri, FBManagedConnectionFactory mcf) { this.mcf = mcf; this.s = s; + this.cri = cri; + this.log = mcf.getLogWriter(); } @@ -140,8 +153,8 @@ ResourceException - generic exception if operation fails ResourceAdapterInternalException - resource adapter related error condition **/ - public void setLogWriter(java.io.PrintWriter out) throws ResourceException { - throw new ResourceException("not yet implemented"); + public void setLogWriter(PrintWriter out){ + this.log = out; } @@ -163,8 +176,8 @@ ResourceException - generic exception if operation fails **/ - public java.io.PrintWriter getLogWriter() throws ResourceException { - throw new ResourceException("not yet implemented"); + public PrintWriter getLogWriter() { + return log; } /**<P> Add an event listener. @@ -200,6 +213,7 @@ public void associateConnection(java.lang.Object connection) throws ResourceException { try { ((FBConnection)connection).setManagedConnection(this); + connectionHandles.add(connection); } catch (ClassCastException cce) { throw new ResourceException("invalid connection supplied to associateConnection: " + cce); @@ -234,7 +248,9 @@ localtransaction is in progress that doesn't allow connection cleanup */ public void cleanup() throws ResourceException { - throw new ResourceException("not yet implemented"); + for (int i = connectionHandles.size() - 1; i>= 0; i--) { + ((FBConnection)connectionHandles.get(i)).close(); + } } /** @@ -267,8 +283,9 @@ throws ResourceException { //subject currently ignored //cxRequestInfo currently ignored. - - return new FBConnection(this); + FBConnection c = new FBConnection(this); + connectionHandles.add(c); + return c; } @@ -286,7 +303,20 @@ IllegalStateException - illegal state for destroying connection **/ public void destroy() throws ResourceException { - throw new ResourceException("not yet implemented"); + if (currentTr != null) { + throw new IllegalStateException("Can't destroy managed connection with active transaction"); + } + if (currentDbHandle != null) { + try { + mcf.gds.isc_detach_database(currentDbHandle); + } + catch (GDSException ge) { + throw new ResourceException("Can't detach from db: " + ge.toString()); + } + finally { + currentDbHandle = null; + } + } } @@ -444,16 +474,65 @@ } //FB public methods. Could be package if packages reorganized. + + public isc_stmt_handle getAllocatedStatement() throws GDSException { + //Should we test for dbhandle? + if (currentTr == null) { + throw new GDSException("No transaction started for allocate statement"); + } + isc_stmt_handle stmt = mcf.gds.get_new_isc_stmt_handle(); + mcf.gds.isc_dsql_allocate_statement(currentTr.getDbHandle(), stmt); + return stmt; + } - public boolean executeSQL(String sql) throws GDSException { + public void prepareSQL(isc_stmt_handle stmt, String sql, boolean describeBind) throws GDSException { //Should we test for dbhandle? - XSQLDA out = new XSQLDA(); - mcf.gds.isc_dsql_exec_inmed2(currentTr.getDbHandle(), currentTr, sql, - GDS.SQL_DIALECT_CURRENT, null, out); + XSQLDA out = mcf.gds.isc_dsql_prepare(currentTr, stmt, sql, GDS.SQL_DIALECT_CURRENT); + if (out.sqld != out.sqln) { + throw new GDSException("Not all columns returned"); + } + if (describeBind) { + mcf.gds.isc_dsql_describe_bind(stmt, GDS.SQLDA_VERSION1); + } + } + + public void executeStatement(isc_stmt_handle stmt) throws GDSException { + mcf.gds.isc_dsql_execute2(currentTr, stmt, + GDS.SQLDA_VERSION1, stmt.getInSqlda(), null); - return false;//Hah! } - + + public Object[] fetch(isc_stmt_handle stmt) throws GDSException { + return mcf.gds.isc_dsql_fetch(stmt, GDS.SQLDA_VERSION1, stmt.getOutSqlda()); + } + + public void closeStatement(isc_stmt_handle stmt, boolean deallocate) throws GDSException { + mcf.gds.isc_dsql_free_statement(stmt, (deallocate) ? GDS.DSQL_drop: GDS.DSQL_close); + } + + public void close(FBConnection c) { + notify(ConnectionEvent.CONNECTION_CLOSED, c, null); + connectionHandles.remove(c); + } + + public void registerStatement(FBStatement fbStatement) { + if (currentTr == null) { + throw new Error("registerStatement called with no transaction"); + } + + mcf.registerStatementWithTransaction(currentTr, fbStatement); + } + + private static byte[] stmtInfo = new byte[] + {GDS.isc_info_sql_records, + GDS.isc_info_sql_stmt_type, + GDS.isc_info_end}; + private static int INFO_SIZE = 128; + + public SqlInfo getSqlInfo(isc_stmt_handle stmt) throws GDSException { + return new SqlInfo(mcf.gds.isc_dsql_sql_info(stmt, stmtInfo.length, stmtInfo, INFO_SIZE), mcf.gds); + } + //-------------------------------------------------------------------- //package visibility //-------------------------------------------------------------------- @@ -465,15 +544,121 @@ currentDbHandle = currentTr.getDbHandle(); } } - //temporarily public for testing - public isc_db_handle getIscDBHandle() throws XAException { + + isc_db_handle getIscDBHandle() throws XAException { if (currentDbHandle == null) { - currentDbHandle = mcf.getDbHandle(); + currentDbHandle = mcf.getDbHandle(cri); } return currentDbHandle; } - - + void notify(int type, FBConnection c, Exception e) { + ConnectionEvent ce = new ConnectionEvent(this, type, e); + ce.setConnectionHandle(c); + Iterator i = connectionEventListeners.iterator(); + switch (type) { + case ConnectionEvent.CONNECTION_CLOSED: + while (i.hasNext()) { + ((ConnectionEventListener)i.next()).connectionClosed(ce); + } + case ConnectionEvent.CONNECTION_ERROR_OCCURRED: + while (i.hasNext()) { + ((ConnectionEventListener)i.next()).connectionErrorOccurred(ce); + } + case ConnectionEvent.LOCAL_TRANSACTION_STARTED: + while (i.hasNext()) { + ((ConnectionEventListener)i.next()).localTransactionStarted(ce); + } + case ConnectionEvent.LOCAL_TRANSACTION_COMMITTED: + while (i.hasNext()) { + ((ConnectionEventListener)i.next()).localTransactionCommitted(ce); + } + case ConnectionEvent.LOCAL_TRANSACTION_ROLLEDBACK: + while (i.hasNext()) { + ((ConnectionEventListener)i.next()).localTransactionRolledback(ce); + } + + default: +// throw new + } + } + + //----------------------------------------- + //Private methods + //----------------------------------------- + + public static class SqlInfo { + private int statementType; + private int insertCount; + private int updateCount; + private int deleteCount; + private int selectCount; //???? + + SqlInfo(byte[] buffer, GDS gds) { + int pos = 0; + int length; + int type; + while ((type = buffer[pos++]) != GDS.isc_info_end) { + length = gds.isc_vax_integer(buffer, pos, 2); + pos += 2; + switch (type) { + case GDS.isc_info_sql_records: + int l; + int t; + while ((t = buffer[pos++]) != GDS.isc_info_end) { + l = gds.isc_vax_integer(buffer, pos, 2); + pos += 2; + switch (t) { + case GDS.isc_info_req_insert_count: + insertCount = gds.isc_vax_integer(buffer, pos, l); + break; + case GDS.isc_info_req_update_count: + updateCount = gds.isc_vax_integer(buffer, pos, l); + break; + case GDS.isc_info_req_delete_count: + deleteCount = gds.isc_vax_integer(buffer, pos, l); + break; + case GDS.isc_info_req_select_count: + selectCount = gds.isc_vax_integer(buffer, pos, l); + break; + default: + break; + } + pos += l; + } + break; + case GDS.isc_info_sql_stmt_type: + statementType = gds.isc_vax_integer(buffer, pos, length); + pos += length; + break; + default: + pos += length; + break; + } + } + } + + public int getStatementType() { + return statementType; + } + + public int getInsertCount() { + return insertCount; + } + + public int getUpdateCount() { + return updateCount; + } + + public int getDeleteCount() { + return deleteCount; + } + + public int getSelectCount() { + return selectCount; + } + } + + } Index: FBManagedConnectionFactory.java =================================================================== RCS file: /cvsroot/firebird/client-java/src/org/firebirdsql/jca/FBManagedConnectionFactory.java,v retrieving revision 1.2 retrieving revision 1.3 diff -U3 -r1.2 -r1.3 --- FBManagedConnectionFactory.java 2001/05/25 16:21:49 1.2 +++ FBManagedConnectionFactory.java 2001/06/14 04:48:01 1.3 @@ -36,8 +36,11 @@ import javax.transaction.xa.XAResource; +import java.io.PrintWriter; import java.util.Set; import java.util.HashMap; +import java.util.ArrayList; +import java.util.Iterator; import java.util.LinkedList; import java.util.NoSuchElementException; @@ -49,7 +52,9 @@ import org.firebirdsql.gds.GDS; import org.firebirdsql.gds.GDSException; import org.firebirdsql.gds.Clumplet; -import org.firebirdsql.jgds.GDS_Impl; +import org.firebirdsql.gds.GDSFactory; +import org.firebirdsql.jdbc.FBDataSource; +import org.firebirdsql.jdbc.FBStatement; /** * @@ -68,8 +73,10 @@ */ public class FBManagedConnectionFactory implements ManagedConnectionFactory { - - GDS gds = new GDS_Impl(); + + private PrintWriter log = new PrintWriter(System.out); + + GDS gds = GDSFactory.newGDS(); private String dbAlias; @@ -77,6 +84,10 @@ private HashMap xidMap = new HashMap(); //Maps supplied XID to internal transaction handle. + private HashMap TransactionStatementMap = new HashMap(); //Maps transaction handle to list of statements with resultsets. + + private FBConnectionRequestInfo defaultCri; + private Clumplet dpbClumplet; private Set tpbSet; @@ -95,14 +106,23 @@ return dbAlias; } - public void setDpb(Clumplet dpb) { - dpbClumplet = dpb; + public void setConnectionRequestInfo(FBConnectionRequestInfo cri) { + this.defaultCri = cri; } - public Clumplet getDpb() { - return dpbClumplet; + public FBConnectionRequestInfo getDefaultConnectionRequestInfo() { + return defaultCri; } +/* public void setDpb(Clumplet dpb) { + dpbClumplet = dpb; + }*/ + +/* public Clumplet getDpb() { +// return dpbClumplet; + return defaultCri.c; + }*/ + public void setTpb(Set tpb) { tpbSet = tpb; } @@ -126,7 +146,7 @@ ResourceAdapterInternalException - Resource adapter related error condition **/ public java.lang.Object createConnectionFactory(ConnectionManager cxManager) throws ResourceException { - throw new ResourceException("not yet implemented"); + return new FBDataSource(this, cxManager); } @@ -144,7 +164,7 @@ **/ public java.lang.Object createConnectionFactory() throws ResourceException { - throw new ResourceException("not yet implemented"); + return new FBDataSource(this, new FBStandAloneConnectionManager()); } @@ -172,8 +192,10 @@ public ManagedConnection createManagedConnection(Subject subject, ConnectionRequestInfo cxRequestInfo) throws ResourceException { - //ignore ConnectionRequestInfo till we think of something to use it for. - return new FBManagedConnection(subject, this); + if (cxRequestInfo == null) { + cxRequestInfo = defaultCri; + } + return new FBManagedConnection(subject, (FBConnectionRequestInfo)cxRequestInfo, this); } @@ -237,8 +259,8 @@ **/ - public void setLogWriter(java.io.PrintWriter out) throws ResourceException { - throw new ResourceException("not yet implemented"); + public void setLogWriter(PrintWriter out) throws ResourceException { + this.log = out; } @@ -258,8 +280,8 @@ ResourceException - generic exception **/ - public java.io.PrintWriter getLogWriter() throws ResourceException { - throw new ResourceException("not yet implemented"); + public PrintWriter getLogWriter() { + return log; } @@ -302,8 +324,6 @@ } //needs synchronization! - //Also needs to use firebirds multi-db transactions! - //returns uninitialized tr_handle if first use. isc_tr_handle getCurrentIscTrHandle(Xid xid, FBManagedConnection mc, int flags) throws XAException { isc_tr_handle tr = lookupXid(xid); if (tr == null) { @@ -330,7 +350,7 @@ } - isc_db_handle getDbHandle() throws XAException { + isc_db_handle getDbHandle(FBConnectionRequestInfo cri) throws XAException { try { synchronized (freeDbHandles) { return (isc_db_handle)freeDbHandles.removeLast(); @@ -338,7 +358,7 @@ } catch (NoSuchElementException e) { isc_db_handle db = gds.get_new_isc_db_handle(); try { - gds.isc_attach_database(dbAlias, db, getDpb()); + gds.isc_attach_database(dbAlias, db, cri.getDpb()); } catch (GDSException ge) { throw new XAException(ge.toString()); @@ -351,9 +371,13 @@ freeDbHandles.addLast(db); } + + void commit(Xid xid) throws XAException { + isc_tr_handle tr = lookupXid(xid); + forgetResultSets(tr); try { - gds.isc_commit_transaction(lookupXid(xid)); + gds.isc_commit_transaction(tr); } catch (GDSException ge) { throw new XAException(ge.toString()); @@ -384,8 +408,10 @@ } void rollback(Xid xid) throws XAException { + isc_tr_handle tr = lookupXid(xid); + forgetResultSets(tr); try { - gds.isc_rollback_transaction(lookupXid(xid)); + gds.isc_rollback_transaction(tr); } catch (GDSException ge) { throw new XAException(ge.toString()); @@ -394,16 +420,34 @@ forgetXid(xid); } } - - -/*public at the moment, at the top - private Clumplet getDpb() { - return dpbClumplet; + + void registerStatementWithTransaction(isc_tr_handle tr, FBStatement stmt) { + ArrayList stmts = null; + synchronized (tr) { + stmts = (ArrayList)TransactionStatementMap.get(tr); + if (stmts == null) { + stmts = new ArrayList(); + TransactionStatementMap.put(tr, stmts); + } + } + stmts.add(stmt); } - private Set getTpb() { - return tpbSet; - }*/ + private void forgetResultSets(isc_tr_handle tr) { + //shouldn't need synchronization, only called by rollback and commit- then we're done + //transaction/thread should also help. + ArrayList stmts = (ArrayList)TransactionStatementMap.get(tr); + if (stmts != null) { + Iterator i = stmts.iterator(); + while (i.hasNext()) { + ((FBStatement)i.next()).forgetResultSet(); + } + stmts.clear(); + } + } + + + } Index: FBStandAloneConnectionManager.java =================================================================== RCS file: /cvsroot/firebird/client-java/src/org/firebirdsql/jca/FBStandAloneConnectionManager.java,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -U3 -r1.1.1.1 -r1.2 --- FBStandAloneConnectionManager.java 2001/05/09 14:28:40 1.1.1.1 +++ FBStandAloneConnectionManager.java 2001/06/14 04:48:01 1.2 @@ -26,11 +26,17 @@ // imports -------------------------------------- +import java.io.PrintWriter; + +import javax.resource.ResourceException; + +import javax.resource.spi.ConnectionEvent; +import javax.resource.spi.ConnectionEventListener; import javax.resource.spi.ConnectionRequestInfo; import javax.resource.spi.ConnectionManager; +import javax.resource.spi.ManagedConnection; import javax.resource.spi.ManagedConnectionFactory; -import javax.resource.ResourceException; /** @@ -65,8 +71,13 @@ **/ -public class FBStandAloneConnectionManager implements ConnectionManager { +public class FBStandAloneConnectionManager implements ConnectionManager , ConnectionEventListener { + + //package constructor + FBStandAloneConnectionManager() { + } + //javax.resource.spi.ConnectionManager implementation /** The method allocateConnection gets called by the resource adapter's connection factory @@ -92,11 +103,43 @@ **/ public java.lang.Object allocateConnection(ManagedConnectionFactory mcf, - ConnectionRequestInfo cxRequestInfo) - throws ResourceException { - throw new ResourceException("not yet implemented"); + ConnectionRequestInfo cxRequestInfo) + throws ResourceException { + + ManagedConnection mc = ((FBManagedConnectionFactory)mcf).createManagedConnection(null, cxRequestInfo); + mc.addConnectionEventListener(this); + return mc.getConnection(null, null); } - - - + + + //javax.resource.spi.ConnectionEventListener implementation + + public void connectionClosed(ConnectionEvent ce) { + PrintWriter log = ((FBManagedConnection)ce.getSource()).getLogWriter(); + try { + ((FBManagedConnection)ce.getSource()).destroy(); + } + catch (ResourceException e) { + log.println("Exception closing unmanaged connection: " + e); + } + + } + + public void connectionErrorOccurred(ConnectionEvent ce) { + PrintWriter log = ((FBManagedConnection)ce.getSource()).getLogWriter(); + try { + ((FBManagedConnection)ce.getSource()).destroy(); + } + catch (ResourceException e) { + log.println("Exception closing unmanaged connection: " + e); + } + } + + //We are only supposed to be notified of local transactions that a Connection started. + //Not much we can do with this info... + public void localTransactionStarted(ConnectionEvent event) {} + + public void localTransactionCommitted(ConnectionEvent event) {} + + public void localTransactionRolledback(ConnectionEvent event) {} } Index: TestFBManagedConnectionFactory.java =================================================================== RCS file: /cvsroot/firebird/client-java/src/org/firebirdsql/jca/TestFBManagedConnectionFactory.java,v retrieving revision 1.2 retrieving revision 1.3 diff -U3 -r1.2 -r1.3 --- TestFBManagedConnectionFactory.java 2001/05/25 19:58:17 1.2 +++ TestFBManagedConnectionFactory.java 2001/06/14 04:48:01 1.3 @@ -11,11 +11,16 @@ import javax.resource.spi.*; import javax.transaction.xa.*; import java.sql.Connection; +import java.sql.Statement; //import org.firebirdsql.jca.*; import org.firebirdsql.gds.Clumplet; import org.firebirdsql.gds.GDS; +import org.firebirdsql.gds.GDSFactory; import org.firebirdsql.jgds.GDS_Impl; +import org.firebirdsql.management.FBManager; +import org.firebirdsql.jdbc.FBConnection; + import java.io.*; import java.util.Properties; import java.util.HashSet; @@ -41,16 +46,8 @@ *This is a class that hands out connections. Initial implementation uses DriverManager.getConnection, *future enhancements will use datasources/ managed stuff. */ -public class TestFBManagedConnectionFactory extends TestCase { - - static final String dbName = "localhost/3050:/usr/local/firebird/dev/client-java/db/jbosstest.gdb"; - static final String dbName2 = "localhost:/usr/local/firebird/dev/client-java/db/testdb2.gdb"; - -// private FBManagedConnectionFactory mcf; - -// private Clumplet dpb; +public class TestFBManagedConnectionFactory extends TestXABase { -// private HashSet tpb; public TestFBManagedConnectionFactory(String name) { super(name); @@ -61,23 +58,24 @@ return new TestSuite(TestFBManagedConnectionFactory.class); } - public FBManagedConnectionFactory initMcf() { - - FBManagedConnectionFactory mcf = new FBManagedConnectionFactory(); - mcf.setDatabase(dbName); - GDS gds = new GDS_Impl(); - Clumplet dpb = gds.newClumplet(GDS.isc_dpb_num_buffers, new byte[] {90}); - dpb.append(gds.newClumplet(GDS.isc_dpb_dummy_packet_interval, new byte[] {120, 10, 0, 0})); - mcf.setDpb(dpb); - HashSet tpb = new HashSet(); - tpb.add(new Integer(GDS.isc_tpb_write)); - tpb.add(new Integer(GDS.isc_tpb_read_committed)); - tpb.add(new Integer(GDS.isc_tpb_no_rec_version)); - tpb.add(new Integer(GDS.isc_tpb_wait)); - mcf.setTpb(tpb); - return mcf; + public void _setUp() throws Exception { + FBManager m = new FBManager(); + m.setURL("localhost"); + m.setPort(3050); + m.start(); + m.createDatabase(DBNAME); + m.stop(); + } + + public void _tearDown() throws Exception { + FBManager m = new FBManager(); + m.setURL("localhost"); + m.setPort(3050); + m.start(); + m.dropDatabase(DBNAME); + m.stop(); } - + @@ -95,426 +93,77 @@ System.out.println("testCreateMc"); FBManagedConnectionFactory mcf = initMcf(); ManagedConnection mc = mcf.createManagedConnection(null, null); + mc.destroy(); } - public void testCreateC() throws Exception { - System.out.println(); - System.out.println("testCreateC"); - FBManagedConnectionFactory mcf = initMcf(); - ManagedConnection mc = mcf.createManagedConnection(null, null); - Connection c = (Connection)mc.getConnection(null, null); - } - - public void testAssociateC() throws Exception { - System.out.println(); - System.out.println("testAssociateC"); - FBManagedConnectionFactory mcf = initMcf(); - ManagedConnection mc1 = mcf.createManagedConnection(null, null); - Connection c1 = (Connection)mc1.getConnection(null, null); - ManagedConnection mc2 = mcf.createManagedConnection(null, null); - Connection c2 = (Connection)mc2.getConnection(null, null); - mc1.associateConnection(c2); - mc2.associateConnection(c1); - } - public void testCreateStatement() throws Exception { - System.out.println(); - System.out.println("testCreateStatement"); - FBManagedConnectionFactory mcf = initMcf(); - ManagedConnection mc = mcf.createManagedConnection(null, null); - Connection c = (Connection)mc.getConnection(null, null); - Statement s = c.createStatement(); - } - - public void testUseStatement() throws Exception { + + public void testSqlInfo() throws Exception { System.out.println(); - System.out.println("testCreateStatement"); + System.out.println("testSqlInfo"); + byte[] testbuffer = { +23, //isc_info_sql_records +29, //length +0, +15, //isc_info_req_update_count +4,//length +0, +4, +0, +0, +0, +16,//isc_info_req_delete_count +4,//length +0, +3, +0, +0, +0, +13,//isc_info_req_select_count +4,//length +0, +2, +0, +0, +0, +14,//isc_info_req_insert_count +4,//length +0, +1, +0, +0, +0, +1, //isc_info_end +21, //isc_info_sql_stmt_type +4, //length +0, +2, //isc_info_sql_stmt_insert +0, +0, +0, +1, //isc_info_end +0, +0, +0, +0, +0, +0, +0, +0, +0, +0}; FBManagedConnectionFactory mcf = initMcf(); ManagedConnection mc = mcf.createManagedConnection(null, null); - Connection c = (Connection)mc.getConnection(null, null); - Statement s = c.createStatement(); - XAResource xa = mc.getXAResource(); - Xid xid = new XidImpl(); - xa.start(xid, XAResource.TMNOFLAGS); - s.execute("CREATE TABLE T1 ( C1 SMALLINT, C2 SMALLINT)"); - xa.end(xid, XAResource.TMNOFLAGS); - xa.commit(xid, true); + FBManagedConnection.SqlInfo si = new FBManagedConnection.SqlInfo(testbuffer, GDSFactory.newGDS()); - xid = new XidImpl(); - xa.start(xid, XAResource.TMNOFLAGS); - s.execute("DROP TABLE T1"); - xa.end(xid, XAResource.TMNOFLAGS); - xa.commit(xid, true); + assert("selectcount wrong " + si.getSelectCount(), si.getSelectCount() == 2); + assert("insertcount wrong " + si.getInsertCount(), si.getInsertCount() == 1); + assert("updatecount wrong " + si.getUpdateCount(), si.getUpdateCount() == 4); + assert("deletecount wrong " + si.getDeleteCount(), si.getDeleteCount() == 3); + assert("statement type wrong " + si.getStatementType(), si.getStatementType() == 2); + mc.destroy(); } - - public void testGetXAResource() throws Exception { - System.out.println(); - System.out.println("testGetXAResource"); - FBManagedConnectionFactory mcf = initMcf(); - ManagedConnection mc = mcf.createManagedConnection(null, null); - XAResource xa1 = mc.getXAResource(); - XAResource xa2 = mc.getXAResource(); - if (xa1 != xa2) { - throw new Exception("XAResources do not match from same mc"); - } - } - - public void testIsSameRM() throws Exception { - System.out.println(); - System.out.println("testIsSameRM"); - FBManagedConnectionFactory mcf1 = initMcf(); - ManagedConnection mc1 = mcf1.createManagedConnection(null, null); - XAResource xa1 = mc1.getXAResource(); - ManagedConnection mc2 = mcf1.createManagedConnection(null, null); - XAResource xa2 = mc2.getXAResource(); - FBManagedConnectionFactory mcf3 = initMcf(); - ManagedConnection mc3 = mcf3.createManagedConnection(null, null); - XAResource xa3 = mc3.getXAResource(); - if (!xa1.isSameRM(xa2)) { - throw new Exception("isSameRM reports difference from same mcf"); - } - if (xa1.isSameRM(xa3)) { - throw new Exception("isSameRM reports no difference from different mcf"); - } - } - - public void testStartXATrans() throws Exception { - System.out.println(); - System.out.println("testStartXATrans"); - FBManagedConnectionFactory mcf = initMcf(); - ManagedConnection mc = mcf.createManagedConnection(null, null); - FBManagedConnection fbmc = (FBManagedConnection)mc; - XAResource xa = mc.getXAResource(); - Xid xid = new XidImpl(); - xa.start(xid, XAResource.TMNOFLAGS); - if (fbmc.getIscDBHandle() == null) { - throw new Exception("no db handle after start xid"); - } - xa.end(xid, XAResource.TMNOFLAGS); - xa.commit(xid, true); - } - - public void testRollbackXATrans() throws Exception { - System.out.println(); - System.out.println("testStartXATrans"); - FBManagedConnectionFactory mcf = initMcf(); - ManagedConnection mc = mcf.createManagedConnection(null, null); - FBManagedConnection fbmc = (FBManagedConnection)mc; - XAResource xa = mc.getXAResource(); - Xid xid = new XidImpl(); - xa.start(xid, XAResource.TMNOFLAGS); - if (fbmc.getIscDBHandle() == null) { - throw new Exception("no db handle after start xid"); - } - xa.end(xid, XAResource.TMNOFLAGS); - xa.rollback(xid); - } - - public void test2PCXATrans() throws Exception { - System.out.println(); - System.out.println("testStartXATrans"); - FBManagedConnectionFactory mcf = initMcf(); - ManagedConnection mc = mcf.createManagedConnection(null, null); - FBManagedConnection fbmc = (FBManagedConnection)mc; - XAResource xa = mc.getXAResource(); - Xid xid = new XidImpl(); - xa.start(xid, XAResource.TMNOFLAGS); - if (fbmc.getIscDBHandle() == null) { - throw new Exception("no db handle after start xid"); - } - xa.end(xid, XAResource.TMNOFLAGS); - xa.prepare(xid); - xa.commit(xid, false); - } - - public void testRollback2PCXATrans() throws Exception { - System.out.println(); - System.out.println("testStartXATrans"); - FBManagedConnectionFactory mcf = initMcf(); - ManagedConnection mc = mcf.createManagedConnection(null, null); - FBManagedConnection fbmc = (FBManagedConnection)mc; - XAResource xa = mc.getXAResource(); - Xid xid = new XidImpl(); - xa.start(xid, XAResource.TMNOFLAGS); - if (fbmc.getIscDBHandle() == null) { - throw new Exception("no db handle after start xid"); - } - xa.end(xid, XAResource.TMNOFLAGS); - xa.prepare(xid); - xa.rollback(xid); - } - - public void testDo2XATrans() throws Exception { - System.out.println(); - System.out.println("testDo2XATrans"); - FBManagedConnectionFactory mcf = initMcf(); - ManagedConnection mc1 = mcf.createManagedConnection(null, null); - FBManagedConnection fbmc1 = (FBManagedConnection)mc1; - XAResource xa1 = mc1.getXAResource(); - Xid xid1 = new XidImpl(); - xa1.start(xid1, XAResource.TMNOFLAGS); - if (fbmc1.getIscDBHandle() == null) { - throw new Exception("no db handle after start xid"); - } - ManagedConnection mc2 = mcf.createManagedConnection(null, null); - FBManagedConnection fbmc2 = (FBManagedConnection)mc2; - XAResource xa2 = mc2.getXAResource(); - Xid xid2 = new XidImpl(); - xa2.start(xid2, XAResource.TMNOFLAGS); - if (fbmc2.getIscDBHandle() == null) { - throw new Exception("no db handle after start xid"); - } - //commit each tr on other xares - xa1.end(xid1, XAResource.TMNOFLAGS); - xa2.commit(xid1, true); - xa2.end(xid2, XAResource.TMNOFLAGS); - xa1.commit(xid2, true); - - } - - /*Borrowed from - * JBoss, the OpenSource EJB server - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ - /* - package org.firebirdsql.jca.test; - - import java.net.InetAddress; - import java.net.UnknownHostException; - - import javax.transaction.xa.Xid; - */ - - /** - * This object encapsulates the ID of a transaction. - * This implementation is immutable and always serializable at runtime. - * - * @see TransactionImpl - * @author Rickard Öberg (ric...@te...) - * @author <a href="mailto:os...@sp...">Ole Husgaard</a> - * @version $Revision$ - */ - public static class XidImpl - implements Xid, java.io.Serializable - { - // Constants ----------------------------------------------------- - - public static final int JBOSS_FORMAT_ID = 0x0101; - - // Attributes ---------------------------------------------------- - - /** - * Hash code of this instance. This is really a sequence number. - */ - private int hash; - - /** - * Global transaction id of this instance. - * The coding of this class depends on the fact that this variable is - * initialized in the constructor and never modified. References to - * this array are never given away, instead a clone is delivered. - */ - private byte[] globalId; - - /** - * Branch qualifier of this instance. - * This identifies the branch of a transaction. - */ - private byte[] branchId; - - // Static -------------------------------------------------------- - - /** - * The host name of this host, followed by a slash. - * - * This is used for building globally unique transaction identifiers. - * It would be safer to use the IP address, but a host name is better - * for humans to read and will do for now. - */ - private static String hostName; - - /** - * The next transaction id to use on this host. - */ - static private int nextId = 0; - - /** - * Return a new unique transaction id to use on this host. - */ - static private synchronized int getNextId() - { - return nextId++; - } - - /** - * Singleton for no branch qualifier. - */ - static private byte[] noBranchQualifier = new byte[0]; - - /** - * Initialize the <code>hostName</code> class variable. - */ - static { - try { - hostName = InetAddress.getLocalHost().getHostName() + "/"; - // Ensure room for 14 digits of serial no. - if (hostName.length() > MAXGTRIDSIZE - 15) - hostName = hostName.substring(0, MAXGTRIDSIZE - 15); - hostName = hostName + "/"; - } catch (UnknownHostException e) { - hostName = "localhost/"; - } - } - - /** - * Return a string that describes any Xid instance. - */ - static String toString(Xid id) { - if (id == null) - return "[NULL Xid]"; - - String s = id.getClass().getName(); - s = s.substring(s.lastIndexOf('.') + 1); - s = s + " [FormatId=" + id.getFormatId() + - ", GlobalId=" + new String(id.getGlobalTransactionId()).trim() + - ", BranchQual=" + new String(id.getBranchQualifier()).trim()+"]"; - - return s; - } - - // Constructors -------------------------------------------------- - - /** - * Create a new instance. - */ - public XidImpl() - { - hash = getNextId(); - globalId = (hostName + Integer.toString(hash)).getBytes(); - branchId = noBranchQualifier; - } - - /** - * Create a new branch of an existing global transaction ID. - * - * @param xid The transaction ID to create a new branch of. - * @param branchId The ID of the new branch. - * - */ - public XidImpl(XidImpl xid, int branchId) - { - this.hash = xid.hash; - this.globalId = xid.globalId; // reuse array instance, we never modify. - this.branchId = Integer.toString(branchId).getBytes(); - } - - // Public -------------------------------------------------------- - - // Xid implementation -------------------------------------------- - - /** - * Return the global transaction id of this transaction. - */ - public byte[] getGlobalTransactionId() - { - return (byte[])globalId.clone(); - } - - /** - * Return the branch qualifier of this transaction. - */ - public byte[] getBranchQualifier() - { - if (branchId.length == 0) - return branchId; // Zero length arrays are immutable. - else - return (byte[])branchId.clone(); - } - - /** - * Return the format identifier of this transaction. - * - * The format identifier augments the global id and specifies - * how the global id and branch qualifier should be interpreted. - */ - public int getFormatId() { - // The id we return here should be different from all other transaction - // implementations. - // Known IDs are: - // -1: Sometimes used to denote a null transaction id. - // 0: OSI TP (javadoc states OSI CCR, but that is a bit misleading - // as OSI CCR doesn't even have ACID properties. But OSI CCR and - // OSI TP do have the same id format.) - // 1: Was used by early betas of jBoss. - // 0x0101: The JBOSS_FORMAT_ID we use here. - // 0xBB14: Used by JONAS. - // 0xBB20: Used by JONAS. - - return JBOSS_FORMAT_ID; - } - - /** - * Compare for equality. - * - * Instances are considered equal if they are both instances of XidImpl, - * and if they have the same global transaction id and transaction - * branch qualifier. - */ - public boolean equals(Object obj) - { - if (obj instanceof XidImpl) { - XidImpl other = (XidImpl)obj; - - if (globalId.length != other.globalId.length || - branchId.length != other.branchId.length) - return false; - - for (int i = 0; i < globalId.length; ++i) - if (globalId[i] != other.globalId[i]) - return false; - - for (int i = 0; i < branchId.length; ++i) - if (branchId[i] != other.branchId[i]) - return false; - - return true; - } - return false; - } - - public int hashCode() - { - return hash; - } - - public String toString() - { - return toString(this); - } - - // Package protected --------------------------------------------- - - /** - * Return the global transaction id of this transaction. - * Unlike the {@link #getGlobalTransactionId()} method, this one - * returns a reference to the global id byte array that may <em>not</em> - * be changed. - */ - public byte[] getInternalGlobalTransactionId() - { - return (byte[])globalId.clone(); - } - - - // Protected ----------------------------------------------------- - - // Private ------------------------------------------------------- - - // Inner classes ------------------------------------------------- - } - } + |