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