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.state.impl;
18  
19  import java.io.Serializable;
20  import java.util.HashMap;
21  import java.util.Iterator;
22  import java.util.Map;
23  
24  import javax.portlet.PortletMode;
25  import javax.portlet.WindowState;
26  
27  import org.apache.jetspeed.Jetspeed;
28  import org.apache.jetspeed.cache.ContentCacheKey;
29  import org.apache.jetspeed.cache.JetspeedContentCache;
30  import org.apache.jetspeed.container.window.PortletWindowAccessor;
31  import org.apache.jetspeed.om.page.Page;
32  import org.apache.jetspeed.request.RequestContext;
33  import org.apache.pluto.om.window.PortletWindow;
34  
35  public class PortletWindowSessionNavigationalStates implements Serializable
36  {
37      private static final class PageState implements Serializable
38      {
39          public Map windowStates = new HashMap();
40          public String maximizedWindowId;
41      }
42      
43      private final boolean storeParameters;
44      private Map pageStates = new HashMap();
45  
46      public PortletWindowSessionNavigationalStates(boolean storeParameters)
47      {
48          this.storeParameters = storeParameters;
49      }
50      /*
51       * JS2-806 patch
52       * <p>
53       *   reset all portlets on page to mode VIEW and window state NORMAL in the case of page navigation.
54       * </p>
55       */
56      public void changeAllPortletsToViewModeAndNormalWindowState(RequestContext context, Page page, PortletWindowRequestNavigationalStates requestStates, JetspeedContentCache cache, JetspeedContentCache decorationCache)
57      {
58          final PortletMode viewMode = PortletMode.VIEW;
59          final WindowState normalWindowState = WindowState.NORMAL;
60          
61          PageState pageState = (PageState)pageStates.get(page.getId());
62          if ( pageState == null )
63          {
64              pageState = new PageState();
65              pageStates.put(page.getId(), pageState);
66          }
67          
68          PortletWindowRequestNavigationalState requestState = null;
69          PortletWindowBaseNavigationalState sessionState = null;
70  
71          //remove any maximized windows
72          if (null != pageState.maximizedWindowId)
73          {
74              pageState.windowStates.remove(pageState.maximizedWindowId);
75              removeFromCache(context, pageState.maximizedWindowId, cache);
76              removeFromCache(context, pageState.maximizedWindowId, decorationCache);            
77              pageState.maximizedWindowId = null;
78          }
79  
80          Iterator iter = requestStates.getWindowIdIterator();
81          iter = pageState.windowStates.keySet().iterator();
82          String windowId;
83          while ( iter.hasNext() )
84          {
85              windowId = (String)iter.next();
86              requestState = requestStates.getPortletWindowNavigationalState(windowId);
87              if ( requestState == null )
88              {
89                  requestState = new PortletWindowRequestNavigationalState(windowId);
90              }
91              //regardless, reset portlet mode and window state
92              requestState.setPortletMode(viewMode);
93              requestState.setWindowState(normalWindowState);
94              // get the session case just in case and create a new one
95              sessionState = (PortletWindowBaseNavigationalState)pageState.windowStates.get(requestState.getWindowId());
96              if ( sessionState == null )
97              {
98                  if ( storeParameters )
99                  {
100                     sessionState = new PortletWindowExtendedNavigationalState();
101                 }
102                 else
103                 {
104                     sessionState = new PortletWindowBaseNavigationalState();
105                 }
106                 pageState.windowStates.put(requestState.getWindowId(),sessionState);
107             }
108             //Now, sync up. NOTE we should not be in this method if there is an portlet action request.
109             boolean changed = syncStates(false, requestState,(PortletWindowBaseNavigationalState)pageState.windowStates.get(windowId));
110             if (changed)
111             {
112                 removeFromCache(context, requestState.getWindowId(), cache);
113                 removeFromCache(context, page.getId(), decorationCache);                    
114                 if (storeParameters)
115                 {
116                     ((PortletWindowExtendedNavigationalState)sessionState).resetDecoratorActionEncodings();
117                 }
118             }
119             
120         }        
121     }
122     
123     public void sync(RequestContext context, Page page, PortletWindowRequestNavigationalStates requestStates, JetspeedContentCache cache, JetspeedContentCache decorationCache)    
124     {
125         PageState pageState = (PageState)pageStates.get(page.getId());
126         if ( pageState == null )
127         {
128             pageState = new PageState();
129             pageStates.put(page.getId(), pageState);
130         }
131         
132         PortletWindowRequestNavigationalState requestState = null;
133         PortletWindowBaseNavigationalState sessionState = null;
134 
135         // first synchronize MAXIMIZED window
136         if ( pageState.maximizedWindowId != null )
137         {
138             String requestMaximizedWindowId = null;
139             
140             if ( requestStates.getMaximizedWindow() != null )
141             {
142                 requestMaximizedWindowId = requestStates.getMaximizedWindow().getId().toString();
143             }
144                 
145             if ( requestMaximizedWindowId == null )
146             {
147                 // check clearing MAXIMIZED window
148                 requestState = requestStates.getPortletWindowNavigationalState(pageState.maximizedWindowId);
149                 if ( requestState != null )
150                 {
151                     if (requestState.getWindowState() != null)
152                     {
153                         pageState.maximizedWindowId = null;
154                         // syncState will reset the sessionState.WindowState
155                     }                         
156                 }
157                 else
158                 {
159                     // check PortletWindow still exists...
160                     // depends on PortletWindowAccessor cache to be active
161                     PortletWindowAccessor accessor = 
162                         (PortletWindowAccessor)Jetspeed.getComponentManager().getComponent(PortletWindowAccessor.class);
163                     PortletWindow maximizedWindow = accessor.getPortletWindow(pageState.maximizedWindowId);
164                     if ( maximizedWindow == null )
165                     {
166                         // gone: remove sessionState
167                         pageState.windowStates.remove(pageState.maximizedWindowId);
168                         pageState.maximizedWindowId = null;
169                     }
170                     else
171                     {
172                         requestStates.setMaximizedWindow(maximizedWindow);
173                     }
174                 }
175             }
176             else if ( !requestMaximizedWindowId.equals( pageState.maximizedWindowId ))
177             {
178                 // When can a non-maximized window request maximized state while another already has it?
179                 // Maybe from a decoration portlet which always needs to be viewable?
180                 requestState = requestStates.getPortletWindowNavigationalState(pageState.maximizedWindowId);
181                 sessionState = (PortletWindowBaseNavigationalState)pageState.windowStates.get(pageState.maximizedWindowId);
182                 if ( requestState == null || requestState.getWindowState() == null )
183                 {
184                     // need to clear it ourselves first
185                     sessionState.setWindowState(null);
186                 }
187             }
188         }
189         
190         if ( requestStates.getMaximizedWindow() != null )
191         {
192             // store the new MAXIMIZED window
193             pageState.maximizedWindowId = requestStates.getMaximizedWindow().getId().toString();
194         }
195         
196         Iterator iter = requestStates.getWindowIdIterator();
197         String actionWindowId = requestStates.getActionWindow() != null ? requestStates.getActionWindow().getId().toString() : null;
198         boolean actionRequestState = false;
199         // now synchronize requestStates and sessionStates
200         while ( iter.hasNext() )
201         {
202             requestState = requestStates.getPortletWindowNavigationalState((String)iter.next());
203             sessionState = (PortletWindowBaseNavigationalState)pageState.windowStates.get(requestState.getWindowId());
204             if ( sessionState == null )
205             {
206                 if ( storeParameters )
207                 {
208                     sessionState = new PortletWindowExtendedNavigationalState();
209                 }
210                 else
211                 {
212                     sessionState = new PortletWindowBaseNavigationalState();
213                 }
214                 pageState.windowStates.put(requestState.getWindowId(),sessionState);
215             }
216 
217             actionRequestState = actionWindowId != null && actionWindowId.equals(requestState.getWindowId());
218             boolean changed = syncStates(actionRequestState, requestState, sessionState);      
219             if (changed)
220             {
221                 removeFromCache(context, requestState.getWindowId(), cache);
222                 removeFromCache(context, page.getId(), decorationCache);
223                 if (storeParameters)
224                 {
225                     ((PortletWindowExtendedNavigationalState)sessionState).resetDecoratorActionEncodings();
226                 }
227             }
228         }
229         
230         // now copy missing requestStates from the pageState
231         iter = pageState.windowStates.keySet().iterator();
232         String windowId;
233         while ( iter.hasNext() )
234         {
235             windowId = (String)iter.next();
236             requestState = requestStates.getPortletWindowNavigationalState(windowId);
237             if ( requestState == null )
238             {
239                 requestState = new PortletWindowRequestNavigationalState(windowId);
240                 boolean changed = syncStates(false, requestState,(PortletWindowBaseNavigationalState)pageState.windowStates.get(windowId));
241                 requestStates.addPortletWindowNavigationalState(windowId, requestState);
242                 if (changed)
243                 {
244                     removeFromCache(context, requestState.getWindowId(), cache);
245                     removeFromCache(context, page.getId(), decorationCache);                    
246                     if (storeParameters)
247                     {
248                         ((PortletWindowExtendedNavigationalState)sessionState).resetDecoratorActionEncodings();
249                     }
250                 }
251             }
252         }        
253     }
254     
255     private boolean modeChanged(PortletMode req, PortletMode ses)
256     {
257         if (req == null)
258         {
259             //if (ses != null && !ses.equals(PortletMode.VIEW))
260             //   return true;
261             return false;
262         }
263         else
264         {
265             if (ses == null)
266             {
267                 if (req.equals(PortletMode.VIEW))
268                     return false;
269                 return true;
270             }
271         }
272         return !req.equals(ses);
273     }
274     
275     private boolean stateChanged(WindowState req, WindowState ses)
276     {
277         if (req == null)
278         {
279             //if (ses != null && !ses.equals(WindowState.NORMAL))
280             //    return true;
281             return false;
282         }
283         else
284         {
285             if (ses == null)
286             {
287                 if (req.equals(WindowState.NORMAL))
288                     return false;
289                 return true;
290             }
291         }
292         return !req.equals(ses);
293     }
294 
295     
296     private boolean syncStates(boolean actionRequestState, PortletWindowRequestNavigationalState requestState, PortletWindowBaseNavigationalState sessionState)
297     {
298         boolean changed = false;
299         
300         if (modeChanged(requestState.getPortletMode(), sessionState.getPortletMode())
301                 || stateChanged(requestState.getWindowState(), sessionState.getWindowState()))
302             changed = true;
303                        
304         if ( requestState.getPortletMode() != null )
305         {
306             if ( requestState.getPortletMode().equals(PortletMode.VIEW) )
307             {
308                 sessionState.setPortletMode(null);
309             }
310             else
311             {
312                 sessionState.setPortletMode(requestState.getPortletMode());
313             }
314         }
315         else if ( sessionState.getPortletMode() == null )
316         {
317             requestState.setPortletMode(PortletMode.VIEW);
318         }
319         else
320         {
321             requestState.setPortletMode(sessionState.getPortletMode());
322         }
323         
324         if ( requestState.getWindowState() != null )
325         {
326             if ( requestState.getWindowState().equals(WindowState.NORMAL) )
327             {
328                 sessionState.setWindowState(null);
329             }
330             else
331             {
332                 sessionState.setWindowState(requestState.getWindowState());
333             }
334         }
335         else if ( sessionState.getWindowState() == null )
336         {
337             requestState.setWindowState(WindowState.NORMAL);
338         }
339         else        
340         {
341             requestState.setWindowState(sessionState.getWindowState());
342         }
343         
344         if (storeParameters)
345         {
346             PortletWindowExtendedNavigationalState extendedSessionState = (PortletWindowExtendedNavigationalState)sessionState;
347             if ( requestState.getParametersMap() != null )
348             {
349                 if ( actionRequestState )
350                 {
351                     // never store ActionRequest parameters in session
352                     extendedSessionState.setParametersMap(null);
353                 }
354                 else 
355                 {
356                     if (changedParameters(requestState.getParametersMap(), extendedSessionState.getParametersMap()))
357                     {
358                         changed = true;
359                     }
360                     extendedSessionState.setParametersMap(new HashMap(requestState.getParametersMap()));
361                 }
362             }
363             else if ( requestState.isClearParameters() )
364             {
365                 extendedSessionState.setParametersMap(null);
366                 requestState.setClearParameters(false);
367                 //changed = true;
368             }            
369             else if ( extendedSessionState.getParametersMap() != null )
370             {
371                 requestState.setParametersMap(new HashMap(extendedSessionState.getParametersMap()));
372             }
373         }
374         return changed;
375     }    
376 
377     protected boolean changedParameters(Map requestMap, Map sessionMap)
378     {
379         if (sessionMap == null || requestMap == null)
380             return true;
381         if (requestMap.size() != sessionMap.size())
382             return true;
383         Iterator ri = requestMap.entrySet().iterator();
384         Iterator si = sessionMap.entrySet().iterator();
385         while (ri.hasNext() && si.hasNext())
386         {
387             Map.Entry r = (Map.Entry)ri.next();
388             Map.Entry s = (Map.Entry)si.next();
389             if (!r.getKey().equals(s.getKey()))
390                 return true;
391             String[] rvals = (String[])r.getValue();
392             String[] svals = (String[])s.getValue();            
393             for (int ix = 0; ix < rvals.length; ix++)
394             {
395                 if (!rvals[ix].equals(svals[ix]))
396                     return true;
397             }
398         }
399         return false;
400     }
401     
402     protected void removeFromCache(RequestContext context, String id, JetspeedContentCache cache)
403     {
404         if (cache == null)
405             return;
406         ContentCacheKey cacheKey = cache.createCacheKey(context, id);
407         if (cache.isKeyInCache(cacheKey))
408         {
409             cache.remove(cacheKey);
410         }
411         cache.invalidate(context);
412     }
413     
414     protected Map getWindowStates(Page page)
415     {
416         PageState pageState = (PageState)pageStates.get(page.getId());
417         return pageState != null ? pageState.windowStates : null;
418     }
419 }