1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 package org.melati.poem;
47
48 import java.util.Vector;
49 import java.util.Enumeration;
50 import java.util.Map;
51 import java.util.HashMap;
52 import org.melati.poem.transaction.ToTidyList;
53
54
55
56
57
58 public final class PoemThread {
59
60 private PoemThread() {
61 }
62
63 private static Vector<SessionToken> sessionTokens = new Vector<SessionToken>();
64
65 private static Vector<Integer> freeSessionTokenIndices = new Vector<Integer>();
66
67
68
69
70 public static final int threadsMax = 100;
71
72 static Integer allocatedSessionToken(AccessToken accessToken,
73 PoemTransaction transaction, PoemTask task) {
74 synchronized (freeSessionTokenIndices) {
75 Integer index;
76 if (freeSessionTokenIndices.size() == 0) {
77 int i = sessionTokens.size();
78 if (i >= threadsMax)
79 throw new TooManyThreadsPoemException();
80 sessionTokens.setSize(i + 1);
81 index = new Integer(i);
82 } else {
83 index = (Integer)freeSessionTokenIndices.lastElement();
84 freeSessionTokenIndices.setSize(freeSessionTokenIndices.size() - 1);
85 }
86
87 SessionToken token = new SessionToken(Thread.currentThread(),
88 transaction, accessToken, task);
89 sessionTokens.setElementAt(token, index.intValue());
90
91 return index;
92 }
93 }
94
95
96 private static Map<Integer, String> threadOldNames = new HashMap<Integer, String>();
97
98
99
100
101
102
103
104
105
106
107
108
109
110 static void beginSession(AccessToken accessToken,
111 PoemTransaction transaction, PoemTask task) throws PoemException {
112 if (inSession())
113 throw new AlreadyInSessionPoemException();
114 Integer token = allocatedSessionToken(accessToken, transaction, task);
115 String oldname = Thread.currentThread().getName();
116 Thread.currentThread().setName("" + (char)token.intValue());
117
118 threadOldNames.put(token, oldname);
119 }
120
121 static void beginSession(AccessToken accessToken, PoemTransaction transaction)
122 throws PoemException {
123 beginSession(accessToken, transaction, null);
124 }
125
126
127
128
129
130
131
132 static void endSession() throws PoemException {
133 char tokenChar = Thread.currentThread().getName().charAt(0);
134 Integer token = new Integer(tokenChar);
135 String oldname = (String)threadOldNames.get(token);
136 if (oldname == null)
137 throw new NotInSessionPoemException(Thread.currentThread().getName()
138 + " has null old name");
139
140 Thread.currentThread().setName(oldname);
141 synchronized (freeSessionTokenIndices) {
142 ((SessionToken)sessionTokens.elementAt(token.intValue())).close();
143 sessionTokens.setElementAt(null, token.intValue());
144 freeSessionTokenIndices.addElement(token);
145 }
146 }
147
148
149
150
151
152
153
154
155 static void inSession(PoemTask task, AccessToken accessToken,
156 PoemTransaction transaction) throws PoemException {
157 beginSession(accessToken, transaction, task);
158 try {
159 task.run();
160 } finally {
161 endSession();
162 }
163 }
164
165
166
167
168
169
170 public static Vector<SessionToken> openSessions() {
171 Vector<SessionToken> open = new Vector<SessionToken>();
172 Enumeration<SessionToken> e = null;
173
174 e = sessionTokens.elements();
175
176 while (e.hasMoreElements()) {
177 SessionToken token = e.nextElement();
178 if (token != null)
179 open.addElement(token);
180 }
181 return open;
182 }
183
184 static SessionToken _sessionToken() {
185
186
187 if (Thread.currentThread().getName().length() != 1)
188 return null;
189 SessionToken context = (SessionToken)sessionTokens.elementAt(Thread
190 .currentThread().getName().charAt(0));
191 if (context.thread == Thread.currentThread())
192 return context;
193 else
194 return null;
195 }
196
197
198
199
200
201 public static SessionToken sessionToken() throws NotInSessionPoemException {
202 SessionToken it = _sessionToken();
203 if (it == null)
204 throw new NotInSessionPoemException();
205 return it;
206 }
207
208
209
210
211
212
213 public static ToTidyList toTidy() throws NotInSessionPoemException {
214 return sessionToken().toTidy();
215 }
216
217
218
219
220
221
222 public static PoemTransaction transaction() {
223 return sessionToken().transaction;
224 }
225
226
227
228
229
230
231 public static boolean inSession() {
232 return _sessionToken() != null;
233 }
234
235
236
237
238
239
240
241
242 public static AccessToken accessToken() throws NotInSessionPoemException,
243 NoAccessTokenPoemException {
244 AccessToken it = sessionToken().accessToken;
245 if (it == null)
246 throw new NoAccessTokenPoemException();
247 return it;
248 }
249
250
251
252
253
254
255
256 public static void setAccessToken(AccessToken token)
257 throws NonRootSetAccessTokenPoemException {
258 SessionToken context = sessionToken();
259 AccessToken old = context.accessToken;
260 if (old != AccessToken.root)
261 throw new NonRootSetAccessTokenPoemException(old);
262 context.accessToken = token;
263 }
264
265
266
267
268
269
270
271
272
273
274 public static void withAccessToken(AccessToken token, PoemTask task) {
275 SessionToken context = sessionToken();
276 AccessToken old = context.accessToken;
277 context.accessToken = token;
278 try {
279 task.run();
280 } finally {
281 context.accessToken = old;
282 }
283 }
284
285
286
287
288
289
290
291
292 public static void assertHasCapability(Capability capability)
293 throws NotInSessionPoemException, NoAccessTokenPoemException,
294 AccessPoemException {
295 AccessToken token = accessToken();
296 if (!token.givesCapability(capability))
297 throw new AccessPoemException(token, capability);
298 }
299
300
301
302
303
304
305 public static Database database() throws NotInSessionPoemException {
306 return transaction().getDatabase();
307 }
308
309
310
311
312
313 public static void writeDown() {
314 transaction().writeDown();
315 }
316
317
318
319
320
321 public static void commit() {
322 SessionToken token = sessionToken();
323 try {
324 token.transaction.commit();
325 } finally {
326 token.toTidy().close();
327 }
328 }
329
330
331
332
333
334 public static void rollback() {
335 SessionToken token = sessionToken();
336 try {
337 token.transaction.rollback();
338 } finally {
339 token.toTidy().close();
340 }
341 }
342 }