View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.orchestra.conversation.servlet;
20  
21  import org.apache.myfaces.orchestra.conversation.ConversationManager;
22  import org.apache.myfaces.orchestra.conversation.ConversationWiperThread;
23  
24  import javax.servlet.ServletContextEvent;
25  import javax.servlet.ServletContextListener;
26  import javax.servlet.http.HttpSessionAttributeListener;
27  import javax.servlet.http.HttpSessionBindingEvent;
28  import javax.servlet.http.HttpSessionListener;
29  import javax.servlet.http.HttpSessionEvent;
30  
31  /***
32   * An http session listener which periodically scans every http session for
33   * conversations and conversation contexts that have exceeded their timeout.
34   * <p>
35   * If a web application wants to configure a conversation timeout that is
36   * shorter than the http session timeout, then this class must be specified
37   * as a listener in the web.xml file. 
38   * <p>
39   * A conversation timeout is useful because the session timeout is refreshed
40   * every time a request is made. If a user starts a conversation that uses
41   * lots of memory, then abandons it and starts working elsewhere in the same
42   * webapp then the session will continue to live, and therefore so will that
43   * old "unused" conversation. Specifying a conversation timeout allows the
44   * memory for that conversation to be reclaimed in this situation. 
45   * <p>
46   * This listener starts a single background thread that periodically wakes
47   * up and scans all http sessions to find ConversationContext objects, and
48   * checks their timeout together with the timeout for all Conversations in
49   * that context. If a conversation or context timeout has expired then it
50   * is removed.
51   * <p>
52   * This code is probably not safe for use with distributed sessions, ie
53   * a "clustered" web application setup.
54   * <p>
55   * See {@link org.apache.myfaces.orchestra.conversation.ConversationWiperThread}
56   * for more details.
57   */
58  public class ConversationManagerSessionListener
59  	implements HttpSessionAttributeListener, ServletContextListener, HttpSessionListener
60  {
61  	private final static long DEFAULT_CHECK_TIME = 5 * 60 * 1000; // every 5 min
62  
63  	private final static String CHECK_TIME = "org.apache.myfaces.orchestra.WIPER_THREAD_CHECK_TIME"; // NON-NLS
64  
65  	private ConversationWiperThread conversationWiperThread;
66  
67  	public void contextInitialized(ServletContextEvent event)
68  	{
69  		long checkTime = DEFAULT_CHECK_TIME;
70  		String checkTimeString = event.getServletContext().getInitParameter(CHECK_TIME);
71  		if (checkTimeString != null)
72  		{
73  			checkTime = Long.parseLong(checkTimeString);
74  		}
75  
76  		conversationWiperThread = new ConversationWiperThread(checkTime);
77  		conversationWiperThread.start();
78  	}
79  
80  	public void contextDestroyed(ServletContextEvent event)
81  	{
82  		conversationWiperThread.interrupt();
83  		conversationWiperThread = null;
84  	}
85  
86  	public void attributeAdded(HttpSessionBindingEvent event)
87  	{
88  		if (event.getValue() instanceof ConversationManager)
89  		{
90  			conversationWiperThread.addConversationManager(
91  				event.getSession().getId(),
92  				(ConversationManager) event.getValue());
93  		}
94  	}
95  
96  	public void attributeRemoved(HttpSessionBindingEvent event)
97  	{
98  		if (event.getValue() instanceof ConversationManager)
99  		{
100 			conversationWiperThread.removeConversationManager(event.getSession().getId());
101 		}
102 	}
103 
104 	public void attributeReplaced(HttpSessionBindingEvent event)
105 	{
106 		if (event.getValue() instanceof ConversationManager)
107 		{
108 			conversationWiperThread.addConversationManager(
109 				event.getSession().getId(),
110 				(ConversationManager) event.getValue());
111 		}
112 	}
113 
114 	public void sessionCreated(HttpSessionEvent event)
115 	{
116 	}
117 
118 	public void sessionDestroyed(HttpSessionEvent event)
119 	{
120 		// just in case we didn't get a attributeRemoved, remove any attached conversatoinManager for this session
121 		conversationWiperThread.removeConversationManager(event.getSession().getId());
122 	}
123 }