Mercurial > hg > blitz_condensed
diff src/org/dancres/blitz/txn/TxnId.java @ 0:3dc0c5604566
Initial checkin of blitz 2.0 fcs - no installer yet.
author | Dan Creswell <dan.creswell@gmail.com> |
---|---|
date | Sat, 21 Mar 2009 11:00:06 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/dancres/blitz/txn/TxnId.java Sat Mar 21 11:00:06 2009 +0000 @@ -0,0 +1,197 @@ +package org.dancres.blitz.txn; + +import java.io.Serializable; +import java.io.IOException; + +import java.rmi.RemoteException; +import java.rmi.MarshalledObject; + +import java.util.Map; +import java.util.HashMap; + +import net.jini.security.ProxyPreparer; + +import net.jini.core.transaction.server.TransactionManager; +import net.jini.core.transaction.TransactionException; + +import net.jini.config.ConfigurationException; + +import org.dancres.blitz.entry.OpInfo; + +import org.dancres.blitz.config.ConfigurationFactory; + +/** + <p> A reference to transactional state being held within the transaction + manager. </p> + + <p> This class uses txnPreparer to do initial preparation of the + passed RemoteEventListener when constructed from scratch (i.e. it's a new + registration). It uses recoveredTxnPreparer in those cases where it + has been de-serialized from storage and is about to be used for the first + time post a restart </p> + */ +public final class TxnId implements Serializable { + private static final ProxyPreparer RECOVERY_PREPARER; + private static final ProxyPreparer PREPARER; + + static { + try { + RECOVERY_PREPARER = + ConfigurationFactory.getPreparer("recoveredTxnPreparer"); + + PREPARER = + ConfigurationFactory.getPreparer("txnPreparer"); + } catch (ConfigurationException aCE) { + throw new RuntimeException("TxnId has problems with preparers", + aCE); + } + } + + private MarshalledObject theMarshalledMgr; + private long theId; + + private transient TransactionManager theManager; + private transient boolean isPrepared; + + private static final LocalTxnManager LOCAL_TXN_MGR = + new LocalTxnManager(); + + private static final Map theMarshalledTxnMgrCache = new HashMap(); + + /** + Repeatedly marshalling the same txn mgr for writing to disk and + such like is costly so we marshall them once and then cache them + forever on the basis that we'll never see enough transaction manager + refs to make the memory consumption substantial + + @todo Broken references may be a problem.... + */ + private static MarshalledObject getMarshalledMgr(TransactionManager aMgr) + throws RemoteException { + + try { + synchronized(theMarshalledTxnMgrCache) { + MarshalledObject myMarshalledMgr = + (MarshalledObject) theMarshalledTxnMgrCache.get(aMgr); + + if (myMarshalledMgr == null) { + myMarshalledMgr = new MarshalledObject(aMgr); + theMarshalledTxnMgrCache.put(aMgr, myMarshalledMgr); + } + + return myMarshalledMgr; + } + } catch (IOException anIOE) { + throw new RemoteException("Failed to marshall txnmgr", anIOE); + } + + } + + static TxnId newNullTxn() throws RemoteException { + return new TxnId(LOCAL_TXN_MGR.nextId()); + } + + /** + Only to be used for local(null) transactions. That's because we do + no preparation on the txn manager reference (there's no point). + */ + private TxnId(long anId) throws RemoteException { + theManager = LOCAL_TXN_MGR; + theMarshalledMgr = null; + isPrepared = true; + theId = anId; + } + + /** + Use this for transactions which have a remote transaction manager + */ + TxnId(TransactionManager aMgr, long anId) throws RemoteException { + theId = anId; + + theManager = (TransactionManager) PREPARER.prepareProxy(aMgr); + + theMarshalledMgr = getMarshalledMgr(aMgr); + + isPrepared = true; + } + + boolean isNull() { + try { + return (getManager() instanceof LocalTxnManager); + } catch (RemoteException anRE) { + // This will only happen if we've tried to unpack a remote + // object reference which implicitly means it's not null + // + return false; + } + } + + public synchronized TransactionManager getManager() + throws RemoteException { + + // This flag is only set in the constructor for non-null txns or by us. + if (!isPrepared) { + Object myManager = null; + + try { + // Only null if it was a local txn mgr..... + // + if (theMarshalledMgr == null) + myManager = LOCAL_TXN_MGR; + else { + myManager = theMarshalledMgr.get(); + myManager = RECOVERY_PREPARER.prepareProxy(myManager); + } + } catch (IOException anIOE) { + throw new RemoteException("Failed to unmarshall txnmgr", + anIOE); + } catch (ClassNotFoundException aCNFE) { + throw new RemoteException("Failed to unmarshall txnmgr", + aCNFE); + } + + theManager = (TransactionManager) myManager; + isPrepared = true; + } + + return theManager; + } + + public long getId() { + return theId; + } + + public String toString() { + try { + return getManager() + "->" + theId; + } catch (RemoteException anRE) { + return "Broken_Codebase->" + theId; + } + } + + public boolean equals(Object anObject) { + if (anObject instanceof TxnId) { + TxnId myOther = (TxnId) anObject; + + if (myOther.theId != theId) + return false; + + try { + TransactionManager myMgr = getManager(); + TransactionManager myOtherMgr = myOther.getManager(); + + return myMgr.equals(myOtherMgr); + } catch (RemoteException anRE) { + // Likely to happen if codebase of txnmgr ref is broken + return false; + } + } + + return false; + } + + public int hashCode() { + return (int) (theId ^ (theId >>> 32)); + } +} +