1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.jetspeed.container.session;
18
19 import java.util.Arrays;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.HashMap;
23 import java.util.Iterator;
24 import java.util.Map;
25
26 import javax.servlet.http.HttpSession;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30
31 /***
32 * PortalSessionsManagerImpl
33 *
34 * @author <a href="mailto:ate@douma.nu">Ate Douma</a>
35 * @version $Id: $
36 */
37 public class PortalSessionsManagerImpl implements PortalSessionsManager
38 {
39
40 private static Log log = LogFactory.getLog(PortalSessionsManagerImpl.class);
41
42 private static final class PortalSessionRegistry
43 {
44 long portalSessionKey;
45 PortalSessionMonitor psm;
46 Map sessionMonitors;
47
48 PortalSessionRegistry()
49 {
50 sessionMonitors = Collections.synchronizedMap(new HashMap());
51 }
52 }
53
54 private long portalSessionKeySequence;
55 private Map portalSessionsRegistry;
56 private boolean forceInvalidate;
57
58 public PortalSessionsManagerImpl()
59 {
60 this(true);
61 }
62
63 public PortalSessionsManagerImpl(boolean forceInvalidate)
64 {
65 portalSessionKeySequence = System.currentTimeMillis();
66 portalSessionsRegistry = Collections.synchronizedMap(new HashMap());
67 this.forceInvalidate = forceInvalidate;
68 }
69
70 /* (non-Javadoc)
71 * @see org.apache.jetspeed.container.session.PortalSessionsManager#portalSessionCreated(javax.servlet.http.HttpSession)
72 */
73 public void portalSessionCreated(HttpSession portalSession)
74 {
75 PortalSessionMonitor psm = null;
76
77 synchronized (this)
78 {
79 psm = new PortalSessionMonitorImpl(++portalSessionKeySequence, forceInvalidate);
80 }
81
82 portalSession.setAttribute(PortalSessionMonitor.SESSION_KEY, psm);
83 // register it as if activated
84 portalSessionDidActivate(psm);
85 }
86
87 /* (non-Javadoc)
88 * @see org.apache.jetspeed.container.session.PortalSessionsManager#portalSessionWillPassivate(org.apache.jetspeed.container.session.PortalSessionMonitor)
89 */
90 public void portalSessionWillPassivate(PortalSessionMonitor psm)
91 {
92 portalSessionsRegistry.remove(psm.getSessionId());
93 }
94
95 /* (non-Javadoc)
96 * @see org.apache.jetspeed.container.session.PortalSessionsManager#portalSessionDidActivate(org.apache.jetspeed.container.session.PortalSessionMonitor)
97 */
98 public void portalSessionDidActivate(PortalSessionMonitor restoredPsm)
99 {
100 PortalSessionRegistry psr = (PortalSessionRegistry)portalSessionsRegistry.get(restoredPsm.getSessionId());
101 if ( psr != null && psr.portalSessionKey != -1 && psr.portalSessionKey != restoredPsm.getSessionKey() )
102 {
103 // looks like Client didn't join the previous portal session while the sessionId is reused (cookies disabled?)
104 // destroy the "old" portal Session and any (probably also not-joined) registered paSessions
105 portalSessionDestroyed(psr.psm);
106 psr = null;
107 }
108 if ( psr == null )
109 {
110 psr = new PortalSessionRegistry();
111 portalSessionsRegistry.put(restoredPsm.getSessionId(), psr);
112 }
113 // save the restored instance
114 psr.psm = restoredPsm;
115 psr.portalSessionKey = restoredPsm.getSessionKey();
116 // validate registered paSessions are in sync
117 // we iterate with shallow copy of paSessions to avoid conflicts with concurrent updates of paSessions
118 Iterator iter = valuesShallowCopy(psr.sessionMonitors.values()).iterator();
119 PortletApplicationSessionMonitor pasm;
120 while (iter.hasNext())
121 {
122 pasm = (PortletApplicationSessionMonitor)iter.next();
123 if ( pasm.getPortalSessionKey() != psr.portalSessionKey )
124 {
125 pasm.invalidateSession();
126 // remove from original map !
127 psr.sessionMonitors.remove(pasm.getContextPath());
128 }
129 }
130 }
131
132 /* (non-Javadoc)
133 * @see org.apache.jetspeed.container.session.PortalSessionsManager#portalSessionDestroyed(org.apache.jetspeed.container.session.PortalSessionMonitor)
134 */
135 public void portalSessionDestroyed(PortalSessionMonitor psm)
136 {
137 PortalSessionRegistry psr = (PortalSessionRegistry)portalSessionsRegistry.remove(psm.getSessionId());
138 if ( psr != null )
139 {
140 // we iterate with shallow copy of paSessions to avoid conflicts with concurrent updates of paSessions
141 Iterator iter = valuesShallowCopy(psr.sessionMonitors.values()).iterator();
142 while (iter.hasNext())
143 {
144 ((PortletApplicationSessionMonitor) iter.next()).invalidateSession();
145 }
146
147 try
148 {
149 // To make sure its gone.
150 // You better not remove the psm from the portal session yourself ;)
151 psm.invalidateSession();
152 }
153 catch (IllegalStateException ise)
154 {
155 // pSession already invalid, ignore
156 }
157 }
158 }
159
160 /* (non-Javadoc)
161 * @see org.apache.jetspeed.container.session.PortalSessionsManager#checkMonitorSession(java.lang.String, javax.servlet.http.HttpSession, javax.servlet.http.HttpSession)
162 */
163 public void checkMonitorSession(String contextPath, HttpSession portalSession, HttpSession paSession)
164 {
165 if ( portalSession != null && paSession != null )
166 {
167 if (portalSession == paSession)
168 {
169 // On WebSphere 6.1.0.11, strange symptoms like this occur...
170 log.warn("servlet context name of paSession(" + paSession.getId() + "): " + paSession.getServletContext().getServletContextName());
171 return;
172 }
173
174 PortalSessionRegistry psr = (PortalSessionRegistry)portalSessionsRegistry.get(portalSession.getId());
175 if (psr == null)
176 {
177 // yet unexplained condition: the HttpSessionListener on the portal application *should* have registered the session!!!
178 // Alas, it has been reported to happen...
179 // Now trying to do some recovering here
180 PortalSessionMonitor psm = (PortalSessionMonitor)portalSession.getAttribute(PortalSessionMonitor.SESSION_KEY);
181 // the psm better be null here, otherwise something really is corrupt or not playing by the listeners contracts
182 if ( psm == null )
183 {
184 portalSessionCreated(portalSession);
185 }
186 else
187 {
188 // Now we have discovered a really strange situation here
189 // Only explanation I can see is that a passivation of the portalSession occurred,
190 // but that the activation again didn't trigger the sessionDidActivate event handler???
191 // Lets just try to accomodate this situation for now:
192 portalSessionDidActivate(psm);
193 }
194 // now retrieve the just created psr again
195 psr = (PortalSessionRegistry)portalSessionsRegistry.get(portalSession.getId());
196 }
197 PortletApplicationSessionMonitor pasm = (PortletApplicationSessionMonitor)psr.sessionMonitors.get(contextPath);
198 if ( pasm != null )
199 {
200 try
201 {
202 if ( paSession.getAttribute(PortletApplicationSessionMonitor.SESSION_KEY) == null )
203 {
204 // looks like Client didn't join the previous pa session
205 // destroy the "old" paSession
206 pasm.invalidateSession();
207 pasm = null;
208 // no need to remove the "old" pasm from the sessionMonitors as it will be replaced right below
209 }
210 }
211 catch (IllegalStateException ise)
212 {
213 // paSession already invalid, ignore
214 }
215 }
216 if ( pasm == null )
217 {
218 pasm = new PortletApplicationSessionMonitorImpl(contextPath,portalSession.getId(),psr.portalSessionKey, forceInvalidate);
219 try
220 {
221 paSession.setAttribute(PortletApplicationSessionMonitor.SESSION_KEY, pasm);
222 psr.sessionMonitors.put(contextPath, pasm);
223 }
224 catch (IllegalStateException ise)
225 {
226 // paSession already invalid, ignore
227 }
228 }
229 }
230 }
231
232 /* (non-Javadoc)
233 * @see org.apache.jetspeed.container.session.PortalSessionsManager#sessionWillPassivate(org.apache.jetspeed.container.session.PortletApplicationSessionMonitor)
234 */
235 public void sessionWillPassivate(PortletApplicationSessionMonitor pasm)
236 {
237 PortalSessionRegistry psr = (PortalSessionRegistry)portalSessionsRegistry.get(pasm.getPortalSessionId());
238 if (psr != null )
239 {
240 psr.sessionMonitors.remove(pasm.getContextPath());
241 }
242 }
243
244 /* (non-Javadoc)
245 * @see org.apache.jetspeed.container.session.PortalSessionsManager#sessionDidActivate(org.apache.jetspeed.container.session.PortletApplicationSessionMonitor)
246 */
247 public void sessionDidActivate(PortletApplicationSessionMonitor restoredPasm)
248 {
249 PortalSessionRegistry psr = (PortalSessionRegistry)portalSessionsRegistry.get(restoredPasm.getPortalSessionId());
250 if ( psr == null )
251 {
252 // looks like the portalSession was passivated or the paSession was replicated to another JVM while its related portalSession wasn't (yet)
253 // so, we're gonna anticipate future activation of the portalSession:
254 // create a temporary psr with an "empty" psm for now (portalSessionKey == -1)
255 // once the portalSession is replicated/Activated, it will validate registered paSessions having the correct portalSessionKey
256 psr = new PortalSessionRegistry();
257 psr.psm = new PortalSessionMonitorImpl(-1);
258 portalSessionsRegistry.put(restoredPasm.getPortalSessionId(), psr);
259 }
260
261 // save the restored instance
262 restoredPasm.getSession().setAttribute(PortletApplicationSessionMonitor.SESSION_KEY, restoredPasm);
263 psr.sessionMonitors.put(restoredPasm.getContextPath(), restoredPasm);
264 }
265
266 /* (non-Javadoc)
267 * @see org.apache.jetspeed.container.session.PortalSessionsManager#sessionDestroyed(org.apache.jetspeed.container.session.PortletApplicationSessionMonitor)
268 */
269 public void sessionDestroyed(PortletApplicationSessionMonitor pasm)
270 {
271 PortalSessionRegistry psr = (PortalSessionRegistry)portalSessionsRegistry.get(pasm.getPortalSessionId());
272 if ( psr != null )
273 {
274 psr.sessionMonitors.remove(pasm.getContextPath());
275
276 try
277 {
278 // To make sure its gone.
279 // You better not remove the pasm from the session yourself ;)
280 pasm.invalidateSession();
281 }
282 catch (IllegalStateException ise)
283 {
284 // paSession already invalid, ignore
285 }
286 }
287 }
288
289 /* (non-Javadoc)
290 * @see org.apache.jetspeed.container.session.PortalSessionsManager#sessionCount()
291 */
292 public int sessionCount() {
293
294 return portalSessionsRegistry.size();
295 }
296
297 /***
298 * Returns a shallow copy of the given Collection.
299 * @param inValues
300 * @return shallow copy
301 */
302 private Collection valuesShallowCopy(Collection inValues) {
303 return Arrays.asList(inValues.toArray());
304 }
305 }