001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.jetspeed.om.folder.proxy;
018:
019: import java.lang.reflect.InvocationHandler;
020: import java.lang.reflect.Method;
021: import java.lang.reflect.Proxy;
022: import java.util.ArrayList;
023: import java.util.Collections;
024: import java.util.Comparator;
025: import java.util.Iterator;
026: import java.util.List;
027: import java.util.Locale;
028:
029: import org.apache.jetspeed.Jetspeed;
030: import org.apache.jetspeed.PortalReservedParameters;
031: import org.apache.jetspeed.om.common.GenericMetadata;
032: import org.apache.jetspeed.om.folder.Folder;
033: import org.apache.jetspeed.om.folder.FolderNotFoundException;
034: import org.apache.jetspeed.om.page.Link;
035: import org.apache.jetspeed.om.page.Page;
036: import org.apache.jetspeed.om.page.proxy.LinkProxy;
037: import org.apache.jetspeed.om.page.proxy.PageProxy;
038: import org.apache.jetspeed.page.PageNotFoundException;
039: import org.apache.jetspeed.page.document.DocumentException;
040: import org.apache.jetspeed.page.document.DocumentNotFoundException;
041: import org.apache.jetspeed.page.document.Node;
042: import org.apache.jetspeed.page.document.NodeException;
043: import org.apache.jetspeed.page.document.NodeNotFoundException;
044: import org.apache.jetspeed.page.document.NodeSet;
045: import org.apache.jetspeed.page.document.proxy.NodeProxy;
046: import org.apache.jetspeed.page.document.proxy.NodeSetImpl;
047: import org.apache.jetspeed.portalsite.view.SiteView;
048: import org.apache.jetspeed.portalsite.view.SiteViewSearchPath;
049: import org.apache.jetspeed.request.RequestContext;
050:
051: /**
052: * This class proxies PSML Folder instances to create a logical view
053: * of site content using the Dynamic Proxy pattern.
054: *
055: * @author <a href="mailto:rwatler@apache.org">Randy Watler</a>
056: * @version $Id: FolderProxy.java 553375 2007-07-05 05:37:00Z taylor $
057: */
058: public class FolderProxy extends NodeProxy implements InvocationHandler {
059: /**
060: * *_METHOD - Folder method constants
061: */
062: protected static final Method GET_ALL_METHOD = reflectMethod(
063: Folder.class, "getAll", null);
064: protected static final Method GET_DEFAULT_PAGE_METHOD = reflectMethod(
065: Folder.class, "getDefaultPage", null);
066: protected static final Method GET_FOLDERS_METHOD = reflectMethod(
067: Folder.class, "getFolders", null);
068: protected static final Method GET_FOLDER_METHOD = reflectMethod(
069: Folder.class, "getFolder", new Class[] { String.class });
070: protected static final Method GET_LINKS_METHOD = reflectMethod(
071: Folder.class, "getLinks", null);
072: protected static final Method GET_LINK_METHOD = reflectMethod(
073: Folder.class, "getLink", new Class[] { String.class });
074: protected static final Method GET_MENU_DEFINITIONS_METHOD = reflectMethod(
075: Folder.class, "getMenuDefinitions", null);
076: protected static final Method GET_METADATA_METHOD = reflectMethod(
077: Folder.class, "getMetadata", null);
078: protected static final Method GET_NAME_METHOD = reflectMethod(
079: Folder.class, "getName", null);
080: protected static final Method GET_PAGES_METHOD = reflectMethod(
081: Folder.class, "getPages", null);
082: protected static final Method GET_PAGE_METHOD = reflectMethod(
083: Folder.class, "getPage", new Class[] { String.class });
084: protected static final Method GET_PAGE_SECURITY_METHOD = reflectMethod(
085: Folder.class, "getPageSecurity", null);
086: protected static final Method GET_SHORT_TITLE_LOCALE_METHOD = reflectMethod(
087: Folder.class, "getShortTitle", new Class[] { Locale.class });
088: protected static final Method GET_SHORT_TITLE_METHOD = reflectMethod(
089: Folder.class, "getShortTitle", null);
090: protected static final Method GET_TITLE_LOCALE_METHOD = reflectMethod(
091: Folder.class, "getTitle", new Class[] { Locale.class });
092: protected static final Method GET_TITLE_METHOD = reflectMethod(
093: Folder.class, "getTitle", null);
094:
095: /**
096: * defaultFolder - default proxy delegate folder instance
097: */
098: private Folder defaultFolder;
099:
100: /**
101: * titledFolder - titled proxy delegate folder instance
102: */
103: private Folder titledFolder;
104:
105: /**
106: * children - aggregated proxy sub-folder, page, and link nodes
107: */
108: private NodeSet children;
109:
110: /**
111: * childrenAggregated - boolean flag to indicate children aggregated
112: */
113: private boolean childrenAggregated;
114:
115: /**
116: * folders - aggregated proxy sub-folder nodes
117: */
118: private NodeSet folders;
119:
120: /**
121: * foldersAggregated - boolean flag to indicate folders aggregated
122: */
123: private boolean foldersAggregated;
124:
125: /**
126: * pages - aggregated proxy page nodes
127: */
128: private NodeSet pages;
129:
130: /**
131: * pagesAggregated - boolean flag to indicate pages aggregated
132: */
133: private boolean pagesAggregated;
134:
135: /**
136: * links - aggregated proxy link nodes
137: */
138: private NodeSet links;
139:
140: /**
141: * linksAggregated - boolean flag to indicate links aggregated
142: */
143: private boolean linksAggregated;
144:
145: /**
146: * SearchFolder - data object used hold concrete search folder and
147: * related search path profile locator name pairs
148: */
149: private class SearchFolder {
150: public Folder folder;
151: public String locatorName;
152:
153: public SearchFolder(Folder folder, String locatorName) {
154: this .folder = folder;
155: this .locatorName = locatorName;
156: }
157: }
158:
159: /**
160: * searchFolders - search folder objects along view search paths
161: * in most to least specific order
162: */
163: private List searchFolders;
164:
165: /**
166: * inheritanceFolders - inheritance graph folder list in most to
167: * least specific order
168: */
169: private List inheritanceFolders;
170:
171: /**
172: * newInstance - creates a new proxy instance that implements the Folder interface
173: *
174: * @param view site view owner of this proxy
175: * @param locatorName name of profile locator associated
176: * with the proxy delegate
177: * @param parentFolder view parent proxy folder
178: * @param folder proxy delegate
179: */
180: public static Folder newInstance(SiteView view, String locatorName,
181: Folder parentFolder, Folder folder) {
182: return (Folder) Proxy
183: .newProxyInstance(folder.getClass().getClassLoader(),
184: new Class[] { Folder.class },
185: new FolderProxy(view, locatorName,
186: parentFolder, folder));
187: }
188:
189: /**
190: * FolderProxy - private constructor used by newInstance()
191: *
192: * @param view site view owner of this proxy
193: * @param locatorName name of profile locator associated
194: * with the proxy delegate
195: * @param parentFolder view parent proxy folder
196: * @param folder proxy delegate
197: */
198: private FolderProxy(SiteView view, String locatorName,
199: Folder parentFolder, Folder folder) {
200: super (view, locatorName, parentFolder, folder.getName(), folder
201: .isHidden());
202: this .defaultFolder = selectDefaultFromAggregateFolders(folder);
203: this .titledFolder = selectTitledFromAggregateFolders(this .defaultFolder);
204: }
205:
206: /**
207: * invoke - method invocation dispatch for this proxy, (defaults to
208: * invocation of delegate unless method is implemented in this
209: * proxy handler or should be hidden/stubbed)
210: *
211: * @param proxy instance invoked against
212: * @param method Folder interface method invoked
213: * @param args method arguments
214: * @throws Throwable
215: */
216: public Object invoke(Object proxy, Method m, Object[] args)
217: throws Throwable {
218: // proxy implementation method dispatch
219: if (m.equals(GET_ALL_METHOD)) {
220: return getAll(proxy);
221: } else if (m.equals(GET_DEFAULT_PAGE_METHOD)) {
222: return getDefaultPage(proxy);
223: } else if (m.equals(GET_FOLDERS_METHOD)) {
224: return getFolders(proxy);
225: } else if (m.equals(GET_FOLDER_METHOD)) {
226: return getFolder(proxy, (String) args[0]);
227: } else if (m.equals(GET_LINKS_METHOD)) {
228: return getLinks(proxy);
229: } else if (m.equals(GET_LINK_METHOD)) {
230: return getLink(proxy, (String) args[0]);
231: } else if (m.equals(GET_MENU_DEFINITIONS_METHOD)) {
232: return getMenuDefinitions();
233: } else if (m.equals(GET_METADATA_METHOD)) {
234: return getMetadata();
235: } else if (m.equals(GET_NAME_METHOD)) {
236: return getName();
237: } else if (m.equals(GET_PAGES_METHOD)) {
238: return getPages(proxy);
239: } else if (m.equals(GET_PAGE_METHOD)) {
240: return getPage(proxy, (String) args[0]);
241: } else if (m.equals(GET_SHORT_TITLE_LOCALE_METHOD)) {
242: return getShortTitle((Locale) args[0]);
243: } else if (m.equals(GET_SHORT_TITLE_METHOD)) {
244: return getShortTitle();
245: } else if (m.equals(GET_TITLE_LOCALE_METHOD)) {
246: return getTitle((Locale) args[0]);
247: } else if (m.equals(GET_TITLE_METHOD)) {
248: return getTitle();
249: } else if (m.equals(GET_PARENT_METHOD)) {
250: return getParent();
251: } else if (m.equals(GET_PATH_METHOD)) {
252: return getPath();
253: } else if (m.equals(GET_URL_METHOD)) {
254: return getUrl();
255: } else if (m.equals(EQUALS_METHOD)) {
256: return new Boolean(equals(args[0]));
257: } else if (m.equals(HASH_CODE_METHOD)) {
258: return new Integer(hashCode());
259: } else if (m.equals(IS_HIDDEN_METHOD)) {
260: return new Boolean(isHidden());
261: } else if (m.equals(TO_STRING_METHOD)) {
262: return toString();
263: }
264:
265: // proxy suppression of not implemented or mutable methods
266: if (m.equals(GET_PAGE_SECURITY_METHOD)
267: || m.getName().startsWith("set")) {
268: throw new RuntimeException(
269: "Folder instance is immutable from proxy.");
270: }
271:
272: // attempt to invoke method on delegate Folder instance
273: return m.invoke(defaultFolder, args);
274: }
275:
276: /**
277: * getAll - proxy implementation of Folder.getAll()
278: *
279: * @param proxy this folder proxy
280: * @return list containing sub-folders and documents in folder
281: * @throws DocumentException
282: */
283: public NodeSet getAll(Object proxy) throws DocumentException {
284: // latently aggregate all children
285: if (!childrenAggregated) {
286: children = aggregateChildren(proxy);
287: childrenAggregated = true;
288: }
289: return children;
290: }
291:
292: /**
293: * getDefaultPage - proxy implementation of Folder.getDefaultPage()
294: *
295: * @param proxy this folder proxy
296: * @return default page name
297: */
298: public String getDefaultPage(Object proxy) {
299: // attempt to get explicitly specified default page
300: return selectDefaultPageFromAggregateFolders(proxy);
301: }
302:
303: /**
304: * getFolders - proxy implementation of Folder.getFolders()
305: *
306: * @param proxy this folder proxy
307: * @return list containing all sub-folders in folder
308: * @throws DocumentException
309: */
310: public NodeSet getFolders(Object proxy) throws DocumentException {
311: // latently subset folders by type from aggregated children
312: if (!foldersAggregated) {
313: NodeSet allChildren = getAll(proxy);
314: if (allChildren != null) {
315: folders = allChildren.subset(Folder.FOLDER_TYPE);
316: }
317: foldersAggregated = true;
318: }
319: return folders;
320: }
321:
322: /**
323: * getFolder - proxy implementation of Folder.getFolder()
324: *
325: * @param proxy this folder proxy
326: * @param name sub-folder name
327: * @return sub-folder
328: * @throws FolderNotFoundException
329: * @throws DocumentException
330: */
331: public Folder getFolder(Object proxy, String name)
332: throws FolderNotFoundException, DocumentException {
333: // search for folder by name or absolute path from
334: // aggregated folders
335: NodeSet allFolders = getFolders(proxy);
336: if (allFolders != null) {
337: Folder folder = (Folder) allFolders.get(name);
338: if (folder != null) {
339: return folder;
340: }
341: }
342: throw new FolderNotFoundException("Folder " + name
343: + " not found at " + getPath());
344: }
345:
346: /**
347: * getLinks - proxy implementation of Folder.getLinks()
348: *
349: * @param proxy this folder proxy
350: * @return list containing all links in folder
351: * @throws NodeException
352: */
353: public NodeSet getLinks(Object proxy) throws NodeException {
354: // latently subset links by type from aggregated children
355: if (!linksAggregated) {
356: NodeSet allChildren = getAll(proxy);
357: if (allChildren != null) {
358: links = allChildren.subset(Link.DOCUMENT_TYPE);
359: }
360: linksAggregated = true;
361: }
362: return links;
363: }
364:
365: /**
366: * getLink - proxy implementation of Folder.getLink()
367: *
368: * @param proxy this folder proxy
369: * @param name link name including extension
370: * @return link
371: * @throws DocumentNotFoundException
372: * @throws NodeException
373: */
374: public Link getLink(Object proxy, String name)
375: throws DocumentNotFoundException, NodeException {
376: // search for link by name or absolute path from
377: // aggregated links
378: NodeSet allLinks = getLinks(proxy);
379: if (allLinks != null) {
380: Link link = (Link) allLinks.get(name);
381: if (link != null) {
382: return link;
383: }
384: }
385: throw new DocumentNotFoundException("Link " + name
386: + " not found at " + getPath());
387: }
388:
389: /**
390: * getName - proxy implementation of Node.getName()
391: *
392: * @return name of folder
393: */
394: public String getName() {
395: // force root folder name since the folder is
396: // normally aggregated using more specific folders;
397: // otherwise, use concrete default folder name
398: if (getPath().equals(Folder.PATH_SEPARATOR)) {
399: return Folder.PATH_SEPARATOR;
400: }
401: return defaultFolder.getName();
402: }
403:
404: /**
405: * getPages - proxy implementation of Folder.getPages()
406: *
407: * @param proxy this folder proxy
408: * @return list containing all pages in folder
409: * @throws NodeException
410: */
411: public NodeSet getPages(Object proxy) throws NodeException {
412: // latently subset pages by type from aggregated children
413: if (!pagesAggregated) {
414: NodeSet allChildren = getAll(proxy);
415: if (allChildren != null) {
416: pages = allChildren.subset(Page.DOCUMENT_TYPE);
417: }
418: pagesAggregated = true;
419: }
420: return pages;
421: }
422:
423: /**
424: * getPage - proxy implementation of Folder.getPage()
425: *
426: * @param proxy this folder proxy
427: * @param name page name including extension
428: * @return page
429: * @throws PageNotFoundException
430: * @throws NodeException
431: */
432: public Page getPage(Object proxy, String name)
433: throws PageNotFoundException, NodeException {
434: // search for page by name or absolute path from
435: // aggregated pages
436: NodeSet allPages = getPages(proxy);
437: if (allPages != null) {
438: Page page = (Page) allPages.get(name);
439: if (page != null) {
440: return page;
441: }
442: }
443: throw new PageNotFoundException("Page " + name
444: + " not found at " + getPath());
445: }
446:
447: /**
448: * getMetadata - proxy implementation of Folder.getMetadata()
449: *
450: * @return metadata
451: */
452: public GenericMetadata getMetadata() {
453: // return titled concrete folder metadata
454: return titledFolder.getMetadata();
455: }
456:
457: /**
458: * getTitle - proxy implementation of Folder.getTitle()
459: *
460: * @return default title
461: */
462: public String getTitle() {
463: // return titled concrete folder title
464: return titledFolder.getTitle();
465: }
466:
467: /**
468: * getShortTitle - proxy implementation of Folder.getShortTitle()
469: *
470: * @return default short title
471: */
472: public String getShortTitle() {
473: // return titled concrete folder short title
474: return titledFolder.getShortTitle();
475: }
476:
477: /**
478: * getTitle - proxy implementation of Folder.getTitle()
479: *
480: * @param locale preferred locale
481: * @return title
482: */
483: public String getTitle(Locale locale) {
484: // return titled concrete folder title
485: return titledFolder.getTitle(locale);
486: }
487:
488: /**
489: * getShortTitle - proxy implementation of Folder.getShortTitle()
490: *
491: * @param locale preferred locale
492: * @return short title
493: */
494: public String getShortTitle(Locale locale) {
495: // return titled concrete folder short title
496: return titledFolder.getShortTitle(locale);
497: }
498:
499: /**
500: * getDefaultFolder - get default proxy delegate folder instance
501: *
502: * @return default delegate folder
503: */
504: public Folder getDefaultFolder() {
505: return defaultFolder;
506: }
507:
508: /**
509: * aggregateMenuDefinitionLocators - aggregate all menu definition locators
510: * in site view for this folder or page
511: */
512: protected void aggregateMenuDefinitionLocators() {
513: // aggregate folder menu definition locators from most to least
514: // specific along inheritance folder graph by name
515: try {
516: Iterator foldersIter = getInheritanceFolders().iterator();
517: while (foldersIter.hasNext()) {
518: // get menu definitions from inheritance folders and
519: // merge into aggregate menu definition locators
520: Folder folder = (Folder) foldersIter.next();
521: mergeMenuDefinitionLocators(
522: folder.getMenuDefinitions(), folder);
523: }
524: } catch (FolderNotFoundException fnfe) {
525: }
526:
527: // aggregate standard menu definition locator defaults
528: mergeMenuDefinitionLocators(getView()
529: .getStandardMenuDefinitionLocators());
530: }
531:
532: /**
533: * selectDefaultFromAggregateFolders - select most appropriate aggregate concrete
534: * folder to use generally in site view at
535: * this proxy folder view path
536: *
537: *
538: * @param defaultFolder default concrete folder
539: * @return selected concrete folder
540: */
541: private Folder selectDefaultFromAggregateFolders(
542: Folder defaultFolder) {
543: // select most specific folder, (i.e. first) along
544: // search paths ordered most to least specific
545: try {
546: return ((SearchFolder) getSearchFolders().get(0)).folder;
547: } catch (FolderNotFoundException fnfe) {
548: }
549: return defaultFolder;
550: }
551:
552: /**
553: * selectTitledFromAggregateFolders - select most appropriate aggregate concrete
554: * folder with a title to use in site view at
555: * this proxy folder view path
556: *
557: * @param defaultFolder default concrete folder
558: * @return selected concrete folder
559: */
560: private Folder selectTitledFromAggregateFolders(Folder defaultFolder) {
561: // select most specific folder along search paths
562: // with a specified title, short title, or metadata
563: try {
564: Iterator foldersIter = getSearchFolders().iterator();
565: while (foldersIter.hasNext()) {
566: Folder folder = ((SearchFolder) foldersIter.next()).folder;
567: String name = folder.getName();
568: String title = folder.getTitle();
569: String shortTitle = folder.getShortTitle();
570: GenericMetadata folderMetadata = folder.getMetadata();
571: if (((title != null) && !title.equalsIgnoreCase(name))
572: || ((shortTitle != null) && !shortTitle
573: .equalsIgnoreCase(name))
574: || ((folderMetadata != null)
575: && (folderMetadata.getFields() != null) && !folderMetadata
576: .getFields().isEmpty())) {
577: return folder;
578: }
579: }
580: } catch (FolderNotFoundException fnfe) {
581: }
582: return defaultFolder;
583: }
584:
585: /**
586: * selectDefaultPageFromAggregateFolders - select most specific default page
587: * proxy to use in site view at this
588: * proxy folder view path
589: *
590: * @param proxy this folder proxy
591: * @return selected default page name
592: */
593: private String selectDefaultPageFromAggregateFolders(Object proxy) {
594: // select most specific specified default page
595: // along search paths
596: try {
597: // only test for fallback default page once
598: boolean fallbackDefaultPageNotFound = false;
599: Iterator foldersIter = getSearchFolders().iterator();
600: while (foldersIter.hasNext()) {
601: // get folder default page name or look for fallback default name
602: Folder folder = ((SearchFolder) foldersIter.next()).folder;
603: String defaultPageName = folder.getDefaultPage();
604: if (defaultPageName != null) {
605: // validate and return default page or folder
606: // if it exists as child in this folder
607: if (defaultPageName.equals("..")) {
608: // default parent folder
609: if (getParent() != null) {
610: return defaultPageName;
611: }
612: } else {
613: // default page
614: try {
615: getPage(proxy, defaultPageName);
616: return defaultPageName;
617: } catch (NodeException ne) {
618: } catch (NodeNotFoundException nnfe) {
619: } catch (SecurityException se) {
620: }
621: // default folder
622: if (!defaultPageName
623: .endsWith(Page.DOCUMENT_TYPE)) {
624: try {
625: getFolder(proxy, defaultPageName);
626: return defaultPageName;
627: } catch (NodeException ne) {
628: } catch (NodeNotFoundException nnfe) {
629: } catch (SecurityException se) {
630: }
631: }
632: }
633: } else if (!fallbackDefaultPageNotFound) {
634: // validate and return fallback default page if
635: // it exists as child in this folder
636: try {
637: getPage(proxy, Folder.FALLBACK_DEFAULT_PAGE);
638: return Folder.FALLBACK_DEFAULT_PAGE;
639: } catch (NodeException ne) {
640: fallbackDefaultPageNotFound = true;
641: } catch (NodeNotFoundException nnfe) {
642: fallbackDefaultPageNotFound = true;
643: } catch (SecurityException se) {
644: fallbackDefaultPageNotFound = true;
645: }
646: }
647: }
648: } catch (FolderNotFoundException fnfe) {
649: }
650: return null;
651: }
652:
653: /**
654: * aggregateChildren - aggregate all children proxies in site view
655: *
656: * @param proxy this folder proxy
657: * @return list containing sub-folders, pages, and links in folder view
658: */
659: private NodeSet aggregateChildren(Object proxy) {
660: // extract all children and document ordering information
661: // from aggregate folders
662: try {
663: // get children proxies
664: List allChildren = new ArrayList();
665: List folderDocumentOrder = null;
666: Iterator foldersIter = getSearchFolders().iterator();
667: while (foldersIter.hasNext()) {
668: // aggregate folders
669: SearchFolder searchFolder = (SearchFolder) foldersIter
670: .next();
671: Folder folder = searchFolder.folder;
672: String locatorName = searchFolder.locatorName;
673:
674: // create and save proxies for concrete children
675: NodeSet children = folder.getAll();
676: Iterator childrenIter = children.iterator();
677: while (childrenIter.hasNext()) {
678: Node child = (Node) childrenIter.next();
679: String childName = child.getName();
680:
681: // filter profiling property folders; they are
682: // accessed only via SiteView search path
683: // aggregation that directly utilizes the
684: // current view page manager
685: boolean visible = (!(child instanceof Folder) || (!childName
686: .startsWith(Folder.RESERVED_SUBSITE_FOLDER_PREFIX) && !childName
687: .startsWith(Folder.RESERVED_FOLDER_PREFIX)));
688: RequestContext rc = Jetspeed
689: .getCurrentRequestContext();
690: boolean configureMode = false;
691: if (rc != null) {
692: if (rc
693: .getPipeline()
694: .getName()
695: .equals(
696: PortalReservedParameters.CONFIG_PIPELINE_NAME)
697: || rc
698: .getPipeline()
699: .getName()
700: .equals(
701: PortalReservedParameters.DESKTOP_CONFIG_PIPELINE_NAME)) {
702: configureMode = true;
703: }
704: }
705:
706: if (visible || configureMode) {
707: // test child name uniqueness
708: boolean childUnique = true;
709: Iterator allChildrenIter = allChildren
710: .iterator();
711: while (childUnique && allChildrenIter.hasNext()) {
712: childUnique = !childName
713: .equals(((Node) allChildrenIter
714: .next()).getName());
715: }
716:
717: // add uniquely named children proxies
718: if (childUnique) {
719: if (child instanceof Folder) {
720: allChildren.add(FolderProxy
721: .newInstance(getView(),
722: locatorName,
723: (Folder) proxy,
724: (Folder) child));
725: } else if (child instanceof Page) {
726: allChildren.add(PageProxy.newInstance(
727: getView(), locatorName,
728: (Folder) proxy, (Page) child));
729: } else if (child instanceof Link) {
730: allChildren.add(LinkProxy.newInstance(
731: getView(), locatorName,
732: (Folder) proxy, (Link) child));
733: }
734: }
735: }
736: }
737:
738: // capture most specific document ordering
739: if (folderDocumentOrder == null) {
740: List documentOrder = folder.getDocumentOrder();
741: if ((documentOrder != null)
742: && !documentOrder.isEmpty()) {
743: folderDocumentOrder = documentOrder;
744: }
745: }
746: }
747:
748: // sort children proxies if more than one by folder
749: // document order or strict collation order
750: if (allChildren.size() > 1) {
751: final List order = folderDocumentOrder;
752: Comparator comparator = new Comparator() {
753: public int compare(Object proxyNode1,
754: Object proxyNode2) {
755: // compare names of nodes against order or each other by default
756: String name1 = ((Node) proxyNode1).getName();
757: String name2 = ((Node) proxyNode2).getName();
758: if (order != null) {
759: // compare names against order
760: int index1 = order.indexOf(name1);
761: int index2 = order.indexOf(name2);
762: if ((index1 != -1) || (index2 != -1)) {
763: if ((index1 == -1) && (index2 != -1)) {
764: return 1;
765: }
766: if ((index1 != -1) && (index2 == -1)) {
767: return -1;
768: }
769: return index1 - index2;
770: }
771: }
772: // compare names against each other
773: return name1.compareTo(name2);
774: }
775: };
776: Collections.sort(allChildren, comparator);
777: }
778:
779: // wrap ordered children in new NodeSet
780: if (!allChildren.isEmpty()) {
781: return new NodeSetImpl(allChildren);
782: }
783: } catch (FolderNotFoundException fnfe) {
784: } catch (DocumentException de) {
785: }
786: return null;
787: }
788:
789: /**
790: * getSearchFolders - aggregate all concrete folders in site view
791: * at this proxy folder view path
792: *
793: * @return list containing concrete search folders in folder view
794: * @throws FolderNotFoundException
795: */
796: private List getSearchFolders() throws FolderNotFoundException {
797: // latently aggregate search folders
798: if (searchFolders == null) {
799: // search for existing folders along search paths
800: List searchPaths = getView().getSearchPaths();
801: searchFolders = new ArrayList(searchPaths.size());
802: Iterator pathsIter = searchPaths.iterator();
803: while (pathsIter.hasNext()) {
804: // construct folder paths
805: SiteViewSearchPath searchPath = (SiteViewSearchPath) pathsIter
806: .next();
807: String path = searchPath.toString();
808: if (!path.equals(Folder.PATH_SEPARATOR)) {
809: path += getPath();
810: } else {
811: path = getPath();
812: }
813:
814: // get existing folders from PageManager, create
815: // corresponding search folder objects, and add to
816: // search folders list
817: try {
818: Folder folder = getView().getPageManager()
819: .getFolder(path);
820: if (folder != null) {
821: searchFolders.add(new SearchFolder(folder,
822: searchPath.getLocatorName()));
823: }
824: } catch (NodeException ne) {
825: } catch (NodeNotFoundException ne) {
826: } catch (SecurityException se) {
827: }
828: }
829: }
830:
831: // return search folders
832: if (!searchFolders.isEmpty()) {
833: return searchFolders;
834: }
835: throw new FolderNotFoundException("Search folders at "
836: + getPath() + " not found or accessible");
837: }
838:
839: /**
840: * getInheritanceFolders - aggregate all concrete inheritance folders
841: * in site view at this proxy folder view path
842: *
843: * @return list containing concrete inheritance folders in folder view
844: * @throws FolderNotFoundException
845: */
846: private List getInheritanceFolders() throws FolderNotFoundException {
847: // latently aggregate inheritance folders
848: if (inheritanceFolders == null) {
849: // inheritance folders are aggregated from super/parent
850: // folder search paths for each proxy folder in the view
851: // path; concatinate all search paths from this proxy
852: // folder to the proxy root to create the inheritance
853: // graph folder list
854: FolderProxy folder = this ;
855: List searchFolders = folder.getSearchFolders();
856: if (getParent() != null) {
857: inheritanceFolders = new ArrayList(
858: searchFolders.size() * 2);
859: } else {
860: inheritanceFolders = new ArrayList(searchFolders.size());
861: }
862: do {
863: // copy ordered search path folders into inheritance
864: // graph folders list
865: Iterator foldersIter = searchFolders.iterator();
866: while (foldersIter.hasNext()) {
867: inheritanceFolders.add(((SearchFolder) foldersIter
868: .next()).folder);
869: }
870:
871: // get super/parent search paths
872: folder = (FolderProxy) getNodeProxy(folder.getParent());
873: if (folder != null) {
874: searchFolders = folder.getSearchFolders();
875: }
876: } while (folder != null);
877: }
878:
879: // return inheritance folders
880: if (!inheritanceFolders.isEmpty()) {
881: return inheritanceFolders;
882: }
883: throw new FolderNotFoundException("Inheritance folders at "
884: + getPath() + " not found or accessible");
885: }
886: }
|