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.proxy;
18  
19  import java.lang.reflect.InvocationHandler;
20  import java.lang.reflect.Method;
21  import java.lang.reflect.Proxy;
22  import java.util.ArrayList;
23  import java.util.Collections;
24  import java.util.Comparator;
25  import java.util.Iterator;
26  import java.util.List;
27  import java.util.Locale;
28  
29  import org.apache.jetspeed.Jetspeed;
30  import org.apache.jetspeed.PortalReservedParameters;
31  import org.apache.jetspeed.om.common.GenericMetadata;
32  import org.apache.jetspeed.om.folder.Folder;
33  import org.apache.jetspeed.om.folder.FolderNotFoundException;
34  import org.apache.jetspeed.om.page.Link;
35  import org.apache.jetspeed.om.page.Page;
36  import org.apache.jetspeed.om.page.proxy.LinkProxy;
37  import org.apache.jetspeed.om.page.proxy.PageProxy;
38  import org.apache.jetspeed.page.PageNotFoundException;
39  import org.apache.jetspeed.page.document.DocumentException;
40  import org.apache.jetspeed.page.document.DocumentNotFoundException;
41  import org.apache.jetspeed.page.document.Node;
42  import org.apache.jetspeed.page.document.NodeException;
43  import org.apache.jetspeed.page.document.NodeNotFoundException;
44  import org.apache.jetspeed.page.document.NodeSet;
45  import org.apache.jetspeed.page.document.proxy.NodeProxy;
46  import org.apache.jetspeed.page.document.proxy.NodeSetImpl;
47  import org.apache.jetspeed.portalsite.view.SiteView;
48  import org.apache.jetspeed.portalsite.view.SiteViewSearchPath;
49  import org.apache.jetspeed.request.RequestContext;
50  
51  /***
52   * This class proxies PSML Folder instances to create a logical view
53   * of site content using the Dynamic Proxy pattern.
54   * 
55   * @author <a href="mailto:rwatler@apache.org">Randy Watler</a>
56   * @version $Id: FolderProxy.java 553375 2007-07-05 05:37:00Z taylor $
57   */
58  public class FolderProxy extends NodeProxy implements InvocationHandler
59  {
60      /***
61       * *_METHOD - Folder method constants
62       */
63      protected static final Method GET_ALL_METHOD = reflectMethod(Folder.class, "getAll", null);
64      protected static final Method GET_DEFAULT_PAGE_METHOD = reflectMethod(Folder.class, "getDefaultPage", null);
65      protected static final Method GET_FOLDERS_METHOD = reflectMethod(Folder.class, "getFolders", null);
66      protected static final Method GET_FOLDER_METHOD = reflectMethod(Folder.class, "getFolder", new Class[]{String.class});
67      protected static final Method GET_LINKS_METHOD = reflectMethod(Folder.class, "getLinks", null);
68      protected static final Method GET_LINK_METHOD = reflectMethod(Folder.class, "getLink", new Class[]{String.class});
69      protected static final Method GET_MENU_DEFINITIONS_METHOD = reflectMethod(Folder.class, "getMenuDefinitions", null);
70      protected static final Method GET_METADATA_METHOD = reflectMethod(Folder.class, "getMetadata", null);
71      protected static final Method GET_NAME_METHOD = reflectMethod(Folder.class, "getName", null);
72      protected static final Method GET_PAGES_METHOD = reflectMethod(Folder.class, "getPages", null);
73      protected static final Method GET_PAGE_METHOD = reflectMethod(Folder.class, "getPage", new Class[]{String.class});
74      protected static final Method GET_PAGE_SECURITY_METHOD = reflectMethod(Folder.class, "getPageSecurity", null);
75      protected static final Method GET_SHORT_TITLE_LOCALE_METHOD = reflectMethod(Folder.class, "getShortTitle", new Class[]{Locale.class});
76      protected static final Method GET_SHORT_TITLE_METHOD = reflectMethod(Folder.class, "getShortTitle", null);
77      protected static final Method GET_TITLE_LOCALE_METHOD = reflectMethod(Folder.class, "getTitle", new Class[]{Locale.class});
78      protected static final Method GET_TITLE_METHOD = reflectMethod(Folder.class, "getTitle", null);
79  
80      /***
81       * defaultFolder - default proxy delegate folder instance
82       */
83      private Folder defaultFolder;
84  
85      /***
86       * titledFolder - titled proxy delegate folder instance
87       */
88      private Folder titledFolder;
89  
90      /***
91       * children - aggregated proxy sub-folder, page, and link nodes
92       */
93      private NodeSet children;
94  
95      /***
96       * childrenAggregated - boolean flag to indicate children aggregated
97       */
98      private boolean childrenAggregated;
99  
100     /***
101      * folders - aggregated proxy sub-folder nodes
102      */
103     private NodeSet folders;
104 
105     /***
106      * foldersAggregated - boolean flag to indicate folders aggregated
107      */
108     private boolean foldersAggregated;
109 
110     /***
111      * pages - aggregated proxy page nodes
112      */
113     private NodeSet pages;
114 
115     /***
116      * pagesAggregated - boolean flag to indicate pages aggregated
117      */
118     private boolean pagesAggregated;
119 
120     /***
121      * links - aggregated proxy link nodes
122      */
123     private NodeSet links;
124 
125     /***
126      * linksAggregated - boolean flag to indicate links aggregated
127      */
128     private boolean linksAggregated;
129 
130     /***
131      * SearchFolder - data object used hold concrete search folder and
132      *                related search path profile locator name pairs
133      */
134     private class SearchFolder
135     {
136         public Folder folder;
137         public String locatorName;
138 
139         public SearchFolder(Folder folder, String locatorName)
140         {
141             this.folder = folder;
142             this.locatorName = locatorName;
143         }
144     }
145 
146     /***
147      * searchFolders - search folder objects along view search paths
148      *                 in most to least specific order
149      */
150     private List searchFolders;
151 
152     /***
153      * inheritanceFolders - inheritance graph folder list in most to
154      *                      least specific order
155      */
156     private List inheritanceFolders;
157         
158     /***
159      * newInstance - creates a new proxy instance that implements the Folder interface
160      *
161      * @param view site view owner of this proxy
162      * @param locatorName name of profile locator associated
163      *                    with the proxy delegate
164      * @param parentFolder view parent proxy folder
165      * @param folder proxy delegate
166      */
167     public static Folder newInstance(SiteView view, String locatorName, Folder parentFolder, Folder folder)
168     {
169         return (Folder)Proxy.newProxyInstance(folder.getClass().getClassLoader(), new Class[]{Folder.class}, new FolderProxy(view, locatorName, parentFolder, folder));
170     }
171 
172     /***
173      * FolderProxy - private constructor used by newInstance()
174      *
175      * @param view site view owner of this proxy
176      * @param locatorName name of profile locator associated
177      *                    with the proxy delegate
178      * @param parentFolder view parent proxy folder
179      * @param folder proxy delegate
180      */
181     private FolderProxy(SiteView view, String locatorName, Folder parentFolder, Folder folder)
182     {
183         super(view, locatorName, parentFolder, folder.getName(), folder.isHidden());
184         this.defaultFolder = selectDefaultFromAggregateFolders(folder);
185         this.titledFolder = selectTitledFromAggregateFolders(this.defaultFolder);
186     }
187     
188     /***
189      * invoke - method invocation dispatch for this proxy, (defaults to
190      *          invocation of delegate unless method is implemented in this
191      *          proxy handler or should be hidden/stubbed)
192      *
193      * @param proxy instance invoked against
194      * @param method Folder interface method invoked
195      * @param args method arguments
196      * @throws Throwable
197      */
198     public Object invoke(Object proxy, Method m, Object [] args) throws Throwable
199     {
200         // proxy implementation method dispatch
201         if (m.equals(GET_ALL_METHOD))
202         {
203             return getAll(proxy);
204         }
205         else if (m.equals(GET_DEFAULT_PAGE_METHOD))
206         {
207             return getDefaultPage(proxy);
208         }
209         else if (m.equals(GET_FOLDERS_METHOD))
210         {
211             return getFolders(proxy);
212         }
213         else if (m.equals(GET_FOLDER_METHOD))
214         {
215             return getFolder(proxy, (String)args[0]);
216         }
217         else if (m.equals(GET_LINKS_METHOD))
218         {
219             return getLinks(proxy);
220         }
221         else if (m.equals(GET_LINK_METHOD))
222         {
223             return getLink(proxy, (String)args[0]);
224         }
225         else if (m.equals(GET_MENU_DEFINITIONS_METHOD))
226         {
227             return getMenuDefinitions();
228         }
229         else if (m.equals(GET_METADATA_METHOD))
230         {
231             return getMetadata();
232         }
233         else if (m.equals(GET_NAME_METHOD))
234         {
235             return getName();
236         }
237         else if (m.equals(GET_PAGES_METHOD))
238         {
239             return getPages(proxy);
240         }
241         else if (m.equals(GET_PAGE_METHOD))
242         {
243             return getPage(proxy, (String)args[0]);
244         }
245         else if (m.equals(GET_SHORT_TITLE_LOCALE_METHOD))
246         {
247             return getShortTitle((Locale)args[0]);
248         }
249         else if (m.equals(GET_SHORT_TITLE_METHOD))
250         {
251             return getShortTitle();
252         }
253         else if (m.equals(GET_TITLE_LOCALE_METHOD))
254         {
255             return getTitle((Locale)args[0]);
256         }
257         else if (m.equals(GET_TITLE_METHOD))
258         {
259             return getTitle();
260         }
261         else if (m.equals(GET_PARENT_METHOD))
262         {
263             return getParent();
264         }
265         else if (m.equals(GET_PATH_METHOD))
266         {
267             return getPath();
268         }
269         else if (m.equals(GET_URL_METHOD))
270         {
271             return getUrl();
272         }
273         else if (m.equals(EQUALS_METHOD))
274         {
275             return new Boolean(equals(args[0]));
276         }
277         else if (m.equals(HASH_CODE_METHOD))
278         {
279             return new Integer(hashCode());
280         }
281         else if (m.equals(IS_HIDDEN_METHOD))
282         {
283             return new Boolean(isHidden());
284         }
285         else if (m.equals(TO_STRING_METHOD))
286         {
287             return toString();
288         }
289     
290         // proxy suppression of not implemented or mutable methods
291         if (m.equals(GET_PAGE_SECURITY_METHOD) ||
292             m.getName().startsWith("set"))
293         {
294             throw new RuntimeException("Folder instance is immutable from proxy.");
295         }
296 
297         // attempt to invoke method on delegate Folder instance
298         return m.invoke(defaultFolder, args);
299     }
300 
301     /***
302      * getAll - proxy implementation of Folder.getAll()
303      *
304      * @param proxy this folder proxy
305      * @return list containing sub-folders and documents in folder
306      * @throws DocumentException
307      */
308     public NodeSet getAll(Object proxy) throws DocumentException
309     {
310         // latently aggregate all children
311         if (!childrenAggregated)
312         {
313             children = aggregateChildren(proxy);
314             childrenAggregated = true;
315         }
316         return children;
317     }
318 
319     /***
320      * getDefaultPage - proxy implementation of Folder.getDefaultPage()
321      *
322      * @param proxy this folder proxy
323      * @return default page name
324      */
325     public String getDefaultPage(Object proxy)
326     {
327         // attempt to get explicitly specified default page
328         return selectDefaultPageFromAggregateFolders(proxy);
329     }
330 
331     /***
332      * getFolders - proxy implementation of Folder.getFolders()
333      *
334      * @param proxy this folder proxy
335      * @return list containing all sub-folders in folder
336      * @throws DocumentException
337      */
338     public NodeSet getFolders(Object proxy) throws DocumentException
339     {
340         // latently subset folders by type from aggregated children
341         if (!foldersAggregated)
342         {
343             NodeSet allChildren = getAll(proxy);
344             if (allChildren != null)
345             {
346                 folders = allChildren.subset(Folder.FOLDER_TYPE);
347             }
348             foldersAggregated = true;
349         }
350         return folders;
351     }
352     
353     /***
354      * getFolder - proxy implementation of Folder.getFolder()
355      *
356      * @param proxy this folder proxy
357      * @param name sub-folder name
358      * @return sub-folder
359      * @throws FolderNotFoundException
360      * @throws DocumentException
361      */
362     public Folder getFolder(Object proxy, String name) throws FolderNotFoundException, DocumentException
363     {
364         // search for folder by name or absolute path from
365         // aggregated folders
366         NodeSet allFolders = getFolders(proxy);
367         if (allFolders != null)
368         {
369             Folder folder = (Folder)allFolders.get(name);
370             if (folder != null)
371             {
372                 return folder;
373             }
374         }
375         throw new FolderNotFoundException("Folder " + name + " not found at " + getPath());
376     }
377 
378     /***
379      * getLinks - proxy implementation of Folder.getLinks()
380      *
381      * @param proxy this folder proxy
382      * @return list containing all links in folder
383      * @throws NodeException
384      */    
385     public NodeSet getLinks(Object proxy) throws NodeException
386     {
387         // latently subset links by type from aggregated children
388         if (!linksAggregated)
389         {
390             NodeSet allChildren = getAll(proxy);
391             if (allChildren != null)
392             {
393                 links = allChildren.subset(Link.DOCUMENT_TYPE);
394             }
395             linksAggregated = true;
396         }
397         return links;
398     }
399     
400     /***
401      * getLink - proxy implementation of Folder.getLink()
402      *
403      * @param proxy this folder proxy
404      * @param name link name including extension
405      * @return link
406      * @throws DocumentNotFoundException
407      * @throws NodeException
408      */    
409     public Link getLink(Object proxy, String name) throws DocumentNotFoundException, NodeException
410     {
411         // search for link by name or absolute path from
412         // aggregated links
413         NodeSet allLinks = getLinks(proxy);
414         if (allLinks != null)
415         {
416             Link link = (Link)allLinks.get(name);
417             if (link != null)
418             {
419                 return link;
420             }
421         }
422         throw new DocumentNotFoundException("Link " + name + " not found at " + getPath());
423     }
424 
425     /***
426      * getName - proxy implementation of Node.getName()
427      *
428      * @return name of folder
429      */
430     public String getName()
431     {
432         // force root folder name since the folder is
433         // normally aggregated using more specific folders;
434         // otherwise, use concrete default folder name
435         if (getPath().equals(Folder.PATH_SEPARATOR))
436         {
437             return Folder.PATH_SEPARATOR;
438         }
439         return defaultFolder.getName();
440     }
441 
442     /***
443      * getPages - proxy implementation of Folder.getPages()
444      *
445      * @param proxy this folder proxy
446      * @return list containing all pages in folder
447      * @throws NodeException
448      */
449     public NodeSet getPages(Object proxy) throws NodeException
450     {
451         // latently subset pages by type from aggregated children
452         if (!pagesAggregated)
453         {
454             NodeSet allChildren = getAll(proxy);
455             if (allChildren != null)
456             {
457                 pages = allChildren.subset(Page.DOCUMENT_TYPE);
458             }
459             pagesAggregated = true;
460         }
461         return pages;
462     }
463     
464     /***
465      * getPage - proxy implementation of Folder.getPage()
466      *
467      * @param proxy this folder proxy
468      * @param name page name including extension
469      * @return page
470      * @throws PageNotFoundException
471      * @throws NodeException
472      */
473     public Page getPage(Object proxy, String name) throws PageNotFoundException, NodeException
474     {
475         // search for page by name or absolute path from
476         // aggregated pages
477         NodeSet allPages = getPages(proxy);
478         if (allPages != null)
479         {
480             Page page = (Page)allPages.get(name);
481             if (page != null)
482             {
483                 return page;
484             }
485         }
486         throw new PageNotFoundException("Page " + name + " not found at " + getPath());
487     }
488 
489     /***
490      * getMetadata - proxy implementation of Folder.getMetadata()
491      *
492      * @return metadata
493      */
494     public GenericMetadata getMetadata()
495     {
496         // return titled concrete folder metadata
497         return titledFolder.getMetadata();
498     }
499 
500     /***
501      * getTitle - proxy implementation of Folder.getTitle()
502      *
503      * @return default title
504      */
505     public String getTitle()
506     {
507         // return titled concrete folder title
508         return titledFolder.getTitle();
509     }
510 
511     /***
512      * getShortTitle - proxy implementation of Folder.getShortTitle()
513      *
514      * @return default short title
515      */
516     public String getShortTitle()
517     {
518         // return titled concrete folder short title
519         return titledFolder.getShortTitle();
520     }
521 
522     /***
523      * getTitle - proxy implementation of Folder.getTitle()
524      *
525      * @param locale preferred locale
526      * @return title
527      */
528     public String getTitle(Locale locale)
529     {
530         // return titled concrete folder title
531         return titledFolder.getTitle(locale);
532     }
533 
534     /***
535      * getShortTitle - proxy implementation of Folder.getShortTitle()
536      *
537      * @param locale preferred locale
538      * @return short title
539      */
540     public String getShortTitle(Locale locale)
541     {
542         // return titled concrete folder short title
543         return titledFolder.getShortTitle(locale);
544     }
545 
546     /***
547      * getDefaultFolder - get default proxy delegate folder instance
548      *
549      * @return default delegate folder
550      */
551     public Folder getDefaultFolder()
552     {
553         return defaultFolder;
554     }
555 
556     /***
557      * aggregateMenuDefinitionLocators - aggregate all menu definition locators
558      *                                   in site view for this folder or page
559      */
560     protected void aggregateMenuDefinitionLocators()
561     {
562         // aggregate folder menu definition locators from most to least
563         // specific along inheritance folder graph by name
564         try
565         {
566             Iterator foldersIter = getInheritanceFolders().iterator();
567             while (foldersIter.hasNext())
568             {
569                 // get menu definitions from inheritance folders and
570                 // merge into aggregate menu definition locators
571                 Folder folder = (Folder)foldersIter.next();
572                 mergeMenuDefinitionLocators(folder.getMenuDefinitions(), folder);
573             }
574         }
575         catch (FolderNotFoundException fnfe)
576         {
577         }
578 
579         // aggregate standard menu definition locator defaults
580         mergeMenuDefinitionLocators(getView().getStandardMenuDefinitionLocators());        
581     }
582 
583     /***
584      * selectDefaultFromAggregateFolders - select most appropriate aggregate concrete
585      *                                     folder to use generally in site view at
586      *                                     this proxy folder view path
587      *                                     
588      *
589      * @param defaultFolder default concrete folder
590      * @return selected concrete folder
591      */
592     private Folder selectDefaultFromAggregateFolders(Folder defaultFolder)
593     {
594         // select most specific folder, (i.e. first) along
595         // search paths ordered most to least specific
596         try
597         {
598             return ((SearchFolder)getSearchFolders().get(0)).folder;
599         }
600         catch (FolderNotFoundException fnfe)
601         {
602         }
603         return defaultFolder;
604     }
605 
606     /***
607      * selectTitledFromAggregateFolders - select most appropriate aggregate concrete
608      *                                    folder with a title to use in site view at
609      *                                    this proxy folder view path
610      *
611      * @param defaultFolder default concrete folder
612      * @return selected concrete folder
613      */
614     private Folder selectTitledFromAggregateFolders(Folder defaultFolder)
615     {
616         // select most specific folder along search paths
617         // with a specified title, short title, or metadata
618         try
619         {
620             Iterator foldersIter = getSearchFolders().iterator();
621             while (foldersIter.hasNext())
622             {
623                 Folder folder = ((SearchFolder)foldersIter.next()).folder;
624                 String name = folder.getName();
625                 String title = folder.getTitle();
626                 String shortTitle = folder.getShortTitle();
627                 GenericMetadata folderMetadata = folder.getMetadata();
628                 if (((title != null) && !title.equalsIgnoreCase(name)) ||
629                     ((shortTitle != null) && !shortTitle.equalsIgnoreCase(name)) ||
630                     ((folderMetadata != null) && (folderMetadata.getFields() != null) && !folderMetadata.getFields().isEmpty()))
631                 {
632                     return folder;
633                 }
634             }
635         }
636         catch (FolderNotFoundException fnfe)
637         {
638         }
639         return defaultFolder;
640     }
641 
642     /***
643      * selectDefaultPageFromAggregateFolders - select most specific default page
644      *                                         proxy to use in site view at this
645      *                                         proxy folder view path
646      *
647      * @param proxy this folder proxy
648      * @return selected default page name
649      */
650     private String selectDefaultPageFromAggregateFolders(Object proxy)
651     {
652         // select most specific specified default page
653         // along search paths
654         try
655         {
656             // only test for fallback default page once
657             boolean fallbackDefaultPageNotFound = false;
658             Iterator foldersIter = getSearchFolders().iterator();
659             while (foldersIter.hasNext())
660             {
661                 // get folder default page name or look for fallback default name
662                 Folder folder = ((SearchFolder)foldersIter.next()).folder;
663                 String defaultPageName = folder.getDefaultPage();
664                 if (defaultPageName != null)
665                 {
666                     // validate and return default page or folder
667                     // if it exists as child in this folder
668                     if (defaultPageName.equals(".."))
669                     {
670                         // default parent folder
671                         if (getParent() != null)
672                         {
673                             return defaultPageName;
674                         }
675                     }
676                     else
677                     {
678                         // default page
679                         try
680                         {
681                             getPage(proxy, defaultPageName);
682                             return defaultPageName;
683                         }
684                         catch (NodeException ne)
685                         {
686                         }
687                         catch (NodeNotFoundException nnfe)
688                         {
689                         }
690                         catch (SecurityException se)
691                         {
692                         }
693                         // default folder
694                         if (!defaultPageName.endsWith(Page.DOCUMENT_TYPE))
695                         {
696                             try
697                             {
698                                 getFolder(proxy, defaultPageName);
699                                 return defaultPageName;
700                             }
701                             catch (NodeException ne)
702                             {
703                             }
704                             catch (NodeNotFoundException nnfe)
705                             {
706                             }
707                             catch (SecurityException se)
708                             {
709                             }
710                         }
711                     }
712                 }
713                 else if (!fallbackDefaultPageNotFound)
714                 {
715                     // validate and return fallback default page if
716                     // it exists as child in this folder
717                     try
718                     {
719                         getPage(proxy, Folder.FALLBACK_DEFAULT_PAGE);
720                         return Folder.FALLBACK_DEFAULT_PAGE;
721                     }
722                     catch (NodeException ne)
723                     {
724                         fallbackDefaultPageNotFound = true;
725                     }
726                     catch (NodeNotFoundException nnfe)
727                     {
728                         fallbackDefaultPageNotFound = true;
729                     }
730                     catch (SecurityException se)
731                     {
732                         fallbackDefaultPageNotFound = true;
733                     }
734                 }
735             }
736         }
737         catch (FolderNotFoundException fnfe)
738         {
739         }
740         return null;
741     }
742 
743     /***
744      * aggregateChildren - aggregate all children proxies in site view
745      *
746      * @param proxy this folder proxy
747      * @return list containing sub-folders, pages, and links in folder view
748      */
749     private NodeSet aggregateChildren(Object proxy)
750     {
751         // extract all children and document ordering information
752         // from aggregate folders
753         try
754         {
755             // get children proxies
756             List allChildren = new ArrayList();
757             List folderDocumentOrder = null;
758             Iterator foldersIter = getSearchFolders().iterator();
759             while (foldersIter.hasNext())
760             {
761                 // aggregate folders
762                 SearchFolder searchFolder = (SearchFolder)foldersIter.next();
763                 Folder folder = searchFolder.folder;
764                 String locatorName = searchFolder.locatorName;
765 
766                 // create and save proxies for concrete children
767                 NodeSet children = folder.getAll();
768                 Iterator childrenIter = children.iterator();
769                 while (childrenIter.hasNext())
770                 {
771                     Node child = (Node)childrenIter.next();
772                     String childName = child.getName();
773 
774                     // filter profiling property folders; they are
775                     // accessed only via SiteView search path
776                     // aggregation that directly utilizes the
777                     // current view page manager
778                     boolean visible = (!(child instanceof Folder) || (!childName.startsWith(Folder.RESERVED_SUBSITE_FOLDER_PREFIX) &&
779                                                        !childName.startsWith(Folder.RESERVED_FOLDER_PREFIX)));
780                     RequestContext rc = Jetspeed.getCurrentRequestContext();
781                     boolean configureMode = false;
782                     if (rc != null)
783                     {
784                         if (rc.getPipeline().getName().equals(PortalReservedParameters.CONFIG_PIPELINE_NAME) ||
785                             rc.getPipeline().getName().equals(PortalReservedParameters.DESKTOP_CONFIG_PIPELINE_NAME))    
786                         {
787                             configureMode = true;
788                         }
789                     }
790                     
791                     if (visible || configureMode)
792                     {
793                         // test child name uniqueness
794                         boolean childUnique = true ;
795                         Iterator allChildrenIter = allChildren.iterator();
796                         while (childUnique && allChildrenIter.hasNext())
797                         {
798                             childUnique = !childName.equals(((Node)allChildrenIter.next()).getName());                            
799                         }
800 
801                         // add uniquely named children proxies
802                         if (childUnique)
803                         {
804                             if (child instanceof Folder)
805                             {
806                                 allChildren.add(FolderProxy.newInstance(getView(), locatorName, (Folder)proxy, (Folder)child));
807                             }
808                             else if (child instanceof Page)
809                             {
810                                 allChildren.add(PageProxy.newInstance(getView(), locatorName, (Folder)proxy, (Page)child));
811                             }
812                             else if (child instanceof Link)
813                             {
814                                 allChildren.add(LinkProxy.newInstance(getView(), locatorName, (Folder)proxy, (Link)child));
815                             }
816                         }
817                     }
818                 }
819 
820                 // capture most specific document ordering
821                 if (folderDocumentOrder == null)
822                 {
823                     List documentOrder = folder.getDocumentOrder();
824                     if ((documentOrder != null) && !documentOrder.isEmpty()) 
825                     {
826                         folderDocumentOrder = documentOrder;
827                     }
828                 }
829             }
830 
831             // sort children proxies if more than one by folder
832             // document order or strict collation order
833             if (allChildren.size() > 1)
834             {
835                 final List order = folderDocumentOrder;
836                 Comparator comparator = new Comparator()
837                     {
838                         public int compare(Object proxyNode1, Object proxyNode2)
839                         {
840                             // compare names of nodes against order or each other by default
841                             String name1 = ((Node)proxyNode1).getName();
842                             String name2 = ((Node)proxyNode2).getName();
843                             if (order != null)
844                             {
845                                 // compare names against order
846                                 int index1 = order.indexOf(name1);
847                                 int index2 = order.indexOf(name2);
848                                 if ((index1 != -1) || (index2 != -1))
849                                 {
850                                     if ((index1 == -1) && (index2 != -1))
851                                     {
852                                         return 1;
853                                     }
854                                     if ((index1 != -1) && (index2 == -1))
855                                     {
856                                         return -1;
857                                     }
858                                     return index1-index2;
859                                 }
860                             }
861                             // compare names against each other
862                             return name1.compareTo(name2);
863                         }
864                     } ;
865                 Collections.sort(allChildren, comparator);
866             }
867 
868             // wrap ordered children in new NodeSet
869             if (!allChildren.isEmpty())
870             {
871                 return new NodeSetImpl(allChildren);
872             }
873         }
874         catch (FolderNotFoundException fnfe)
875         {
876         }
877         catch (DocumentException de)
878         {
879         }
880         return null;
881     }
882 
883     /***
884      * getSearchFolders - aggregate all concrete folders in site view
885      *                    at this proxy folder view path
886      *
887      * @return list containing concrete search folders in folder view
888      * @throws FolderNotFoundException
889      */
890     private List getSearchFolders() throws FolderNotFoundException
891     {
892         // latently aggregate search folders
893         if (searchFolders == null)
894         {
895             // search for existing folders along search paths
896             List searchPaths = getView().getSearchPaths();
897             searchFolders = new ArrayList(searchPaths.size());
898             Iterator pathsIter = searchPaths.iterator();
899             while (pathsIter.hasNext())
900             {
901                 // construct folder paths
902                 SiteViewSearchPath searchPath = (SiteViewSearchPath)pathsIter.next();
903                 String path = searchPath.toString();
904                 if (!path.equals(Folder.PATH_SEPARATOR))
905                 {
906                     path += getPath();
907                 }
908                 else
909                 {
910                     path = getPath();
911                 }
912                 
913                 // get existing folders from PageManager, create
914                 // corresponding search folder objects, and add to
915                 // search folders list
916                 try
917                 {
918                     Folder folder = getView().getPageManager().getFolder(path);
919                     if (folder != null)
920                     {
921                         searchFolders.add(new SearchFolder(folder, searchPath.getLocatorName()));
922                     }
923                 }
924                 catch (NodeException ne)
925                 {
926                 }
927                 catch (NodeNotFoundException ne)
928                 {
929                 }
930                 catch (SecurityException se)
931                 {
932                 }
933             }
934         }
935 
936         // return search folders
937         if (!searchFolders.isEmpty())
938         {
939             return searchFolders;
940         }
941         throw new FolderNotFoundException("Search folders at " + getPath() + " not found or accessible");
942     }
943 
944     /***
945      * getInheritanceFolders - aggregate all concrete inheritance folders
946      *                         in site view at this proxy folder view path
947      *
948      * @return list containing concrete inheritance folders in folder view
949      * @throws FolderNotFoundException
950      */
951     private List getInheritanceFolders() throws FolderNotFoundException
952     {
953         // latently aggregate inheritance folders
954         if (inheritanceFolders == null)
955         {
956             // inheritance folders are aggregated from super/parent
957             // folder search paths for each proxy folder in the view
958             // path; concatinate all search paths from this proxy
959             // folder to the proxy root to create the inheritance
960             // graph folder list
961             FolderProxy folder = this;
962             List searchFolders = folder.getSearchFolders();
963             if (getParent() != null)
964             {
965                 inheritanceFolders = new ArrayList(searchFolders.size() * 2);
966             }
967             else
968             {
969                 inheritanceFolders = new ArrayList(searchFolders.size());
970             }        
971             do
972             {
973                 // copy ordered search path folders into inheritance
974                 // graph folders list
975                 Iterator foldersIter = searchFolders.iterator();
976                 while (foldersIter.hasNext())
977                 {
978                     inheritanceFolders.add(((SearchFolder)foldersIter.next()).folder);
979                 }
980 
981                 // get super/parent search paths
982                 folder = (FolderProxy)getNodeProxy(folder.getParent());
983                 if (folder != null)
984                 {
985                     searchFolders = folder.getSearchFolders();
986                 }
987             }
988             while (folder != null);
989         }
990 
991         // return inheritance folders
992         if (!inheritanceFolders.isEmpty())
993         {
994             return inheritanceFolders;
995         }
996         throw new FolderNotFoundException("Inheritance folders at " + getPath() + " not found or accessible");
997     }
998 }