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