User: mulder
Date: 00/10/20 22:20:24
Modified: src/main/org/jboss/tm TransactionImpl.java TxCapsule.java
XidImpl.java
Log:
Make jBoss work with Oracle XADataSource driver.
Not yet a very elegant solution - we need to be able to use a different
Xid implementation class per pool for this to really work right.
The requirements of the Oracle driver were:
- Xid must be instanceof OracleXid
- Global and Branch IDs must be exactly 64 bytes
- RM that end is called on must be *exactly* the same as start
was called on (XAConnection.getXAResource returns a different
instance each time *despite* the documented 1-to-1 relation)
- Can't execute DDL (create/drop table, etc) within a transaction
Haven't tested this well with multiple data sources - that's next.
Revision Changes Path
1.10 +8 -8 jboss/src/main/org/jboss/tm/TransactionImpl.java
Index: TransactionImpl.java
===================================================================
RCS file: /products/cvs/ejboss/jboss/src/main/org/jboss/tm/TransactionImpl.java,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- TransactionImpl.java 2000/09/28 21:10:11 1.9
+++ TransactionImpl.java 2000/10/21 05:20:23 1.10
@@ -35,7 +35,7 @@
* @author Rickard �berg ([EMAIL PROTECTED])
* @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Ole Husgaard</a>
- * @version $Revision: 1.9 $
+ * @version $Revision: 1.10 $
*/
public class TransactionImpl
implements Transaction, Serializable
@@ -44,17 +44,17 @@
// Attributes ----------------------------------------------------
- XidImpl xid; // Transaction ID.
-
+ Xid xid; // Transaction ID.
+
// Constructors --------------------------------------------------
-
- TransactionImpl(TxCapsule txCapsule, XidImpl xid)
+
+ TransactionImpl(TxCapsule txCapsule, Xid xid)
{
this.txCapsule = txCapsule;
- this.xid = xid;
+ this.xid = xid;
travelled = false;
}
-
+
// Public --------------------------------------------------------
// In the following methods we synchronize to avoid races with transaction
@@ -153,7 +153,7 @@
public int hashCode()
{
- return xid.hash;
+ return xid.hashCode();
}
public String toString()
1.17 +64 -29 jboss/src/main/org/jboss/tm/TxCapsule.java
Index: TxCapsule.java
===================================================================
RCS file: /products/cvs/ejboss/jboss/src/main/org/jboss/tm/TxCapsule.java,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- TxCapsule.java 2000/10/20 03:14:56 1.16
+++ TxCapsule.java 2000/10/21 05:20:23 1.17
@@ -7,6 +7,7 @@
package org.jboss.tm;
import java.io.Serializable;
+import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Set;
import java.util.HashSet;
@@ -43,14 +44,16 @@
* @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Ole Husgaard</a>
*
- * @version $Revision: 1.16 $
+ * @version $Revision: 1.17 $
*/
class TxCapsule implements TimeoutTarget
{
// Constants -----------------------------------------------------
// Trace enabled flag
- static private final boolean trace = true;
+ static private final boolean trace = false;
+ // Constructor for Xid instances
+ private static Constructor xidConstructor = null;
// Code meaning "no heuristics seen", must not be XAException.XA_HEURxxx
static private final int HEUR_NONE = XAException.XA_RETRY;
@@ -85,7 +88,7 @@
*/
private TxCapsule(TxManager tm)
{
- xid = new XidImpl();
+ xid = createXid();
this.tm = tm;
if (trace)
@@ -114,7 +117,7 @@
done = false;
resourcesEnded = false;
- xid = new XidImpl();
+ xid = createXid();
status = Status.STATUS_ACTIVE;
heuristicCode = HEUR_NONE;
@@ -194,7 +197,7 @@
// Package protected ---------------------------------------------
- XidImpl getXid()
+ Xid getXid()
{
return xid;
}
@@ -732,7 +735,7 @@
/**
* The ID of this transaction.
*/
- private XidImpl xid; // Transaction id
+ private Xid xid; // Transaction id
/**
* Status of this transaction.
@@ -803,7 +806,7 @@
return "STATUS_MARKED_ROLLBACK";
case Status.STATUS_ACTIVE:
return "STATUS_ACTIVE";
-
+
default:
return "STATUS_UNKNOWN(" + status + ")";
}
@@ -864,7 +867,7 @@
return "XAER_RMERR";
case XAException.XAER_RMFAIL:
return "XAER_RMFAIL";
-
+
default:
return "XA_UNKNOWN(" + errorCode + ")";
}
@@ -890,7 +893,7 @@
} catch (InterruptedException ex) {}
// MF FIXME: don't we need a notify() in this case?
- // we need to release all the thread waiting on this lock
+ // we need to release all the thread waiting on this lock
// OSH: notifyAll() is done in instanceDone()
// and notify() is done in unlock().
@@ -942,14 +945,16 @@
/**
* Return index of XAResource, or <code>-1</code> if not found.
*/
- private int findResource(XAResource xaRes)
- {
- for (int i = 0; i < resourceCount; ++i)
- if (resources[i] == xaRes)
- return i;
+ private int findResource(XAResource xaRes) {
+ int pos = -1;
+ for (int i = 0; i < resourceCount; ++i)
+ try { // FIXME: Do we need to join if there's more than one?
+ if(resources[i].isSameRM(xaRes))
+ pos = i;
+ } catch(XAException e) {}
- return -1;
- }
+ return pos;
+ }
/**
* Add a resource, expanding tables if needed.
@@ -996,18 +1001,20 @@
private void startResource(XAResource xaRes, int flags)
throws XAException
{
- Logger.debug("TxCapsule.startResource(" + xid.toString() +
- ") entered: " + xaRes.toString() +
- " flags=" + flags);
+ if(trace)
+ Logger.debug("TxCapsule.startResource(" + xid.toString() +
+ ") entered: " + xaRes.toString() +
+ " flags=" + flags);
unlock();
// OSH FIXME: resourceState could be incorrect during this callout.
try {
xaRes.start(xid, flags);
} finally {
lock();
- Logger.debug("TxCapsule.startResource(" + xid.toString() +
- ") leaving: " + xaRes.toString() +
- " flags=" + flags);
+ if(trace)
+ Logger.debug("TxCapsule.startResource(" + xid.toString() +
+ ") leaving: " + xaRes.toString() +
+ " flags=" + flags);
}
}
@@ -1018,18 +1025,20 @@
private void endResource(XAResource xaRes, int flag)
throws XAException
{
- Logger.debug("TxCapsule.endResource(" + xid.toString() +
- ") entered: " + xaRes.toString() +
- " flag=" + flag);
+ if(trace)
+ Logger.debug("TxCapsule.endResource(" + xid.toString() +
+ ") entered: " + xaRes.toString() +
+ " flag=" + flag);
unlock();
// OSH FIXME: resourceState could be incorrect during this callout.
try {
xaRes.end(xid, flag);
} finally {
lock();
- Logger.debug("TxCapsule.endResource(" + xid.toString() +
- ") leaving: " + xaRes.toString() +
- " flag=" + flag);
+ if(trace)
+ Logger.debug("TxCapsule.endResource(" + xid.toString() +
+ ") leaving: " + xaRes.toString() +
+ " flag=" + flag);
}
}
@@ -1304,7 +1313,9 @@
status = Status.STATUS_COMMITTING;
for (int i = 0; i < resourceCount; i++) {
- Logger.debug("TxCapsule.commitResources():
resourceStates["+i+"]="+resourceState[i]);
+ if(trace) {
+ Logger.debug("TxCapsule.commitResources():
resourceStates["+i+"]="+resourceState[i]);
+ }
if (!onePhase && resourceState[i] != RS_VOTE_OK)
continue;
@@ -1376,11 +1387,35 @@
Logger.exception(e);
break;
}
+ try {
+ resources[i].forget(xid);
+ } catch(XAException forgetEx) {}
}
}
status = Status.STATUS_ROLLEDBACK;
}
+
+ private Xid createXid() {
+ String name = System.getProperty("jboss.xa.xidclass",
"org.jboss.tm.XidImpl");
+ if(xidConstructor == null) {
+ try {
+ Class cls = Class.forName(name);
+ xidConstructor = cls.getConstructor(new Class[]{Integer.TYPE,
byte[].class, byte[].class});
+ } catch(Exception e) {
+ System.out.println("Unable to load Xid class '"+name+"'");
+ }
+ }
+ try {
+ Object xid = xidConstructor.newInstance(new Object[]{new
Integer(XidImpl.getJbossFormatId()),
+
XidImpl.getGlobalIdString(XidImpl.getNextId()),
+
XidImpl.noBranchQualifier});
+ return (Xid)xid;
+ } catch(Exception e) {
+ System.out.println("Unable to create an Xid (reverting to default
impl): "+e);
+ return new XidImpl(XidImpl.getJbossFormatId(),
XidImpl.getGlobalIdString(XidImpl.getNextId()), XidImpl.noBranchQualifier);
+ }
+ }
// Inner classes -------------------------------------------------
}
1.5 +36 -20 jboss/src/main/org/jboss/tm/XidImpl.java
Index: XidImpl.java
===================================================================
RCS file: /products/cvs/ejboss/jboss/src/main/org/jboss/tm/XidImpl.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- XidImpl.java 2000/09/28 21:10:11 1.4
+++ XidImpl.java 2000/10/21 05:20:23 1.5
@@ -18,13 +18,13 @@
* @see TransactionImpl
* @author Rickard �berg ([EMAIL PROTECTED])
* @author <a href="mailto:[EMAIL PROTECTED]">Ole Husgaard</a>
- * @version $Revision: 1.4 $
+ * @version $Revision: 1.5 $
*/
class XidImpl
implements Xid, java.io.Serializable
{
// Constants -----------------------------------------------------
-
+
// Attributes ----------------------------------------------------
/**
@@ -42,7 +42,7 @@
* This identifies the branch of a transaction.
*/
byte[] branchId;
-
+
// Static --------------------------------------------------------
/**
@@ -66,7 +66,7 @@
hostName = "localhost/";
}
}
-
+
return hostName;
}
@@ -78,7 +78,7 @@
/**
* Return a new unique transaction id to use on this host.
*/
- static private synchronized int getNextId()
+ static synchronized int getNextId()
{
return nextId++;
}
@@ -86,18 +86,22 @@
/**
* Singleton for no branch qualifier.
*/
- static private byte[] noBranchQualifier = new byte[0];
+ static byte[] noBranchQualifier = new byte[MAXBQUALSIZE];
+ static {
+ for(int i=0; i<noBranchQualifier.length; i++)
+ noBranchQualifier[i] = 0;
+ }
// Constructors --------------------------------------------------
/**
* Create a new unique branch qualifier.
*/
- public XidImpl()
+ public XidImpl(int formatId, byte[] globalId, byte[] branchId)
{
- hash = getNextId();
- this.globalId = getGlobalIdString().getBytes();
- this.branchId = noBranchQualifier;
+ this.hash = getNextId();
+ this.globalId = globalId;
+ this.branchId = branchId;
}
/**
@@ -109,9 +113,9 @@
this.globalId = xid.globalId;
this.branchId = branchId;
}
-
+
// Public --------------------------------------------------------
-
+
// Xid implementation --------------------------------------------
/**
@@ -121,7 +125,7 @@
{
return (byte[])globalId.clone();
}
-
+
/**
* Return the branch qualifier of this transaction.
*/
@@ -139,7 +143,11 @@
* The format identifier augments the global id and specifies
* how the global id and branch qualifier should be interpreted.
*/
- public int getFormatId()
+ public int getFormatId() {
+ return getJbossFormatId();
+ }
+
+ public static int getJbossFormatId()
{
// The id we return here should be different from all other transaction
// implementations.
@@ -150,7 +158,7 @@
// OSI TP do have the same id format.)
// 0xBB14: Used by JONAS
// 0xBB20: Used by JONAS
- return 1;
+ return 0x0101;
}
/**
@@ -185,18 +193,26 @@
public String toString()
{
- return "XidImpl:" + getGlobalIdString();
+ return "XidImpl:" + getGlobalTransactionId();
}
// Package protected ---------------------------------------------
-
+
// Protected -----------------------------------------------------
-
+
// Private -------------------------------------------------------
- private String getGlobalIdString()
+ static byte[] getGlobalIdString(int hash)
{
- return getHostName() + hash;
+ String value;
+ String s = getHostName();
+ String h = Integer.toString(hash);
+ if(s.length() + h.length() > 64) {
+ value = s.substring(0, 64-h.length())+h;
+ } else value = s+h;
+ byte b[] = new byte[MAXGTRIDSIZE];
+ System.arraycopy(value.getBytes(), 0, b, 0, value.length());
+ return b;
}
// Inner classes -------------------------------------------------