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.om.folder.impl;
18  
19  import java.security.AccessController;
20  import java.util.Collection;
21  import java.util.Comparator;
22  import java.util.Iterator;
23  import java.util.List;
24  
25  import org.apache.jetspeed.JetspeedActions;
26  import org.apache.jetspeed.om.folder.Folder;
27  import org.apache.jetspeed.om.folder.FolderNotFoundException;
28  import org.apache.jetspeed.om.folder.MenuDefinition;
29  import org.apache.jetspeed.om.folder.MenuExcludeDefinition;
30  import org.apache.jetspeed.om.folder.MenuIncludeDefinition;
31  import org.apache.jetspeed.om.folder.MenuOptionsDefinition;
32  import org.apache.jetspeed.om.folder.MenuSeparatorDefinition;
33  import org.apache.jetspeed.om.page.Fragment;
34  import org.apache.jetspeed.om.page.Link;
35  import org.apache.jetspeed.om.page.Page;
36  import org.apache.jetspeed.om.page.PageMetadataImpl;
37  import org.apache.jetspeed.om.page.PageSecurity;
38  import org.apache.jetspeed.om.page.impl.LinkImpl;
39  import org.apache.jetspeed.om.page.impl.PageImpl;
40  import org.apache.jetspeed.om.page.impl.PageSecurityImpl;
41  import org.apache.jetspeed.page.PageManager;
42  import org.apache.jetspeed.page.PageNotFoundException;
43  import org.apache.jetspeed.page.document.DocumentException;
44  import org.apache.jetspeed.page.document.DocumentNotFoundException;
45  import org.apache.jetspeed.page.document.Node;
46  import org.apache.jetspeed.page.document.NodeException;
47  import org.apache.jetspeed.page.document.NodeNotFoundException;
48  import org.apache.jetspeed.page.document.NodeSet;
49  import org.apache.jetspeed.page.document.impl.NodeImpl;
50  import org.apache.jetspeed.page.document.impl.NodeSetImpl;
51  import org.apache.jetspeed.page.impl.DatabasePageManagerUtils;
52  import org.apache.jetspeed.security.FolderPermission;
53  import org.apache.ojb.broker.core.proxy.ProxyHelper;
54  
55  /***
56   * FolderImpl
57   *
58   * @author <a href="mailto:rwatler@apache.org">Randy Watler</a>
59   * @version $Id$
60   */
61  public class FolderImpl extends NodeImpl implements Folder
62  {
63      private String defaultPage;
64      private String skin;
65      private String defaultLayoutDecorator;
66      private String defaultPortletDecorator;
67      private List orders;
68      private List menus;
69  
70      private PageManager pageManager;
71      private List folders;
72      private boolean foldersCached;
73      private List pages;
74      private boolean pagesCached;
75      private List links;
76      private boolean linksCached;
77      private PageSecurityImpl pageSecurity;
78      private boolean pageSecurityCached;
79      private List all;
80      private boolean allCached;
81      private FolderOrderList documentOrder;
82      private boolean documentOrderComparatorValid;
83      private Comparator documentOrderComparator;
84      private NodeSet foldersNodeSet;
85      private NodeSet pagesNodeSet;
86      private NodeSet linksNodeSet;
87      private NodeSet allNodeSet;
88      private FolderMenuDefinitionList menuDefinitions;
89  
90      public FolderImpl()
91      {
92          super(new FolderSecurityConstraintsImpl());
93      }
94  
95      /***
96       * accessFolderOrders
97       *
98       * Access mutable persistent collection member for List wrappers.
99       *
100      * @return persistent collection
101      */
102     List accessFolderOrders()
103     {
104         // create initial collection if necessary
105         if (orders == null)
106         {
107             orders = DatabasePageManagerUtils.createList();
108         }
109         return orders;
110     }
111 
112     /***
113      * accessMenus
114      *
115      * Access mutable persistent collection member for List wrappers.
116      *
117      * @return persistent collection
118      */
119     List accessMenus()
120     {
121         // create initial collection if necessary
122         if (menus == null)
123         {
124             menus = DatabasePageManagerUtils.createList();
125         }
126         return menus;
127     }
128 
129     /***
130      * setPageManager
131      *
132      * Infuses PageManager for use by this folder instance.
133      *
134      * @param pageManager page manager that manages this folder instance
135      */
136     public void setPageManager(PageManager pageManager)
137     {
138         this.pageManager = pageManager;
139     }
140 
141     /***
142      * accessFolders
143      *
144      * Access folders transient cache collection for use by PageManager.
145      *
146      * @return folders collection
147      */
148     public List accessFolders()
149     {
150         // create initial collection if necessary
151         if (folders == null)
152         {
153             folders = DatabasePageManagerUtils.createList();
154         }
155         return folders;
156     }
157 
158     /***
159      * resetFolders
160      *
161      * Reset folders transient caches for use by PageManager.
162      *
163      * @param cached set cached state for folders
164      */
165     public void resetFolders(boolean cached)
166     {
167         // save cached state
168         foldersCached = cached;
169         allCached = false;
170 
171         // update node caches
172         if (!cached)
173         {
174             accessFolders().clear();
175         }
176         accessAll().clear();
177 
178         // reset cached node sets
179         foldersNodeSet = null;
180         allNodeSet = null;
181     }
182 
183     /***
184      * accessPages
185      *
186      * Access pages transient cache collection for use by PageManager.
187      *
188      * @return pages collection
189      */
190     public List accessPages()
191     {
192         // create initial collection if necessary
193         if (pages == null)
194         {
195             pages = DatabasePageManagerUtils.createList();
196         }
197         return pages;
198     }
199 
200     /***
201      * resetPages
202      *
203      * Reset pages transient caches for use by PageManager.
204      *
205      * @param cached set cached state for pages
206      */
207     public void resetPages(boolean cached)
208     {
209         // save cached state
210         pagesCached = cached;
211         allCached = false;
212 
213         // update node caches
214         if (!cached)
215         {
216             accessPages().clear();
217         }
218         accessAll().clear();
219 
220         // reset cached node sets
221         pagesNodeSet = null;
222         allNodeSet = null;
223     }
224 
225     /***
226      * accessLinks
227      *
228      * Access links transient cache collection for use by PageManager.
229      *
230      * @return links collection
231      */
232     public List accessLinks()
233     {
234         // create initial collection if necessary
235         if (links == null)
236         {
237             links = DatabasePageManagerUtils.createList();
238         }
239         return links;
240     }
241 
242     /***
243      * resetLinks
244      *
245      * Reset links transient caches for use by PageManager.
246      *
247      * @param cached set cached state for links
248      */
249     public void resetLinks(boolean cached)
250     {
251         // save cached state
252         linksCached = cached;
253         allCached = false;
254 
255         // update node caches
256         if (!cached)
257         {
258             accessLinks().clear();
259         }
260         accessAll().clear();
261 
262         // reset cached node sets
263         linksNodeSet = null;
264         allNodeSet = null;
265     }
266 
267     /***
268      * accessPageSecurity
269      *
270      * Access pageSecurity cached instance for use by PageManager.
271      *
272      * @return pageSecurity instance
273      */
274     public PageSecurityImpl accessPageSecurity()
275     {
276         return pageSecurity;
277     }
278 
279     /***
280      * resetPageSecurity
281      *
282      * Reset pageSecurity transient cache instance for use by PageManager.
283      *
284      * @param newPageSecurty cached page security instance.
285      * @param cached set cached state for page security
286      */
287     public void resetPageSecurity(PageSecurityImpl newPageSecurity, boolean cached)
288     {
289         // save cached state
290         pageSecurity = newPageSecurity;
291         pageSecurityCached = cached;
292         allCached = false;
293 
294         // update node caches
295         accessAll().clear();
296 
297         // reset cached node sets
298         allNodeSet = null;
299     }
300 
301     /***
302      * accessAll
303      *
304      * Access all transient cache collection for use by PageManager.
305      *
306      * @return all collection
307      */
308     public List accessAll()
309     {
310         // create initial collection if necessary
311         if (all == null)
312         {
313             all = DatabasePageManagerUtils.createList();
314         }
315         return all;
316     }
317 
318     /***
319      * resetAll
320      *
321      * Reset all transient caches for use by PageManager.
322      *
323      * @param cached set cached state for all
324      */
325     public void resetAll(boolean cached)
326     {
327         // save cached state
328         allCached = cached;
329         foldersCached = cached;
330         pagesCached = cached;
331         linksCached = cached;
332         pageSecurityCached = cached;
333 
334         // update node caches
335         accessFolders().clear();
336         accessPages().clear();
337         accessLinks().clear();
338         pageSecurity = null;
339         if (cached)
340         {
341             // populate node caches
342             synchronized(all)
343             {
344                 Iterator nodeIter = accessAll().iterator();
345                 while (nodeIter.hasNext())
346                 {
347                     Node node = (Node)nodeIter.next();
348                     if (node instanceof PageImpl)
349                     {
350                         pages.add(node);
351                     }
352                     else if (node instanceof FolderImpl)
353                     {
354                         folders.add(node);
355                     }
356                     else if (node instanceof LinkImpl)
357                     {
358                         links.add(node);
359                     }
360                     else if (node instanceof PageSecurityImpl)
361                     {
362                         pageSecurity = (PageSecurityImpl)node;
363                     }
364                 }
365             }
366         }
367         else
368         {
369             accessAll().clear();
370         }
371 
372         // reset cached node sets
373         allNodeSet = null;
374         foldersNodeSet = null;
375         pagesNodeSet = null;
376         linksNodeSet = null;
377     }
378 
379     /***
380      * createDocumentOrderComparator
381      *
382      * @return document order comparator
383      */
384     private Comparator createDocumentOrderComparator()
385     {
386         if (!documentOrderComparatorValid)
387         {
388             documentOrderComparatorValid = true;
389             // return null if no document order exists;
390             // (null implies natural ordering by name)
391             final List documentOrder = getDocumentOrder();
392             if ((documentOrder == null) || documentOrder.isEmpty())
393             {
394                 return null;
395             }
396             // create new document order comparator
397             documentOrderComparator = new Comparator()
398                 {
399                     /* (non-Javadoc)
400                      * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
401                      */
402                     public int compare(Object o1, Object o2)
403                     {
404                         // Compare node names using document order;
405                         // use indicies as names if found in document
406                         // order to force explicitly ordered items
407                         // ahead of unordered items
408                         String name1 = (String)o1;
409                         int index1 = documentOrder.indexOf(name1);
410                         if (index1 >= 0)
411                         {
412                             // use order index as name1
413                             name1 = String.valueOf(index1);
414                         }
415                         String name2 = (String)o2;
416                         int index2 = documentOrder.indexOf(name2);
417                         if (index2 >= 0)
418                         {
419                             // use order index as name2
420                             name2 = String.valueOf(index2);
421                             if (index1 >= 0)
422                             {
423                                 // pad order indicies for numeric string compare
424                                 while (name1.length() != name2.length())
425                                 {
426                                     if (name1.length() < name2.length())
427                                     {
428                                         name1 = "0" + name1;
429                                     }
430                                     else
431                                     {
432                                         name2 = "0" + name2;
433                                     }
434                                 }
435                             }
436                         }
437                         // compare names and/or indicies
438                         return name1.compareTo(name2);                        
439                     }
440                 };
441         }
442         return documentOrderComparator;
443     }
444 
445     /***
446      * clearDocumentOrderComparator
447      */
448     void clearDocumentOrderComparator()
449     {
450         // clear node set ordering
451         documentOrderComparatorValid = false;
452         documentOrderComparator = null;
453         // clear previously cached node sets
454         allNodeSet = null;
455         foldersNodeSet = null;
456         pagesNodeSet = null;
457     }
458 
459     /* (non-Javadoc)
460      * @see org.apache.jetspeed.page.document.impl.NodeImpl#newPageMetadata(java.util.Collection)
461      */
462     public PageMetadataImpl newPageMetadata(Collection fields)
463     {
464         PageMetadataImpl pageMetadata = new PageMetadataImpl(FolderMetadataLocalizedFieldImpl.class);
465         pageMetadata.setFields(fields);
466         return pageMetadata;
467     }
468     
469     /* (non-Javadoc)
470      * @see org.apache.jetspeed.om.page.impl.BaseElementImpl#getEffectivePageSecurity()
471      */
472     public PageSecurity getEffectivePageSecurity()
473     {
474         // return page security instance if available
475         if (!pageSecurityCached)
476         {
477             // use PageManager to get and cache page security
478             // instance for this folder
479             try
480             {
481                 return pageManager.getPageSecurity(this);
482             }
483             catch (NodeException ne)
484             {
485             }
486             catch (NodeNotFoundException nnfe)
487             {
488             }
489         }
490         else if (pageSecurity != null)
491         {
492             return pageSecurity;
493         }
494 
495         // delegate to real parent folder implementation
496         FolderImpl parentFolderImpl = (FolderImpl)ProxyHelper.getRealObject(getParent());
497         if (parentFolderImpl != null)
498         {
499             return parentFolderImpl.getEffectivePageSecurity();
500         }
501         return null;
502     }
503 
504     /* (non-Javadoc)
505      * @see org.apache.jetspeed.om.page.impl.BaseElementImpl#checkPermissions(java.lang.String, int, boolean, boolean)
506      */
507     public void checkPermissions(String path, int mask, boolean checkNodeOnly, boolean checkParentsOnly) throws SecurityException
508     {
509         // check granted folder permissions unless the check is
510         // to be skipped due to explicity granted access
511         if (!checkParentsOnly)
512         {
513             FolderPermission permission = new FolderPermission(path, mask);
514             AccessController.checkPermission(permission);
515         }
516 
517         // if not checking node only, recursively check
518         // all parent permissions in hierarchy
519         if (!checkNodeOnly)
520         {
521             FolderImpl parentFolderImpl = (FolderImpl)ProxyHelper.getRealObject(getParent());
522             if (parentFolderImpl != null)
523             {
524                 parentFolderImpl.checkPermissions(mask, false, false);
525             }
526         }
527     }
528 
529     /* (non-Javadoc)
530      * @see org.apache.jetspeed.om.page.BaseElement#getTitle()
531      */
532     public String getTitle()
533     {
534         // default title to folder name
535         String title = super.getTitle();
536         if (title == null)
537         {
538             title = defaultTitleFromName();
539             setTitle(title);
540         }
541         return title;
542     }
543 
544     /* (non-Javadoc)
545      * @see org.apache.jetspeed.om.folder.Folder#getSkin()
546      */
547     public String getSkin()
548     {
549         return skin;
550     }
551     
552     /* (non-Javadoc)
553      * @see org.apache.jetspeed.om.folder.Folder#setSkin(java.lang.String)
554      */
555     public void setSkin(String skinName)
556     {
557         this.skin = skinName;
558     }
559 
560     /* (non-Javadoc)
561      * @see org.apache.jetspeed.om.folder.Folder#getEffectiveDefaultDecorator(java.lang.String)
562      */
563     public String getEffectiveDefaultDecorator(String fragmentType)
564     {
565         // get locally defined decorator
566         String decorator = getDefaultDecorator(fragmentType);
567         if (decorator == null)
568         {
569             // delegate to parent folder
570             Folder parentFolder = (Folder)ProxyHelper.getRealObject(getParent());
571             if (parentFolder != null)
572             {
573                 return parentFolder.getEffectiveDefaultDecorator(fragmentType);
574             }
575         }
576         return decorator;
577     }
578 
579     /* (non-Javadoc)
580      * @see org.apache.jetspeed.om.folder.Folder#getDefaultDecorator(java.lang.String)
581      */
582     public String getDefaultDecorator(String fragmentType)
583     {
584         // retrieve supported decorator types
585         if (fragmentType != null)
586         {
587             if (fragmentType.equals(Fragment.LAYOUT))
588             {
589                 return defaultLayoutDecorator; 
590             }
591             if (fragmentType.equals(Fragment.PORTLET))
592             {
593                 return defaultPortletDecorator; 
594             }
595         }
596         return null;
597     }
598     
599     /* (non-Javadoc)
600      * @see org.apache.jetspeed.om.folder.Folder#getDefaultDecorator(java.lang.String,java.lang.String)
601      */
602     public void setDefaultDecorator(String decoratorName, String fragmentType)
603     {
604         // save supported decorator types
605         if (fragmentType != null)
606         {
607             if (fragmentType.equals(Fragment.LAYOUT))
608             {
609                 defaultLayoutDecorator = decoratorName; 
610             }
611             if (fragmentType.equals(Fragment.PORTLET))
612             {
613                 defaultPortletDecorator = decoratorName; 
614             }
615         }
616     }
617 
618     /* (non-Javadoc)
619      * @see org.apache.jetspeed.om.folder.Folder#getDocumentOrder()
620      */
621     public List getDocumentOrder()
622     {
623         // return mutable document order list
624         // by using list wrapper to manage sort
625         // order and element uniqueness
626         if (documentOrder == null)
627         {
628             documentOrder = new FolderOrderList(this);
629         }
630         return documentOrder;
631     }
632     
633     /* (non-Javadoc)
634      * @see org.apache.jetspeed.om.folder.Folder#setDocumentOrder(java.util.List)
635      */
636     public void setDocumentOrder(List docNames)
637     {
638         // set document order using ordered document
639         // names by replacing existing entries with
640         // new elements if new collection is specified
641         List documentOrder = getDocumentOrder();
642         if (docNames != documentOrder)
643         {
644             // replace all document order names
645             documentOrder.clear();
646             if (docNames != null)
647             {
648                 documentOrder.addAll(docNames);
649             }
650         }
651     }
652 
653     /* (non-Javadoc)
654      * @see org.apache.jetspeed.om.folder.Folder#getDefaultPage()
655      */
656     public String getDefaultPage()
657     {
658         return defaultPage;
659     }
660     
661     /* (non-Javadoc)
662      * @see org.apache.jetspeed.om.folder.Folder#setDefaultPage(java.lang.String)
663      */
664     public void setDefaultPage(String defaultPage)
665     {
666         this.defaultPage = defaultPage;
667     }
668 
669     /* (non-Javadoc)
670      * @see org.apache.jetspeed.om.folder.Folder#getFolders()
671      */
672     public NodeSet getFolders() throws DocumentException
673     {
674         // get folders collection
675         if (!foldersCached)
676         {
677             // use PageManager to get and cache folders
678             // collection for this folder
679             return pageManager.getFolders(this);
680         }
681 
682         // return nodes with view access
683         return filterNodeSetByAccess(getFoldersNodeSet());
684     }
685     
686     /* (non-Javadoc)
687      * @see org.apache.jetspeed.om.folder.Folder#getFolder(java.lang.String)
688      */
689     public Folder getFolder(String name) throws FolderNotFoundException, DocumentException
690     {
691         // get folder instance if folders collection not available
692         if (!foldersCached)
693         {
694             // use PageManager to get folder instance without
695             // caching the folders collection for this folder
696             return pageManager.getFolder(this, name);
697         }
698 
699         // select folder by name from cached folders collection
700         Folder folder = (Folder)getFoldersNodeSet().get(name);
701         if (folder == null)
702         {
703             throw new FolderNotFoundException("Folder not found: " + name);
704         }
705 
706         // check for view access on folder
707         folder.checkAccess(JetspeedActions.VIEW);
708 
709         return folder;
710     }
711     
712     /* (non-Javadoc)
713      * @see org.apache.jetspeed.om.folder.Folder#getPages()
714      */
715     public NodeSet getPages() throws NodeException
716     {
717         // get pages collection
718         if (!pagesCached)
719         {
720             // use PageManager to get and cache pages
721             // collection for this folder
722             return pageManager.getPages(this);
723         }
724 
725         // return nodes with view access
726         return filterNodeSetByAccess(getPagesNodeSet());
727     }
728     
729     /* (non-Javadoc)
730      * @see org.apache.jetspeed.om.folder.Folder#getPage(java.lang.String)
731      */
732     public Page getPage(String name) throws PageNotFoundException, NodeException
733     {
734         // get page instance if pages collection not available
735         if (!pagesCached)
736         {
737             // use PageManager to get page instance without
738             // caching the pages collection for this folder
739             return pageManager.getPage(this, name);
740         }
741 
742         // select page by name from cached pages collection
743         Page page = (Page)getPagesNodeSet().get(name);
744         if (page == null)
745         {
746             throw new PageNotFoundException("Page not found: " + name);
747         }
748 
749         // check for view access on page
750         page.checkAccess(JetspeedActions.VIEW);
751 
752         return page;
753     }
754     
755     /* (non-Javadoc)
756      * @see org.apache.jetspeed.om.folder.Folder#getLinks()
757      */
758     public NodeSet getLinks() throws NodeException
759     {
760         // get links collection
761         if (!linksCached)
762         {
763             // use PageManager to get and cache links
764             // collection for this folder
765             return pageManager.getLinks(this);
766         }
767 
768         // return nodes with view access
769         return filterNodeSetByAccess(getLinksNodeSet());
770     }
771     
772     /* (non-Javadoc)
773      * @see org.apache.jetspeed.om.folder.Folder#getLink(java.lang.String)
774      */
775     public Link getLink(String name) throws DocumentNotFoundException, NodeException
776     {
777         // get link instance if links collection not available
778         if (!linksCached)
779         {
780             // use PageManager to get link instance without
781             // caching the links collection for this folder
782             return pageManager.getLink(this, name);
783         }
784 
785         // select link by name from cached links collection
786         Link link = (Link)getLinksNodeSet().get(name);
787         if (link == null)
788         {
789             throw new DocumentNotFoundException("Link not found: " + name);
790         }
791 
792         // check for view access on link
793         link.checkAccess(JetspeedActions.VIEW);
794 
795         return link;
796     }
797     
798     /* (non-Javadoc)
799      * @see org.apache.jetspeed.om.folder.Folder#getPageSecurity()
800      */
801     public PageSecurity getPageSecurity() throws DocumentNotFoundException, NodeException
802     {
803         // get page security instance
804         if (!pageSecurityCached)
805         {
806             // use PageManager to get and cache page security
807             // instance for this folder
808             return pageManager.getPageSecurity(this);
809         }
810         if (pageSecurity == null)
811         {
812             throw new DocumentNotFoundException("Page security document not found");
813         }
814 
815         // check for view access on document
816         pageSecurity.checkAccess(JetspeedActions.VIEW);
817 
818         return pageSecurity;
819     }
820     
821     /* (non-Javadoc)
822      * @see org.apache.jetspeed.om.folder.Folder#getAll()
823      */
824     public NodeSet getAll() throws DocumentException
825     {
826         // get all nodes collection
827         if (!allCached)
828         {
829             // use PageManager to get and cache all nodes
830             // collection for this folder
831             return pageManager.getAll(this);
832         }
833 
834         // return nodes with view access
835         return filterNodeSetByAccess(getAllNodeSet());
836     }
837     
838     /* (non-Javadoc)
839      * @see org.apache.jetspeed.om.folder.Folder#getMenuDefinitions()
840      */
841     public List getMenuDefinitions()
842     {
843         // return mutable menu definition list
844         // by using list wrapper to manage
845         // element uniqueness
846         if (menuDefinitions == null)
847         {
848             menuDefinitions = new FolderMenuDefinitionList(this);
849         }
850         return menuDefinitions;
851     }
852     
853     /* (non-Javadoc)
854      * @see org.apache.jetspeed.om.folder.Folder#newMenuDefinition()
855      */
856     public MenuDefinition newMenuDefinition()
857     {
858         return new FolderMenuDefinitionImpl();
859     }
860 
861     /* (non-Javadoc)
862      * @see org.apache.jetspeed.om.folder.Folder#newMenuExcludeDefinition()
863      */
864     public MenuExcludeDefinition newMenuExcludeDefinition()
865     {
866         return new FolderMenuExcludeDefinitionImpl();
867     }
868 
869     /* (non-Javadoc)
870      * @see org.apache.jetspeed.om.folder.Folder#newMenuIncludeDefinition()
871      */
872     public MenuIncludeDefinition newMenuIncludeDefinition()
873     {
874         return new FolderMenuIncludeDefinitionImpl();
875     }
876 
877     /* (non-Javadoc)
878      * @see org.apache.jetspeed.om.folder.Folder#newMenuOptionsDefinition()
879      */
880     public MenuOptionsDefinition newMenuOptionsDefinition()
881     {
882         return new FolderMenuOptionsDefinitionImpl();
883     }
884 
885     /* (non-Javadoc)
886      * @see org.apache.jetspeed.om.folder.Folder#newMenuSeparatorDefinition()
887      */
888     public MenuSeparatorDefinition newMenuSeparatorDefinition()
889     {
890         return new FolderMenuSeparatorDefinitionImpl();
891     }
892 
893     /* (non-Javadoc)
894      * @see org.apache.jetspeed.om.folder.Folder#setMenuDefinitions(java.util.List)
895      */
896     public void setMenuDefinitions(List definitions)
897     {
898         // set menu definitions by replacing
899         // existing entries with new elements if
900         // new collection is specified
901         List menuDefinitions = getMenuDefinitions();
902         if (definitions != menuDefinitions)
903         {
904             // replace all menu definitions
905             menuDefinitions.clear();
906             if (definitions != null)
907             {
908                 menuDefinitions.addAll(definitions);
909             }
910         }
911     }
912 
913     /* (non-Javadoc)
914      * @see org.apache.jetspeed.om.folder.Folder#isReserved()
915      */
916     public boolean isReserved()
917     {
918         // folders are always concrete in this implementation
919         return false;
920     }
921     
922     /* (non-Javadoc)
923      * @see org.apache.jetspeed.om.folder.Folder#getReservedType()
924      */
925     public int getReservedType()
926     {
927         // folders are always concrete in this implementation
928         return RESERVED_FOLDER_NONE;
929     }
930 
931     /* (non-Javadoc)
932      * @see org.apache.jetspeed.page.document.Node#getType()
933      */
934     public String getType()
935     {
936         return FOLDER_TYPE;
937     }
938 
939     /***
940      * getFoldersNodeSet
941      *
942      * Latently create and access folders node set.
943      *
944      * @return folders node set
945      */
946     private NodeSet getFoldersNodeSet()
947     {
948         if (foldersNodeSet == null)
949         {
950             if ((folders != null) && !folders.isEmpty())
951             {
952                 foldersNodeSet = new NodeSetImpl(folders, createDocumentOrderComparator());
953             }
954             else
955             {
956                 foldersNodeSet = NodeSetImpl.EMPTY_NODE_SET;
957             }
958         }
959         return foldersNodeSet;
960     }
961     
962     /***
963      * getPagesNodeSet
964      *
965      * Latently create and access pages node set.
966      *
967      * @return folders node set
968      */
969     private NodeSet getPagesNodeSet() throws NodeException
970     {
971         if (pagesNodeSet == null)
972         {
973             if ((pages != null) && !pages.isEmpty())
974             {
975                 pagesNodeSet = new NodeSetImpl(pages, createDocumentOrderComparator());
976             }
977             else
978             {
979                 pagesNodeSet = NodeSetImpl.EMPTY_NODE_SET;
980             }
981         }
982         return pagesNodeSet;
983     }
984     
985     /***
986      * getLinksNodeSet
987      *
988      * Latently create and access links node set.
989      *
990      * @return folders node set
991      */
992     private NodeSet getLinksNodeSet() throws NodeException
993     {
994         if (linksNodeSet == null)
995         {
996             if ((links != null) && !links.isEmpty())
997             {
998                 linksNodeSet = new NodeSetImpl(links, createDocumentOrderComparator());
999             }
1000             else
1001             {
1002                 linksNodeSet = NodeSetImpl.EMPTY_NODE_SET;
1003             }
1004         }
1005         return linksNodeSet;
1006     }
1007     
1008     /***
1009      * getAllNodeSet
1010      *
1011      * Latently create and access all nodes node set.
1012      *
1013      * @return all nodes node set
1014      */
1015     private NodeSet getAllNodeSet()
1016     {
1017         if (allNodeSet == null)
1018         {
1019             if ((all != null) && !all.isEmpty())
1020             {
1021                 List allCopy = new java.util.ArrayList();
1022                 synchronized(all)
1023                 {
1024                     allCopy.addAll(all); 
1025                 }
1026                 allNodeSet = new NodeSetImpl(allCopy, createDocumentOrderComparator());
1027             }
1028             else
1029             {
1030                 allNodeSet = NodeSetImpl.EMPTY_NODE_SET;
1031             }
1032         }
1033         return allNodeSet;
1034     }
1035 
1036     /***
1037      * filterNodeSetByAccess
1038      *
1039      * Filter node set elements for view access.
1040      *
1041      * @param nodes node set containing nodes to check
1042      * @return checked subset of nodes
1043      */
1044     static NodeSet filterNodeSetByAccess(NodeSet nodes)
1045     {
1046         if ((nodes != null) && !nodes.isEmpty())
1047         {
1048             // check permissions and constraints, filter nodes as required
1049             NodeSetImpl filteredNodes = null;
1050             Iterator checkAccessIter = nodes.iterator();
1051             while (checkAccessIter.hasNext())
1052             {
1053                 Node node = (Node)checkAccessIter.next();
1054                 try
1055                 {
1056                     // check access
1057                     node.checkAccess(JetspeedActions.VIEW);
1058 
1059                     // add to filteredNodes nodes if copying
1060                     if (filteredNodes != null)
1061                     {
1062                         // permitted, add to filteredNodes nodes
1063                         filteredNodes.add(node);
1064                     }
1065                 }
1066                 catch (SecurityException se)
1067                 {
1068                     // create filteredNodes nodes if not already copying
1069                     if (filteredNodes == null)
1070                     {
1071                         // not permitted, copy previously permitted nodes
1072                         // to new filteredNodes node set with same comparator
1073                         filteredNodes = new NodeSetImpl(nodes);
1074                         Iterator copyIter = nodes.iterator();
1075                         while (copyIter.hasNext())
1076                         {
1077                             Node copyNode = (Node)copyIter.next();
1078                             if (copyNode != node)
1079                             {
1080                                 filteredNodes.add(copyNode);
1081                             }
1082                             else
1083                             {
1084                                 break;
1085                             }
1086                         }
1087                     }
1088                 }
1089             }
1090 
1091             // return filteredNodes nodes if generated
1092             if (filteredNodes != null)
1093             {
1094                 return filteredNodes;
1095             }
1096         }
1097         return nodes;
1098     }
1099 }