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.portalsite.impl;
18  
19  import java.util.ArrayList;
20  import java.util.HashMap;
21  import java.util.HashSet;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.Set;
26  import java.util.Collections;
27  
28  import org.apache.jetspeed.om.folder.Folder;
29  import org.apache.jetspeed.om.page.Page;
30  import org.apache.jetspeed.page.document.Node;
31  import org.apache.jetspeed.page.document.NodeException;
32  import org.apache.jetspeed.page.document.NodeNotFoundException;
33  import org.apache.jetspeed.page.document.NodeSet;
34  import org.apache.jetspeed.page.document.proxy.NodeSetImpl;
35  import org.apache.jetspeed.portalsite.Menu;
36  import org.apache.jetspeed.portalsite.PortalSiteRequestContext;
37  import org.apache.jetspeed.portalsite.PortalSiteSessionContext;
38  import org.apache.jetspeed.portalsite.view.SiteViewMenuDefinitionLocator;
39  
40  /***
41   * This class encapsulates managed request state for and
42   * interface to the portal-site component.
43   * 
44   * @author <a href="mailto:rwatler@apache.org">Randy Watler</a>
45   * @version $Id: PortalSiteRequestContextImpl.java 517121 2007-03-12 07:45:49Z ate $
46   */
47  public class PortalSiteRequestContextImpl implements PortalSiteRequestContext
48  {
49      /***
50       * sessionContext - component session state/interface
51       */
52      private PortalSiteSessionContextImpl sessionContext;
53  
54      /***
55       * requestProfileLocators - map of request profile locators by locator names
56       */
57      private Map requestProfileLocators;
58  
59      /***
60       * requestFallback - flag indicating whether request should fallback to root folder
61       *                   if locators do not select a page or access is forbidden
62       */
63      private boolean requestFallback;
64  
65      /***
66       * useHistory - flag indicating whether to use visited page
67       *              history to select default page per site folder
68       */
69      private boolean useHistory;
70  
71      /***
72       * page - cached request profiled page proxy
73       */
74      private Page requestPage;
75  
76      /***
77       * siblingPages - cached node set of visible sibling page proxies
78       */
79      private NodeSet siblingPages;
80  
81      /***
82       * siblingPagesCached - cached flag for sibling page proxies
83       */
84      private boolean siblingPagesCached;
85  
86      /***
87       * siblingFolders - cached node set of visible sibling folder proxies
88       */
89      private NodeSet siblingFolders;
90  
91      /***
92       * siblingFoldersCached - cached flag for sibling folder proxies
93       */
94      private boolean siblingFoldersCached;
95  
96      /***
97       * rootFolder - cached request profiled root folder proxy
98       */
99      private Folder requestRootFolder;
100 
101     /***
102      * rootLinks - cached node set of visible link proxies
103      */
104     private NodeSet rootLinks;
105 
106     /***
107      * rootLinksCached - cached flag for link proxies
108      */
109     private boolean rootLinksCached;
110 
111     /***
112      * pageMenuDefinitionNames - cached menu definition names for request page
113      */
114     private Set pageMenuDefinitionNames;
115 
116     /***
117      * menuDefinitionLocatorCache - cached menu definition locators for
118      *                              relative menus valid for request
119      */
120     private Map menuDefinitionLocatorCache;
121 
122     /***
123      * PortalSiteRequestContextImpl - constructor
124      *
125      * @param sessionContext session context
126      * @param requestProfileLocators request profile locators
127      * @param requestFallback flag specifying whether to fallback to root folder
128      *                        if locators do not select a page or access is forbidden
129      * @param useHistory flag indicating whether to use visited page
130      *                   history to select default page per site folder
131      */
132     public PortalSiteRequestContextImpl(PortalSiteSessionContextImpl sessionContext, Map requestProfileLocators,
133                                         boolean requestFallback, boolean useHistory)
134     {
135         this.sessionContext = sessionContext;
136         this.requestProfileLocators = requestProfileLocators;
137         this.requestFallback = requestFallback;
138         this.useHistory = useHistory;
139     }
140 
141     /***
142      * PortalSiteRequestContextImpl - constructor
143      *
144      * @param sessionContext session context
145      * @param requestProfileLocators request profile locators
146      * @param requestFallback flag specifying whether to fallback to root folder
147      *                        if locators do not select a page or access is forbidden
148      */
149     public PortalSiteRequestContextImpl(PortalSiteSessionContextImpl sessionContext, Map requestProfileLocators,
150                                         boolean requestFallback)
151     {
152         this(sessionContext, requestProfileLocators, requestFallback, true);
153     }
154 
155     /***
156      * PortalSiteRequestContextImpl - constructor
157      *
158      * @param sessionContext session context
159      * @param requestProfileLocators request profile locators
160      */
161     public PortalSiteRequestContextImpl(PortalSiteSessionContextImpl sessionContext, Map requestProfileLocators)
162     {
163         this(sessionContext, requestProfileLocators, true, true);
164     }
165 
166     /***
167      * getSessionContext - get component session context
168      *
169      * @return component session context
170      */
171     public PortalSiteSessionContext getSessionContext()
172     {
173         return sessionContext;
174     }
175 
176     /***
177      * getLocators - get profile locators by locator names
178      *  
179      * @return request profile locators
180      */
181     public Map getLocators()
182     {
183         return requestProfileLocators;
184     }
185 
186     /***
187      * getManagedPage - get request profiled concrete page instance
188      *                  as managed by the page manager
189      *  
190      * @return managed page
191      * @throws NodeNotFoundException if page not found
192      * @throws SecurityException if page view access not granted
193      */
194     public Page getManagedPage() throws NodeNotFoundException
195     {
196         return sessionContext.getManagedPage(getPage());            
197     }
198 
199     /***
200      * getPage - get request profiled page proxy
201      *  
202      * @return page proxy
203      * @throws NodeNotFoundException if page not found
204      * @throws SecurityException if page view access not granted
205      */
206     public Page getPage() throws NodeNotFoundException
207     {
208         // select request page from session context using
209         // request profile locators if not previously
210         // cached in this context
211         if (requestPage == null)
212         {
213             requestPage = sessionContext.selectRequestPage(requestProfileLocators, requestFallback, useHistory);            
214         }
215         return requestPage;
216     }
217 
218     /***
219      * getFolder - get folder proxy relative to request profiled page
220      *  
221      * @return page folder proxy
222      * @throws NodeNotFoundException if page not found
223      * @throws SecurityException if page view access not granted
224      */
225     public Folder getFolder() throws NodeNotFoundException
226     {
227         // return parent folder of request page
228         Page page = getPage();
229         if (page != null)
230         {
231             return (Folder)page.getParent();
232         }
233         return null;
234     }
235 
236     /***
237      * getSiblingPages - get node set of sibling page proxies relative
238      *                   to request profiled page, (includes profiled
239      *                   page proxy)
240      *  
241      * @return sibling page proxies
242      * @throws NodeNotFoundException if page not found
243      * @throws SecurityException if page view access not granted
244      */
245     public NodeSet getSiblingPages() throws NodeNotFoundException
246     {
247         // cache filtered return value
248         if (!siblingPagesCached)
249         {
250             // return pages from parent folder of request page
251             Folder folder = getFolder();
252             if (folder != null)
253             {
254                 try
255                 {
256                     // access, filter hidden, and cache
257                     siblingPages = filterHiddenNodes(folder.getPages());
258                     siblingPagesCached = true;
259                 }
260                 catch (NodeException ne)
261                 {
262                     NodeNotFoundException nnfe = new NodeNotFoundException("Sibling pages not found.");
263                     nnfe.initCause(ne);
264                     throw nnfe;
265                 }
266             }
267         }
268         return siblingPages;
269     }
270 
271     /***
272      * getParentFolder - get parent folder proxy relative to request
273      *                   profiled page
274      *  
275      * @return parent folder proxy or null
276      * @throws NodeNotFoundException if page not found
277      * @throws SecurityException if page view access not granted
278      */
279     public Folder getParentFolder() throws NodeNotFoundException
280     {
281         // return parent folder of parent folder of request page
282         Folder folder = getFolder();
283         if (folder != null)
284         {
285             // access, filter hidden, and return
286             Folder parent = (Folder)folder.getParent();
287             if ((parent != null) && !parent.isHidden())
288             {
289                 return parent;
290             }
291         }
292         return null;
293     }
294 
295     /***
296      * getSiblingFolders - get node set of sibling folder proxies relative
297      *                     to request profiled page, (includes profiled
298      *                     page folder proxy)
299      *  
300      * @return sibling folder proxies
301      * @throws NodeNotFoundException if page not found
302      * @throws SecurityException if page view access not granted
303      */
304     public NodeSet getSiblingFolders() throws NodeNotFoundException
305     {
306         // cache filtered return value
307         if (!siblingFoldersCached)
308         {
309             // return folders from parent folder of request page
310             Folder folder = getFolder();
311             if (folder != null)
312             {
313                 try
314                 {
315                     // access, filter hidden, and cache
316                     siblingFolders = filterHiddenNodes(folder.getFolders());
317                     siblingFoldersCached = true;
318                 }
319                 catch (NodeException ne)
320                 {
321                     NodeNotFoundException nnfe = new NodeNotFoundException("Sibling folders not found.");
322                     nnfe.initCause(ne);
323                     throw nnfe;
324                 }
325             }
326         }
327         return siblingFolders;
328     }
329 
330     /***
331      * getRootFolder - get root profiled folder proxy
332      *  
333      * @return parent folder proxy
334      * @throws NodeNotFoundException if page not found
335      * @throws SecurityException if page view access not granted
336      */
337     public Folder getRootFolder() throws NodeNotFoundException
338     {
339         // get request root folder from session context
340         // using request profile locators if not previously
341         // cached in this context
342         if (requestRootFolder == null)
343         {
344             requestRootFolder = sessionContext.getRequestRootFolder(requestProfileLocators);
345         }
346         return requestRootFolder;
347     }
348 
349     /***
350      * getRootLinks - get node set of link proxies relative to
351      *                profiled root folder
352      *  
353      * @return root link proxies
354      * @throws NodeNotFoundException if page not found
355      * @throws SecurityException if page view access not granted
356      */
357     public NodeSet getRootLinks() throws NodeNotFoundException
358     {
359         // cache filtered return value
360         if (!rootLinksCached)
361         {
362             // return links from request root folder
363             Folder rootFolder = getRootFolder();
364             if (rootFolder != null)
365             {
366                 try
367                 {
368                     // access, filter hidden, and cache
369                     rootLinks = filterHiddenNodes(rootFolder.getLinks());
370                     rootLinksCached = true;
371                 }
372                 catch (NodeException ne)
373                 {
374                     NodeNotFoundException nnfe = new NodeNotFoundException("Root links not found.");
375                     nnfe.initCause(ne);
376                     throw nnfe;
377                 }
378             }
379         }
380         return rootLinks;
381     }
382 
383     /***
384      * getStandardMenuNames - get set of available standard menu names
385      *  
386      * @return menu names set
387      */
388     public Set getStandardMenuNames()
389     {
390         // return standard menu names defined for session
391         return sessionContext.getStandardMenuNames();
392     }
393 
394     /***
395      * getCustomMenuNames - get set of custom menu names available as
396      *                      defined for the request profiled page and folder
397      *  
398      * @return menu names set
399      * @throws NodeNotFoundException if page not found
400      * @throws SecurityException if page view access not granted
401      */
402     public Set getCustomMenuNames() throws NodeNotFoundException
403     {
404         // access page to force request page resolution
405         Page page = getPage();
406 
407         // return available menu definition names from
408         // current request page if not previously cached
409         // in this context
410         Set standardMenuNames = sessionContext.getStandardMenuNames();
411         if ((page != null) && (standardMenuNames != null) && (pageMenuDefinitionNames == null))
412         {
413             List locators = sessionContext.getMenuDefinitionLocators(page);
414             if (locators != null)
415             {
416                 // get custom definition names
417                 pageMenuDefinitionNames = Collections.synchronizedSet(new HashSet(locators.size()));
418                 Iterator locatorsIter = locators.iterator();
419                 while (locatorsIter.hasNext())
420                 {
421                     // get definition name; filter standard menu names
422                     String definitionName = ((SiteViewMenuDefinitionLocator)locatorsIter.next()).getName();
423                     if (!standardMenuNames.contains(definitionName))
424                     {
425                         pageMenuDefinitionNames.add(definitionName);
426                     }
427                 }
428             }
429             else
430             {
431                 pageMenuDefinitionNames = Collections.synchronizedSet(new HashSet(0));
432             }
433         }
434         return pageMenuDefinitionNames;
435     }
436 
437     /***
438      * getMenu - get instantiated menu available for the request
439      *           profiled page and folder
440      *  
441      * @param name menu definition name
442      * @return menu instance
443      * @throws NodeNotFoundException if page not found
444      * @throws SecurityException if page view access not granted
445      */
446     public Menu getMenu(String name) throws NodeNotFoundException
447     {
448         // get menu initiating at menu definition root
449         // with no related menu definition names
450         return getMenu(name, null);
451     }
452 
453     /***
454      * getMenu - get instantiated menu available for the request
455      *           profiled page and folder, avoiding cyclic
456      *           menu definition loops by propagating related menu
457      *           names set from menu construction
458      *
459      * @param name menu definition name
460      * @param names set of related menu definition names
461      * @return menu instance
462      * @throws NodeNotFoundException if page not found
463      * @throws SecurityException if page view access not granted
464      */
465     public Menu getMenu(String name, Set names) throws NodeNotFoundException
466     {
467         // access page to force request page resolution
468         Page page = getPage();
469         if ((page != null) && (name != null))
470         {
471             // get menu definition locator
472             SiteViewMenuDefinitionLocator locator = sessionContext.getMenuDefinitionLocator(page, name);
473             if (locator != null)
474             {
475                 // lookup and return cached relative/request menus
476                 if (menuDefinitionLocatorCache != null)
477                 {
478                     MenuImpl menu = (MenuImpl)menuDefinitionLocatorCache.get(locator);
479                     if (menu != null)
480                     {
481                         return menu;
482                     }
483                 }
484 
485                 // lookup and return cached absolute/session menus
486                 // if current page is not hidden; hidden pages generate
487                 // menus that should be considered relative since
488                 // explicitly addressed hidden pages are added to
489                 // menus for display purposes
490                 if (sessionContext.getMenuDefinitionLocatorCache() != null)
491                 {
492                     MenuImpl menu = (MenuImpl)sessionContext.getMenuDefinitionLocatorCache().get(locator);
493                     if (menu != null)
494                     {
495                         return menu;
496                     }
497                 }
498 
499                 // construct new menu from menu definition in locator
500                 // using current request context and propagating related
501                 // names set to detect cyclic menu definitions
502                 MenuImpl menu = new MenuImpl(locator.getMenuDefinition(), this, names);
503  
504                 // determine whether menu definition locator is
505                 // relative/request, based on hidden page, or
506                 // absolute/session cachable and cache accordingly
507                 if (page.isHidden() || menu.isElementRelative())
508                 {
509                     // cache relative menu for request
510                     if (menuDefinitionLocatorCache == null)
511                     {
512                         menuDefinitionLocatorCache = Collections.synchronizedMap(new HashMap(8));
513                     }
514                     menuDefinitionLocatorCache.put(locator, menu);
515                 }
516                 else
517                 {
518                     // cache absolute menu for session
519                     if (sessionContext.getMenuDefinitionLocatorCache() == null)
520                     {
521                         sessionContext.setMenuDefinitionLocatorCache(Collections.synchronizedMap(new HashMap(8)));
522                     }
523                     sessionContext.getMenuDefinitionLocatorCache().put(locator, menu);
524                 }
525 
526                 // return new cached menu
527                 return menu;
528             }
529         }
530         return null;
531     }
532 
533     /***
534      * filterHiddenNodes - utility to filter hidden node proxies out of node sets
535      *
536      * @param nodes proxy node set to filter
537      * @return input or filtered proxy node set
538      */
539     private static NodeSet filterHiddenNodes(NodeSet nodes)
540     {
541         if ((nodes != null) && !nodes.isEmpty())
542         {
543             // filter node proxies in node set
544             List filteredNodes = null;
545             Iterator nodesIter = nodes.iterator();
546             while (nodesIter.hasNext())
547             {
548                 // test hidden status of individual node proxies
549                 Node node = (Node)nodesIter.next();
550                 if (node.isHidden())
551                 {
552                     // if not copying, create new node set
553                     // and copy preceding node proxies
554                     if (filteredNodes == null)
555                     {
556                         filteredNodes = new ArrayList(nodes.size());
557                         Iterator copyIter = nodes.iterator();
558                         while (copyIter.hasNext())
559                         {
560                             Node copyNode = (Node)copyIter.next();
561                             if (copyNode != node)
562                             {
563                                 filteredNodes.add(copyNode);
564                             }
565                             else
566                             {
567                                 break;
568                             }
569                         }
570                     }
571                 }
572                 else if (filteredNodes != null)
573                 {
574                     // if copying, copy node proxy to filtered set
575                     filteredNodes.add(node);
576                 }
577             }
578 
579             // return filteredNodes node proxies if generated
580             // in new immutable proxy node set
581             if (filteredNodes != null)
582             {
583                 return new NodeSetImpl(filteredNodes);
584             }
585         }
586         return nodes;
587     }
588 }