1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.myfaces.orchestra.conversation;
21
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24 import org.apache.myfaces.orchestra.lib.OrchestraException;
25 import org.apache.myfaces.orchestra.lib._ReentrantLock;
26
27 import java.util.Arrays;
28 import java.util.HashMap;
29 import java.util.Iterator;
30 import java.util.Map;
31 import java.util.TreeMap;
32
33
34
35
36
37
38
39
40
41
42
43 public class ConversationContext
44 {
45 private final Log log = LogFactory.getLog(ConversationContext.class);
46
47
48
49
50
51
52
53
54
55 private final Long id;
56
57
58 private final Map attributes = new TreeMap();
59
60
61 private final ConversationContext parent;
62
63
64 private final Map conversations = new TreeMap();
65
66
67
68
69 private String name;
70
71
72 private long lastAccess;
73
74
75 private long timeoutMillis = 30 * 60 * 1000;
76
77 private final _ReentrantLock lock = new _ReentrantLock();
78
79
80 private Map childContexts = new HashMap();
81
82
83
84
85 protected ConversationContext(long id)
86 {
87 this(null, id);
88 }
89
90
91
92
93
94
95 protected ConversationContext(ConversationContext parent, long id)
96 {
97 this.parent = parent;
98 this.id = Long.valueOf(id);
99
100 if (parent != null)
101 {
102 parent.addChild(this);
103 }
104
105 touch();
106 }
107
108
109
110
111
112
113 public String getName()
114 {
115 return name;
116 }
117
118
119
120
121
122
123 public void setName(String name)
124 {
125 this.name = name;
126 }
127
128
129
130
131 public long getId()
132 {
133 return id.longValue();
134 }
135
136
137
138
139 public Long getIdAsLong()
140 {
141 return id;
142 }
143
144
145
146
147
148
149 public ConversationContext getParent()
150 {
151 return parent;
152 }
153
154
155
156
157 public void addChild(ConversationContext context)
158 {
159 childContexts.put(context.getIdAsLong(), context);
160 }
161
162
163
164
165 public void removeChild(ConversationContext context)
166 {
167 Object o = childContexts.remove(context.getIdAsLong());
168 if (o != context)
169 {
170
171
172 throw new OrchestraException("Invalid call of removeChild");
173 }
174 }
175
176
177
178
179 public boolean hasChildren()
180 {
181 return !childContexts.isEmpty();
182 }
183
184
185
186
187 protected void touch()
188 {
189 lastAccess = System.currentTimeMillis();
190
191 if (getParent() != null)
192 {
193 getParent().touch();
194 }
195 }
196
197
198
199
200 public long getLastAccess()
201 {
202 return lastAccess;
203 }
204
205
206
207
208
209
210 public long getTimeout()
211 {
212 return timeoutMillis;
213 }
214
215
216
217
218
219
220 public void setTimeout(long timeoutMillis)
221 {
222 this.timeoutMillis = timeoutMillis;
223 }
224
225
226
227
228
229
230 protected void clear()
231 {
232 invalidate();
233 }
234
235
236
237
238
239
240 protected void invalidate()
241 {
242 synchronized (this)
243 {
244 Conversation[] convArray = new Conversation[conversations.size()];
245 conversations.values().toArray(convArray);
246
247 for (int i = 0; i < convArray.length; i++)
248 {
249 Conversation conversation = convArray[i];
250 conversation.invalidate();
251 }
252
253 conversations.clear();
254 }
255 }
256
257
258
259
260 protected Conversation startConversation(String name, ConversationFactory factory)
261 {
262 synchronized (this)
263 {
264 touch();
265 Conversation conversation = (Conversation) conversations.get(name);
266 if (conversation == null)
267 {
268 conversation = factory.createConversation(this, name);
269
270 conversations.put(name, conversation);
271 }
272 return conversation;
273 }
274 }
275
276
277
278
279
280
281 protected void removeConversation(Conversation conversation)
282 {
283 synchronized (this)
284 {
285 touch();
286 conversations.remove(conversation.getName());
287 }
288 }
289
290
291
292
293
294
295 protected void removeConversation(String name)
296 {
297 synchronized (this)
298 {
299 touch();
300 Conversation conversation = (Conversation) conversations.get(name);
301 if (conversation != null)
302 {
303 removeConversation(conversation);
304 }
305 }
306 }
307
308
309
310
311 protected boolean hasConversations()
312 {
313 synchronized (this)
314 {
315 touch();
316 return conversations.size() > 0;
317 }
318 }
319
320
321
322
323 protected boolean hasConversation(String name)
324 {
325 synchronized (this)
326 {
327 touch();
328 return conversations.get(name) != null;
329 }
330 }
331
332
333
334
335
336
337 protected Conversation getConversation(String name)
338 {
339 synchronized (this)
340 {
341 touch();
342
343 Conversation conv = (Conversation) conversations.get(name);
344 if (conv != null)
345 {
346 conv.touch();
347 }
348
349 return conv;
350 }
351 }
352
353
354
355
356
357
358
359
360
361 public Iterator iterateConversations()
362 {
363 synchronized (this)
364 {
365 touch();
366
367 Conversation[] convs = (Conversation[]) conversations.values().toArray(
368 new Conversation[conversations.size()]);
369 return Arrays.asList(convs).iterator();
370 }
371 }
372
373
374
375
376
377
378 protected void checkConversationTimeout()
379 {
380 synchronized (this)
381 {
382 Conversation[] convArray = new Conversation[conversations.size()];
383 conversations.values().toArray(convArray);
384
385 for (int i = 0; i < convArray.length; i++)
386 {
387 Conversation conversation = convArray[i];
388
389 ConversationTimeoutableAspect timeoutAspect =
390 (ConversationTimeoutableAspect)
391 conversation.getAspect(ConversationTimeoutableAspect.class);
392
393 if (timeoutAspect != null && timeoutAspect.isTimeoutReached())
394 {
395 if (log.isDebugEnabled())
396 {
397 log.debug("end conversation due to timeout: " + conversation.getName());
398 }
399
400 conversation.invalidate();
401 }
402 }
403 }
404 }
405
406
407
408
409
410
411
412 public void setAttribute(String name, Object attribute)
413 {
414 synchronized(attributes)
415 {
416 attributes.remove(name);
417 attributes.put(name, attribute);
418 }
419 }
420
421
422
423
424 public boolean hasAttribute(String name)
425 {
426 synchronized(attributes)
427 {
428 return attributes.containsKey(name);
429 }
430 }
431
432
433
434
435 public Object getAttribute(String name)
436 {
437 synchronized(attributes)
438 {
439 return attributes.get(name);
440 }
441 }
442
443
444
445
446 public Object removeAttribute(String name)
447 {
448 synchronized(attributes)
449 {
450 return attributes.remove(name);
451 }
452 }
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469 public void lockInterruptablyForCurrentThread() throws InterruptedException
470 {
471 if (log.isDebugEnabled())
472 {
473 log.debug("Locking context " + this.id);
474 }
475 lock.lockInterruptibly();
476 }
477
478
479
480
481
482
483
484
485
486
487 public void unlockForCurrentThread()
488 {
489 if (log.isDebugEnabled())
490 {
491 log.debug("Unlocking context " + this.id);
492 }
493 lock.unlock();
494 }
495
496
497
498
499
500
501 public boolean isLockedForCurrentThread()
502 {
503 return lock.isHeldByCurrentThread();
504 }
505
506
507
508
509
510
511
512
513
514
515 public ConversationContext getRoot()
516 {
517 ConversationContext cctx = this;
518 while (cctx != null && cctx.getParent() != null)
519 {
520 cctx = getParent();
521 }
522
523 return cctx;
524 }
525 }