Mercurial > hg > blitz_stable
comparison 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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:3dc0c5604566 |
---|---|
1 package org.dancres.blitz.txn; | |
2 | |
3 import java.io.Serializable; | |
4 import java.io.IOException; | |
5 | |
6 import java.rmi.RemoteException; | |
7 import java.rmi.MarshalledObject; | |
8 | |
9 import java.util.Map; | |
10 import java.util.HashMap; | |
11 | |
12 import net.jini.security.ProxyPreparer; | |
13 | |
14 import net.jini.core.transaction.server.TransactionManager; | |
15 import net.jini.core.transaction.TransactionException; | |
16 | |
17 import net.jini.config.ConfigurationException; | |
18 | |
19 import org.dancres.blitz.entry.OpInfo; | |
20 | |
21 import org.dancres.blitz.config.ConfigurationFactory; | |
22 | |
23 /** | |
24 <p> A reference to transactional state being held within the transaction | |
25 manager. </p> | |
26 | |
27 <p> This class uses txnPreparer to do initial preparation of the | |
28 passed RemoteEventListener when constructed from scratch (i.e. it's a new | |
29 registration). It uses recoveredTxnPreparer in those cases where it | |
30 has been de-serialized from storage and is about to be used for the first | |
31 time post a restart </p> | |
32 */ | |
33 public final class TxnId implements Serializable { | |
34 private static final ProxyPreparer RECOVERY_PREPARER; | |
35 private static final ProxyPreparer PREPARER; | |
36 | |
37 static { | |
38 try { | |
39 RECOVERY_PREPARER = | |
40 ConfigurationFactory.getPreparer("recoveredTxnPreparer"); | |
41 | |
42 PREPARER = | |
43 ConfigurationFactory.getPreparer("txnPreparer"); | |
44 } catch (ConfigurationException aCE) { | |
45 throw new RuntimeException("TxnId has problems with preparers", | |
46 aCE); | |
47 } | |
48 } | |
49 | |
50 private MarshalledObject theMarshalledMgr; | |
51 private long theId; | |
52 | |
53 private transient TransactionManager theManager; | |
54 private transient boolean isPrepared; | |
55 | |
56 private static final LocalTxnManager LOCAL_TXN_MGR = | |
57 new LocalTxnManager(); | |
58 | |
59 private static final Map theMarshalledTxnMgrCache = new HashMap(); | |
60 | |
61 /** | |
62 Repeatedly marshalling the same txn mgr for writing to disk and | |
63 such like is costly so we marshall them once and then cache them | |
64 forever on the basis that we'll never see enough transaction manager | |
65 refs to make the memory consumption substantial | |
66 | |
67 @todo Broken references may be a problem.... | |
68 */ | |
69 private static MarshalledObject getMarshalledMgr(TransactionManager aMgr) | |
70 throws RemoteException { | |
71 | |
72 try { | |
73 synchronized(theMarshalledTxnMgrCache) { | |
74 MarshalledObject myMarshalledMgr = | |
75 (MarshalledObject) theMarshalledTxnMgrCache.get(aMgr); | |
76 | |
77 if (myMarshalledMgr == null) { | |
78 myMarshalledMgr = new MarshalledObject(aMgr); | |
79 theMarshalledTxnMgrCache.put(aMgr, myMarshalledMgr); | |
80 } | |
81 | |
82 return myMarshalledMgr; | |
83 } | |
84 } catch (IOException anIOE) { | |
85 throw new RemoteException("Failed to marshall txnmgr", anIOE); | |
86 } | |
87 | |
88 } | |
89 | |
90 static TxnId newNullTxn() throws RemoteException { | |
91 return new TxnId(LOCAL_TXN_MGR.nextId()); | |
92 } | |
93 | |
94 /** | |
95 Only to be used for local(null) transactions. That's because we do | |
96 no preparation on the txn manager reference (there's no point). | |
97 */ | |
98 private TxnId(long anId) throws RemoteException { | |
99 theManager = LOCAL_TXN_MGR; | |
100 theMarshalledMgr = null; | |
101 isPrepared = true; | |
102 theId = anId; | |
103 } | |
104 | |
105 /** | |
106 Use this for transactions which have a remote transaction manager | |
107 */ | |
108 TxnId(TransactionManager aMgr, long anId) throws RemoteException { | |
109 theId = anId; | |
110 | |
111 theManager = (TransactionManager) PREPARER.prepareProxy(aMgr); | |
112 | |
113 theMarshalledMgr = getMarshalledMgr(aMgr); | |
114 | |
115 isPrepared = true; | |
116 } | |
117 | |
118 boolean isNull() { | |
119 try { | |
120 return (getManager() instanceof LocalTxnManager); | |
121 } catch (RemoteException anRE) { | |
122 // This will only happen if we've tried to unpack a remote | |
123 // object reference which implicitly means it's not null | |
124 // | |
125 return false; | |
126 } | |
127 } | |
128 | |
129 public synchronized TransactionManager getManager() | |
130 throws RemoteException { | |
131 | |
132 // This flag is only set in the constructor for non-null txns or by us. | |
133 if (!isPrepared) { | |
134 Object myManager = null; | |
135 | |
136 try { | |
137 // Only null if it was a local txn mgr..... | |
138 // | |
139 if (theMarshalledMgr == null) | |
140 myManager = LOCAL_TXN_MGR; | |
141 else { | |
142 myManager = theMarshalledMgr.get(); | |
143 myManager = RECOVERY_PREPARER.prepareProxy(myManager); | |
144 } | |
145 } catch (IOException anIOE) { | |
146 throw new RemoteException("Failed to unmarshall txnmgr", | |
147 anIOE); | |
148 } catch (ClassNotFoundException aCNFE) { | |
149 throw new RemoteException("Failed to unmarshall txnmgr", | |
150 aCNFE); | |
151 } | |
152 | |
153 theManager = (TransactionManager) myManager; | |
154 isPrepared = true; | |
155 } | |
156 | |
157 return theManager; | |
158 } | |
159 | |
160 public long getId() { | |
161 return theId; | |
162 } | |
163 | |
164 public String toString() { | |
165 try { | |
166 return getManager() + "->" + theId; | |
167 } catch (RemoteException anRE) { | |
168 return "Broken_Codebase->" + theId; | |
169 } | |
170 } | |
171 | |
172 public boolean equals(Object anObject) { | |
173 if (anObject instanceof TxnId) { | |
174 TxnId myOther = (TxnId) anObject; | |
175 | |
176 if (myOther.theId != theId) | |
177 return false; | |
178 | |
179 try { | |
180 TransactionManager myMgr = getManager(); | |
181 TransactionManager myOtherMgr = myOther.getManager(); | |
182 | |
183 return myMgr.equals(myOtherMgr); | |
184 } catch (RemoteException anRE) { | |
185 // Likely to happen if codebase of txnmgr ref is broken | |
186 return false; | |
187 } | |
188 } | |
189 | |
190 return false; | |
191 } | |
192 | |
193 public int hashCode() { | |
194 return (int) (theId ^ (theId >>> 32)); | |
195 } | |
196 } | |
197 |