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 java.io.IOException;
23 import java.io.ObjectStreamException;
24 import java.io.Serializable;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.Iterator;
28 import java.util.Map;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.myfaces.orchestra.FactoryFinder;
33 import org.apache.myfaces.orchestra.frameworkAdapter.FrameworkAdapter;
34 import org.apache.myfaces.orchestra.lib.OrchestraException;
35 import org.apache.myfaces.orchestra.requestParameterProvider.RequestParameterProviderManager;
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 public class ConversationManager implements Serializable
56 {
57 private static final long serialVersionUID = 1L;
58
59 final static String CONVERSATION_CONTEXT_PARAM = "conversationContext";
60
61 private final static String CONVERSATION_MANAGER_KEY = "org.apache.myfaces.ConversationManager";
62 private final static String CONVERSATION_CONTEXT_REQ = "org.apache.myfaces.ConversationManager.conversationContext";
63
64 private static final Iterator EMPTY_ITERATOR = Collections.EMPTY_LIST.iterator();
65
66
67 private static final Object DUMMY = new Integer(-1);
68
69 private final Log log = LogFactory.getLog(ConversationManager.class);
70
71
72
73
74
75
76
77
78 private long nextConversationContextId = 1;
79
80
81
82 private final Map conversationContexts = new HashMap();
83
84 protected ConversationManager()
85 {
86 }
87
88
89
90
91
92
93
94
95
96
97 public static ConversationManager getInstance()
98 {
99 return getInstance(true);
100 }
101
102
103
104
105
106
107
108
109
110 public static ConversationManager getInstance(boolean create)
111 {
112 FrameworkAdapter frameworkAdapter = FrameworkAdapter.getCurrentInstance();
113 if (frameworkAdapter == null)
114 {
115 if (!create)
116 {
117
118
119 return null;
120 }
121 else
122 {
123 throw new IllegalStateException("FrameworkAdapter not found");
124 }
125 }
126
127 Object cmObj = frameworkAdapter.getSessionAttribute(CONVERSATION_MANAGER_KEY);
128
129 if (cmObj == DUMMY)
130 {
131 Log log = LogFactory.getLog(ConversationManager.class);
132 log.debug("Method getInstance found dummy ConversationManager object");
133 cmObj = null;
134 }
135
136
137 ConversationManager conversationManager = (ConversationManager) cmObj;
138
139 if (conversationManager == null && create)
140 {
141 Log log = LogFactory.getLog(ConversationManager.class);
142 log.debug("Register ConversationRequestParameterProvider");
143
144 conversationManager = FactoryFinder.getConversationManagerFactory().createConversationManager();
145
146
147 RequestParameterProviderManager.getInstance().register(new ConversationRequestParameterProvider());
148
149
150 FrameworkAdapter.getCurrentInstance().setSessionAttribute(CONVERSATION_MANAGER_KEY, conversationManager);
151 }
152
153 return conversationManager;
154 }
155
156
157
158
159
160
161 private Long findConversationContextId()
162 {
163 FrameworkAdapter fa = FrameworkAdapter.getCurrentInstance();
164
165
166 Long conversationContextId = (Long)fa.getRequestAttribute(CONVERSATION_CONTEXT_REQ);
167 if (conversationContextId == null)
168 {
169 if (fa.containsRequestParameterAttribute(CONVERSATION_CONTEXT_PARAM))
170 {
171 String urlConversationContextId = fa.getRequestParameterAttribute(
172 CONVERSATION_CONTEXT_PARAM).toString();
173 conversationContextId = new Long(
174 Long.parseLong(urlConversationContextId, Character.MAX_RADIX));
175 }
176 }
177 return conversationContextId;
178 }
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197 private Long getOrCreateConversationContextId()
198 {
199 Long conversationContextId = findConversationContextId();
200 if (conversationContextId == null)
201 {
202 conversationContextId = createNextConversationContextId();
203 FrameworkAdapter fa = FrameworkAdapter.getCurrentInstance();
204 fa.setRequestAttribute(CONVERSATION_CONTEXT_REQ, conversationContextId);
205 }
206
207 return conversationContextId;
208 }
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229 public Long getConversationContextId()
230 {
231 return getOrCreateConversationContextId();
232 }
233
234
235
236
237
238
239
240
241 private Long createNextConversationContextId()
242 {
243 Long conversationContextId;
244 synchronized(this)
245 {
246 conversationContextId = new Long(nextConversationContextId);
247 nextConversationContextId++;
248 }
249 return conversationContextId;
250 }
251
252
253
254
255
256
257
258
259
260
261 public ConversationContext getConversationContext(Long conversationContextId)
262 {
263 synchronized (this)
264 {
265 return (ConversationContext) conversationContexts.get(conversationContextId);
266 }
267 }
268
269
270
271
272
273
274
275
276
277
278 protected ConversationContext getOrCreateConversationContext(Long conversationContextId)
279 {
280 synchronized (this)
281 {
282 ConversationContext conversationContext = (ConversationContext) conversationContexts.get(
283 conversationContextId);
284 if (conversationContext == null)
285 {
286 ConversationContextFactory factory = FactoryFinder.getConversationContextFactory();
287 conversationContext = factory.createConversationContext(null, conversationContextId.longValue());
288 conversationContexts.put(conversationContextId, conversationContext);
289
290
291
292 log.debug("Created context " + conversationContextId);
293 }
294 return conversationContext;
295 }
296 }
297
298
299
300
301
302
303
304
305
306 public ConversationContext createConversationContext(ConversationContext parent)
307 {
308 Long ctxId = createNextConversationContextId();
309 ConversationContextFactory factory = FactoryFinder.getConversationContextFactory();
310 ConversationContext ctx = factory.createConversationContext(parent, ctxId.longValue());
311
312 synchronized(this)
313 {
314 conversationContexts.put(ctxId, ctx);
315 }
316
317 return ctx;
318 }
319
320
321
322
323
324
325
326
327
328 public void activateConversationContext(ConversationContext ctx)
329 {
330 FrameworkAdapter fa = FrameworkAdapter.getCurrentInstance();
331 fa.setRequestAttribute(CONVERSATION_CONTEXT_REQ, ctx.getIdAsLong());
332 }
333
334
335
336
337 public void clearCurrentConversationContext()
338 {
339 Long conversationContextId = findConversationContextId();
340 if (conversationContextId != null)
341 {
342 ConversationContext conversationContext = getConversationContext(conversationContextId);
343 if (conversationContext != null)
344 {
345 conversationContext.invalidate();
346 }
347 }
348 }
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364 public void removeAndInvalidateConversationContext(ConversationContext context)
365 {
366 if (context.hasChildren())
367 {
368 throw new OrchestraException("Cannot remove context with children");
369 }
370
371 if (context.getIdAsLong().equals(findConversationContextId()))
372 {
373 throw new OrchestraException("Cannot remove current context");
374 }
375
376 synchronized(conversationContexts)
377 {
378 conversationContexts.remove(context.getIdAsLong());
379 }
380
381 ConversationContext parent = context.getParent();
382 if (parent != null)
383 {
384 parent.removeChild(context);
385 }
386
387 context.invalidate();
388
389
390
391
392
393
394
395
396
397
398
399 }
400
401
402
403
404
405
406
407
408
409 protected void removeConversationContext(Long conversationContextId)
410 {
411 synchronized (this)
412 {
413 conversationContexts.remove(conversationContextId);
414 }
415 }
416
417
418
419
420
421
422 public Conversation startConversation(String name, ConversationFactory factory)
423 {
424 ConversationContext conversationContext = getOrCreateCurrentConversationContext();
425 return conversationContext.startConversation(name, factory);
426 }
427
428
429
430
431
432
433
434
435 protected void removeConversation(String name)
436 {
437 Long conversationContextId = findConversationContextId();
438 if (conversationContextId != null)
439 {
440 ConversationContext conversationContext = getConversationContext(conversationContextId);
441 if (conversationContext != null)
442 {
443 conversationContext.removeConversation(name);
444 }
445 }
446 }
447
448
449
450
451
452
453 public Conversation getConversation(String name)
454 {
455 ConversationContext conversationContext = getCurrentConversationContext();
456 if (conversationContext == null)
457 {
458 return null;
459 }
460 return conversationContext.getConversation(name);
461 }
462
463
464
465
466 public boolean hasConversation(String name)
467 {
468 ConversationContext conversationContext = getCurrentConversationContext();
469 if (conversationContext == null)
470 {
471 return false;
472 }
473 return conversationContext.hasConversation(name);
474 }
475
476
477
478
479
480 public Iterator iterateConversations()
481 {
482 ConversationContext conversationContext = getCurrentConversationContext();
483 if (conversationContext == null)
484 {
485 return EMPTY_ITERATOR;
486 }
487
488 return conversationContext.iterateConversations();
489 }
490
491
492
493
494
495
496
497
498
499
500 public ConversationContext getCurrentConversationContext()
501 {
502 Long ccid = findConversationContextId();
503 if (ccid == null)
504 {
505 return null;
506 }
507 else
508 {
509 ConversationContext ctx = getConversationContext(ccid);
510 if (ctx == null)
511 {
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531 log.warn("ConversationContextId specified but context does not exist");
532 synchronized(this)
533 {
534 if (nextConversationContextId <= ccid.longValue())
535 {
536 nextConversationContextId = ccid.longValue() + 1;
537 }
538 }
539 return null;
540 }
541 return ctx;
542 }
543 }
544
545
546
547
548
549
550
551
552
553
554
555
556 ConversationContext getOrCreateCurrentConversationContext()
557 {
558 Long ccid = getOrCreateConversationContextId();
559 return getOrCreateConversationContext(ccid);
560 }
561
562
563
564
565
566 public boolean hasConversationContext()
567 {
568 return getCurrentConversationContext() == null;
569 }
570
571
572
573
574
575
576
577
578 public ConversationContext getCurrentRootConversationContext()
579 {
580 Long ccid = findConversationContextId();
581 if (ccid == null)
582 {
583 return null;
584 }
585
586 synchronized (this)
587 {
588 ConversationContext conversationContext = getConversationContext(ccid);
589 if (conversationContext == null)
590 {
591 return null;
592 }
593 else
594 {
595 return conversationContext.getRoot();
596 }
597 }
598 }
599
600
601
602
603
604
605
606 public ConversationMessager getMessager()
607 {
608 return FrameworkAdapter.getCurrentInstance().getConversationMessager();
609 }
610
611
612
613
614
615
616
617
618
619
620
621 protected void checkTimeouts()
622 {
623 Map.Entry[] contexts;
624 synchronized (this)
625 {
626 contexts = new Map.Entry[conversationContexts.size()];
627 conversationContexts.entrySet().toArray(contexts);
628 }
629
630 long checkTime = System.currentTimeMillis();
631
632 for (int i = 0; i<contexts.length; i++)
633 {
634 Map.Entry context = contexts[i];
635
636 ConversationContext conversationContext = (ConversationContext) context.getValue();
637 if (conversationContext.hasChildren())
638 {
639
640 continue;
641 }
642
643 conversationContext.checkConversationTimeout();
644
645 if (conversationContext.getTimeout() > -1 &&
646 (conversationContext.getLastAccess() +
647 conversationContext.getTimeout()) < checkTime)
648 {
649 if (log.isDebugEnabled())
650 {
651 log.debug("end conversation context due to timeout: " + conversationContext.getId());
652 }
653
654 removeAndInvalidateConversationContext(conversationContext);
655 }
656 }
657 }
658
659
660
661
662 public void removeAndInvalidateAllConversationContexts()
663 {
664 ConversationContext[] contexts;
665 synchronized (this)
666 {
667 contexts = new ConversationContext[conversationContexts.size()];
668 conversationContexts.values().toArray(contexts);
669 }
670
671 for (int i = 0; i<contexts.length; i++)
672 {
673 ConversationContext context = contexts[i];
674 removeAndInvalidateConversationContextAndChildren(context);
675 }
676 }
677
678 private void removeAndInvalidateConversationContextAndChildren(ConversationContext conversationContext)
679 {
680 while (conversationContext.hasChildren())
681 {
682
683 ConversationContext child = (ConversationContext) conversationContext.getChildren().iterator().next();
684
685
686 removeAndInvalidateConversationContextAndChildren(child);
687 }
688
689 if (log.isDebugEnabled())
690 {
691 log.debug("end conversation context: " + conversationContext.getId());
692 }
693
694 removeAndInvalidateConversationContext(conversationContext);
695 }
696
697 private void writeObject(java.io.ObjectOutputStream out) throws IOException
698 {
699
700
701 }
702
703 private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException
704 {
705
706 }
707
708 private Object readResolve() throws ObjectStreamException
709 {
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738 Log log = LogFactory.getLog(ConversationManager.class);
739 log.debug("readResolve returning dummy ConversationManager object");
740 return DUMMY;
741 }
742 }