1 |
| package org.jboss.cache.transaction; |
2 |
| |
3 |
| import org.apache.commons.logging.Log; |
4 |
| import org.apache.commons.logging.LogFactory; |
5 |
| |
6 |
| import javax.naming.Context; |
7 |
| import javax.naming.InitialContext; |
8 |
| import javax.naming.NamingException; |
9 |
| import javax.transaction.HeuristicMixedException; |
10 |
| import javax.transaction.HeuristicRollbackException; |
11 |
| import javax.transaction.InvalidTransactionException; |
12 |
| import javax.transaction.NotSupportedException; |
13 |
| import javax.transaction.RollbackException; |
14 |
| import javax.transaction.SystemException; |
15 |
| import javax.transaction.Transaction; |
16 |
| import java.util.HashMap; |
17 |
| import java.util.Iterator; |
18 |
| import java.util.Map; |
19 |
| import java.util.Properties; |
20 |
| |
21 |
| public class AsyncRollbackTransactionManager extends DummyTransactionManager |
22 |
| { |
23 |
| static AsyncRollbackTransactionManager instance = null; |
24 |
| private static Log log = LogFactory.getLog(AsyncRollbackTransactionManager.class); |
25 |
| |
26 |
8
| public static DummyTransactionManager getInstance()
|
27 |
| { |
28 |
8
| if (instance == null)
|
29 |
| { |
30 |
1
| instance = new AsyncRollbackTransactionManager();
|
31 |
1
| try
|
32 |
| { |
33 |
1
| Properties p = new Properties();
|
34 |
1
| p.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.cache.transaction.DummyContextFactory");
|
35 |
1
| Context ctx = new InitialContext(p);
|
36 |
1
| ctx.bind("java:/TransactionManager", instance);
|
37 |
1
| ctx.bind("UserTransaction", new DummyUserTransaction(instance));
|
38 |
| } |
39 |
| catch (NamingException e) |
40 |
| { |
41 |
0
| log.error("binding of DummyTransactionManager failed", e);
|
42 |
| } |
43 |
| } |
44 |
8
| return instance;
|
45 |
| } |
46 |
| |
47 |
| private Thread timedOutTransactionsChecker = null; |
48 |
| private int timeout = 30; |
49 |
| private Map txMap = new HashMap(); |
50 |
| |
51 |
8
| public void setTransactionTimeout(int seconds) throws SystemException
|
52 |
| { |
53 |
8
| this.timeout = seconds;
|
54 |
| } |
55 |
| |
56 |
1
| public AsyncRollbackTransactionManager()
|
57 |
| { |
58 |
1
| timedOutTransactionsChecker = new TimedOutTransactionsChecker();
|
59 |
1
| timedOutTransactionsChecker.start();
|
60 |
| } |
61 |
| |
62 |
| private class TimedOutTransactionsChecker extends Thread |
63 |
| { |
64 |
| private boolean running; |
65 |
| |
66 |
1
| public TimedOutTransactionsChecker()
|
67 |
| { |
68 |
| } |
69 |
| |
70 |
1
| public void run()
|
71 |
| { |
72 |
1
| running = true;
|
73 |
46
| while (running)
|
74 |
| { |
75 |
46
| try
|
76 |
| { |
77 |
46
| Thread.sleep(500);
|
78 |
45
| synchronized (this)
|
79 |
| { |
80 |
45
| Iterator iterator = txMap.values().iterator();
|
81 |
45
| do
|
82 |
| { |
83 |
89
| if (!iterator.hasNext())
|
84 |
| { |
85 |
45
| break;
|
86 |
| } |
87 |
44
| AsyncRollbackTransaction t = (AsyncRollbackTransaction) iterator.next();
|
88 |
44
| try
|
89 |
| { |
90 |
44
| t.wakeUp();
|
91 |
| } |
92 |
| catch (SystemException e) |
93 |
| { |
94 |
0
| e.printStackTrace();
|
95 |
| } |
96 |
| |
97 |
| } |
98 |
| while (true); |
99 |
| } |
100 |
| } |
101 |
| catch (InterruptedException e) |
102 |
| { |
103 |
| } |
104 |
| } |
105 |
| } |
106 |
| |
107 |
| } |
108 |
| |
109 |
9
| public void begin() throws NotSupportedException, SystemException
|
110 |
| { |
111 |
9
| Transaction currentTx;
|
112 |
?
| if ((currentTx = getTransaction()) != null)
|
113 |
| { |
114 |
0
| throw new NotSupportedException(Thread.currentThread() +
|
115 |
| " is already associated with a transaction (" + currentTx + ")"); |
116 |
| } |
117 |
9
| AsyncRollbackTransaction tx = new AsyncRollbackTransaction(this, timeout);
|
118 |
9
| setTransaction(tx);
|
119 |
9
| txMap.put(tx.generateTransactionId(), tx);
|
120 |
| } |
121 |
| |
122 |
| |
123 |
6
| public void rollback() throws IllegalStateException, SecurityException, SystemException
|
124 |
| { |
125 |
6
| removeTxFromMap((AsyncRollbackTransaction) getTransaction());
|
126 |
6
| super.rollback();
|
127 |
| } |
128 |
| |
129 |
15
| public void removeTxFromMap(AsyncRollbackTransaction tx) throws SystemException
|
130 |
| { |
131 |
15
| if (tx != null)
|
132 |
| { |
133 |
15
| txMap.remove(tx.getTransactionId());
|
134 |
| } |
135 |
| } |
136 |
| |
137 |
| |
138 |
3
| public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException, IllegalStateException, SystemException
|
139 |
| { |
140 |
3
| AsyncRollbackTransaction tx = (AsyncRollbackTransaction) getTransaction();
|
141 |
3
| if (tx != null)
|
142 |
| { |
143 |
3
| txMap.remove(tx.getTransactionId());
|
144 |
| } |
145 |
3
| super.commit();
|
146 |
| } |
147 |
| |
148 |
| |
149 |
0
| public void resume(Transaction tx) throws InvalidTransactionException, IllegalStateException, SystemException
|
150 |
| { |
151 |
| |
152 |
0
| super.resume(tx);
|
153 |
| } |
154 |
| |
155 |
| |
156 |
0
| public Transaction suspend() throws SystemException
|
157 |
| { |
158 |
| |
159 |
0
| return super.suspend();
|
160 |
| } |
161 |
| |
162 |
| static class AsyncRollbackTransaction extends DummyTransaction |
163 |
| { |
164 |
| private static long transactionNums = 0; |
165 |
| |
166 |
| private long transactionId; |
167 |
| |
168 |
| private long beginTimeMillis; |
169 |
| |
170 |
| private int timeoutSec; |
171 |
| |
172 |
9
| public AsyncRollbackTransaction(DummyBaseTransactionManager tm, int timeout)
|
173 |
| { |
174 |
9
| super(tm);
|
175 |
9
| this.timeoutSec = timeout;
|
176 |
9
| this.beginTimeMillis = System.currentTimeMillis();
|
177 |
| } |
178 |
| |
179 |
| |
180 |
| |
181 |
| |
182 |
18
| public long getTransactionId()
|
183 |
| { |
184 |
18
| return transactionId;
|
185 |
| } |
186 |
| |
187 |
9
| public long generateTransactionId()
|
188 |
| { |
189 |
9
| long result = 0;
|
190 |
9
| synchronized (AsyncRollbackTransaction.class)
|
191 |
| { |
192 |
9
| transactionNums++;
|
193 |
9
| result = transactionNums;
|
194 |
| } |
195 |
9
| this.transactionId = result;
|
196 |
9
| return result;
|
197 |
| } |
198 |
| |
199 |
0
| final int getTimeoutSeconds()
|
200 |
| { |
201 |
0
| return timeoutSec;
|
202 |
| } |
203 |
| |
204 |
9
| protected final void asyncRollback() throws SystemException
|
205 |
| { |
206 |
9
| Thread asyncRollbackThread = new Thread()
|
207 |
| { |
208 |
9
| public void run()
|
209 |
| { |
210 |
9
| try
|
211 |
| { |
212 |
9
| rollback();
|
213 |
| } |
214 |
| catch (Exception exception) |
215 |
| { |
216 |
| } |
217 |
| } |
218 |
| }; |
219 |
9
| ((AsyncRollbackTransactionManager) tm_).removeTxFromMap(this);
|
220 |
9
| asyncRollbackThread.start();
|
221 |
| } |
222 |
| |
223 |
44
| public void wakeUp() throws SystemException
|
224 |
| { |
225 |
44
| if (isTransactionTimedOut())
|
226 |
| { |
227 |
9
| asyncRollback();
|
228 |
| } |
229 |
| } |
230 |
| |
231 |
44
| private boolean isTransactionTimedOut()
|
232 |
| { |
233 |
44
| return (System.currentTimeMillis() - beginTimeMillis) > (timeoutSec * 1000);
|
234 |
| } |
235 |
| } |
236 |
| |
237 |
| |
238 |
| } |