View Javadoc

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 }