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