0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017: package org.apache.jetspeed.portalsite.view;
0018:
0019: import java.util.ArrayList;
0020: import java.util.HashSet;
0021: import java.util.Iterator;
0022: import java.util.List;
0023: import java.util.Map;
0024: import java.util.Set;
0025:
0026: import org.apache.jetspeed.om.folder.Folder;
0027: import org.apache.jetspeed.om.folder.FolderNotFoundException;
0028: import org.apache.jetspeed.om.folder.proxy.FolderProxy;
0029: import org.apache.jetspeed.om.page.Page;
0030: import org.apache.jetspeed.om.page.proxy.PageProxy;
0031: import org.apache.jetspeed.page.PageManager;
0032: import org.apache.jetspeed.page.document.Node;
0033: import org.apache.jetspeed.page.document.NodeException;
0034: import org.apache.jetspeed.page.document.NodeNotFoundException;
0035: import org.apache.jetspeed.page.document.NodeSet;
0036: import org.apache.jetspeed.page.document.proxy.NodeProxy;
0037: import org.apache.jetspeed.portalsite.menu.StandardBackMenuDefinition;
0038: import org.apache.jetspeed.portalsite.menu.StandardBreadcrumbsMenuDefinition;
0039: import org.apache.jetspeed.portalsite.menu.StandardNavigationsMenuDefinition;
0040: import org.apache.jetspeed.portalsite.menu.StandardPagesMenuDefinition;
0041: import org.apache.jetspeed.profiler.ProfileLocator;
0042: import org.apache.jetspeed.profiler.ProfileLocatorProperty;
0043:
0044: /**
0045: * This class defines the logical view of site content.
0046: *
0047: * @author <a href="mailto:rwatler@apache.org">Randy Watler</a>
0048: * @version $Id: SiteView.java 534967 2007-05-03 19:23:06Z taylor $
0049: */
0050: public class SiteView {
0051: /**
0052: * CURRENT_PAGE_PATH - expression used to match the current page
0053: */
0054: public final static String CURRENT_PAGE_PATH = "~";
0055:
0056: /**
0057: * ALT_CURRENT_PAGE_PATH - alternate expression used to match the current page
0058: */
0059: public final static String ALT_CURRENT_PAGE_PATH = "@";
0060:
0061: /**
0062: * STANDARD_*_MENU_NAME - standard menu names
0063: */
0064: public final static String STANDARD_BACK_MENU_NAME = "back";
0065: public final static String STANDARD_BREADCRUMBS_MENU_NAME = "breadcrumbs";
0066: public final static String STANDARD_PAGES_MENU_NAME = "pages";
0067: public final static String STANDARD_NAVIGATIONS_MENU_NAME = "navigations";
0068:
0069: /**
0070: * CUSTOM_*_MENU_NAME - custom menu names
0071: */
0072: public final static String CUSTOM_PAGE_NAVIGATIONS_MENU_NAME = "page-navigations";
0073:
0074: /**
0075: * STANDARD_MENU_NAMES - set of supported standard menu names
0076: */
0077: private final static Set STANDARD_MENU_NAMES = new HashSet(3);
0078: static {
0079: STANDARD_MENU_NAMES.add(STANDARD_BACK_MENU_NAME);
0080: STANDARD_MENU_NAMES.add(STANDARD_BREADCRUMBS_MENU_NAME);
0081: STANDARD_MENU_NAMES.add(STANDARD_PAGES_MENU_NAME);
0082: STANDARD_MENU_NAMES.add(STANDARD_NAVIGATIONS_MENU_NAME);
0083: }
0084:
0085: /**
0086: * STANDARD_MENU_DEFINITION_LOCATORS - list of standard menu definition locators
0087: */
0088: private final static List STANDARD_MENU_DEFINITION_LOCATORS = new ArrayList(
0089: 4);
0090: static {
0091: STANDARD_MENU_DEFINITION_LOCATORS
0092: .add(new SiteViewMenuDefinitionLocator(
0093: new StandardBackMenuDefinition()));
0094: STANDARD_MENU_DEFINITION_LOCATORS
0095: .add(new SiteViewMenuDefinitionLocator(
0096: new StandardBreadcrumbsMenuDefinition()));
0097: STANDARD_MENU_DEFINITION_LOCATORS
0098: .add(new SiteViewMenuDefinitionLocator(
0099: new StandardPagesMenuDefinition()));
0100: STANDARD_MENU_DEFINITION_LOCATORS
0101: .add(new SiteViewMenuDefinitionLocator(
0102: new StandardNavigationsMenuDefinition()));
0103: }
0104:
0105: /**
0106: * pageManager - PageManager component
0107: */
0108: private PageManager pageManager;
0109:
0110: /**
0111: * searchPaths - validated list of ordered search path objects
0112: * where paths have no trailing folder separator
0113: */
0114: private List searchPaths;
0115:
0116: /**
0117: * searchPathsString - search paths as string
0118: */
0119: private String searchPathsString;
0120:
0121: /**
0122: * rootFolderProxy - root folder proxy instance
0123: */
0124: private Folder rootFolderProxy;
0125:
0126: /**
0127: * SiteView - validating constructor
0128: *
0129: * @param pageManager PageManager component instance
0130: * @param searchPaths list of search paths in string or search path
0131: * object form
0132: */
0133: public SiteView(PageManager pageManager, List searchPaths) {
0134: this .pageManager = pageManager;
0135: if ((searchPaths != null) && !searchPaths.isEmpty()) {
0136: // validate search path format and existence
0137: this .searchPaths = new ArrayList(searchPaths.size());
0138: StringBuffer searchPathsStringBuffer = new StringBuffer();
0139: Iterator pathsIter = searchPaths.iterator();
0140: while (pathsIter.hasNext()) {
0141: Object pathObject = pathsIter.next();
0142: if (!(pathObject instanceof SiteViewSearchPath)) {
0143: String path = pathObject.toString().trim();
0144: if (path.length() > 0) {
0145: pathObject = new SiteViewSearchPath(
0146: ProfileLocator.PAGE_LOCATOR, path);
0147: }
0148: }
0149: SiteViewSearchPath searchPath = (SiteViewSearchPath) pathObject;
0150: if (this .searchPaths.indexOf(searchPath) == -1) {
0151: try {
0152: if (this .pageManager.getFolder(searchPath
0153: .toString()) != null) {
0154: this .searchPaths.add(searchPath);
0155:
0156: // construct search paths as string
0157: if (searchPathsStringBuffer.length() == 0) {
0158: searchPathsStringBuffer
0159: .append(searchPath);
0160: } else {
0161: searchPathsStringBuffer.append(',');
0162: searchPathsStringBuffer
0163: .append(searchPath);
0164: }
0165: }
0166: } catch (NodeException ne) {
0167: } catch (NodeNotFoundException nnfe) {
0168: } catch (SecurityException se) {
0169: }
0170: }
0171: }
0172:
0173: // if no valid paths found, assume root search path
0174: // with no aggregation is to be used as default; otherwise,
0175: // save search paths as string
0176: if (this .searchPaths.isEmpty()) {
0177: this .searchPaths.add(new SiteViewSearchPath(
0178: ProfileLocator.PAGE_LOCATOR,
0179: Folder.PATH_SEPARATOR));
0180: this .searchPathsString = Folder.PATH_SEPARATOR;
0181: } else {
0182: this .searchPathsString = searchPathsStringBuffer
0183: .toString();
0184: }
0185: } else {
0186: // root search path with no aggregation
0187: this .searchPaths = new ArrayList(1);
0188: this .searchPaths
0189: .add(new SiteViewSearchPath(
0190: ProfileLocator.PAGE_LOCATOR,
0191: Folder.PATH_SEPARATOR));
0192: this .searchPathsString = Folder.PATH_SEPARATOR;
0193: }
0194: }
0195:
0196: /**
0197: * SiteView - validating constructor
0198: *
0199: * @param pageManager PageManager component instance
0200: * @param searchPaths array of search paths
0201: */
0202: public SiteView(PageManager pageManager, String[] searchPaths) {
0203: this (pageManager, makeSearchPathList(searchPaths));
0204: }
0205:
0206: /**
0207: * makeSearchPathList - construct from array
0208: *
0209: * @param searchPaths array of search paths
0210: * @return search path list
0211: */
0212: private static List makeSearchPathList(String[] searchPaths) {
0213: if ((searchPaths != null) && (searchPaths.length > 0)) {
0214: List searchPathsList = new ArrayList(searchPaths.length);
0215: for (int i = 0; (i < searchPaths.length); i++) {
0216: searchPathsList.add(searchPaths[i]);
0217: }
0218: return searchPathsList;
0219: }
0220: return null;
0221: }
0222:
0223: /**
0224: * SiteView - validating constructor
0225: *
0226: * @param pageManager PageManager component instance
0227: * @param searchPaths string of comma separated search paths
0228: */
0229: public SiteView(PageManager pageManager, String searchPaths) {
0230: this (pageManager, makeSearchPathList(searchPaths));
0231: }
0232:
0233: /**
0234: * makeSearchPathList - construct from string
0235: *
0236: * @param searchPaths string of comma separated search paths
0237: * @return search path list
0238: */
0239: private static List makeSearchPathList(String searchPaths) {
0240: return ((searchPaths != null) ? makeSearchPathList(searchPaths
0241: .split(",")) : null);
0242: }
0243:
0244: /**
0245: * SiteView - validating constructor
0246: *
0247: * @param pageManager PageManager component instance
0248: * @param locator profile locator search specification
0249: */
0250: public SiteView(PageManager pageManager, ProfileLocator locator) {
0251: this (pageManager, makeSearchPathList(locator));
0252: }
0253:
0254: /**
0255: * makeSearchPathList - construct from profile locator
0256: *
0257: * @param locator profile locator search specification
0258: * @return search path list
0259: */
0260: private static List makeSearchPathList(ProfileLocator locator) {
0261: if (locator != null) {
0262: // generate and return locator search paths
0263: return mergeSearchPathList(ProfileLocator.PAGE_LOCATOR,
0264: locator, new ArrayList(8));
0265: }
0266: return null;
0267: }
0268:
0269: /**
0270: * SiteView - validating constructor
0271: *
0272: * @param pageManager PageManager component instance
0273: * @param locators map of named profile locator search specifications
0274: */
0275: public SiteView(PageManager pageManager, Map locators) {
0276: this (pageManager, makeSearchPathList(locators));
0277: }
0278:
0279: /**
0280: * makeSearchPathList - construct from profile locators
0281: *
0282: * @param locators map of named profile locator search specifications
0283: * @return search path list
0284: */
0285: private static List makeSearchPathList(Map locators) {
0286: if ((locators != null) && !locators.isEmpty()) {
0287: // generate locators search paths; aggregate individual
0288: // profile locator search paths with the 'page' locator
0289: // having priority, (all other named locators are processed
0290: // subsequent to 'page' in unspecified order).
0291: List searchPaths = new ArrayList(8 * locators.size());
0292: ProfileLocator pageLocator = (ProfileLocator) locators
0293: .get(ProfileLocator.PAGE_LOCATOR);
0294: if (pageLocator != null) {
0295: // add priority 'page' locator search paths
0296: mergeSearchPathList(ProfileLocator.PAGE_LOCATOR,
0297: pageLocator, searchPaths);
0298: }
0299: if ((pageLocator == null) || (locators.size() > 1)) {
0300: Iterator locatorNameIter = locators.keySet().iterator();
0301: while (locatorNameIter.hasNext()) {
0302: String locatorName = (String) locatorNameIter
0303: .next();
0304: if (!locatorName
0305: .equals(ProfileLocator.PAGE_LOCATOR)) {
0306: // add alternate locator search paths
0307: mergeSearchPathList(locatorName,
0308: (ProfileLocator) locators
0309: .get(locatorName), searchPaths);
0310: }
0311: }
0312: }
0313: return searchPaths;
0314: }
0315: return null;
0316: }
0317:
0318: /**
0319: * mergeSearchPathList - append search paths from profile locator
0320: *
0321: * @param locatorName name of profile locator
0322: * @param locator profile locator search specification
0323: * @param searchPaths list of search paths to merge into
0324: * @return search path list
0325: */
0326: private static List mergeSearchPathList(String locatorName,
0327: ProfileLocator locator, List searchPaths) {
0328: // generate profile locator search paths with locator
0329: // names to be used later for node identification and
0330: // grouping; note that the profile locator iterator
0331: // starts returning a full set of properties and returns
0332: // a shorter properties array with each iteration to
0333: // create the next search criteria... depending on the
0334: // validity of the property values and their cardinality,
0335: // (multiple property values are returned sequentially),
0336: // profiler locator iterations may be skipped to
0337: // generate the proper search paths
0338: List locatorSearchPaths = new ArrayList(8);
0339: int addLocatorSearchPathsAt = 0;
0340: Iterator locatorIter = locator.iterator();
0341: while (locatorIter.hasNext()) {
0342: // initialize path construction variables
0343: String pathRoot = Folder.PATH_SEPARATOR;
0344: List paths = new ArrayList(8);
0345: paths.add(new StringBuffer(pathRoot));
0346: int pathDepth = 0;
0347: int lastPathsCount = 0;
0348: String lastPropertyName = null;
0349: int lastPropertyValueLength = 0;
0350: boolean navigatedPathRoot = false;
0351:
0352: // reset advance of the profile locator offset by one
0353: // to accomodate automatic iteration within locator loop
0354: int skipProfileLocatorIterations = -1;
0355:
0356: // form locator properties into a complete path
0357: ProfileLocatorProperty[] properties = (ProfileLocatorProperty[]) locatorIter
0358: .next();
0359: for (int i = 0; (i < properties.length); i++) {
0360: if (properties[i].isNavigation()) {
0361: // reset search paths to navigation root path, (reset
0362: // only navigation supported), skip null navigation values
0363: if (properties[i].getValue() != null) {
0364: // TODO: support relative navigation values
0365:
0366: // assume navigation value must be a root prefix
0367: // and contains proper path prefix for each subsite
0368: // path folder name
0369: pathRoot = properties[i].getValue();
0370: if (!pathRoot.startsWith(Folder.PATH_SEPARATOR)) {
0371: pathRoot = Folder.PATH_SEPARATOR + pathRoot;
0372: }
0373: if (!pathRoot.endsWith(Folder.PATH_SEPARATOR)) {
0374: pathRoot += Folder.PATH_SEPARATOR;
0375: }
0376: if (!pathRoot.equals(Folder.PATH_SEPARATOR)) {
0377: int folderIndex = 1;
0378: do {
0379: if (!pathRoot
0380: .regionMatches(
0381: folderIndex,
0382: Folder.RESERVED_SUBSITE_FOLDER_PREFIX,
0383: 0,
0384: Folder.RESERVED_SUBSITE_FOLDER_PREFIX
0385: .length())) {
0386: pathRoot = pathRoot.substring(0,
0387: folderIndex)
0388: + Folder.RESERVED_SUBSITE_FOLDER_PREFIX
0389: + pathRoot
0390: .substring(folderIndex);
0391: }
0392: folderIndex = pathRoot.indexOf(
0393: Folder.PATH_SEPARATOR,
0394: folderIndex) + 1;
0395: } while ((folderIndex != -1)
0396: && (folderIndex != pathRoot
0397: .length()));
0398: }
0399:
0400: // reset locator paths using new prefix
0401: pathDepth = 0;
0402: paths.clear();
0403: paths.add(new StringBuffer(pathRoot));
0404: lastPathsCount = 0;
0405: lastPropertyName = null;
0406: lastPropertyValueLength = 0;
0407: navigatedPathRoot = true;
0408:
0409: // reset advance of the the profile locator iterator
0410: skipProfileLocatorIterations = 0;
0411: } else {
0412: // make sure multiple trailing null valued properties are
0413: // ignored if more than one is present by advancing
0414: // the profile locator iterator
0415: skipProfileLocatorIterations++;
0416: }
0417: } else if (properties[i].isControl()) {
0418: // skip null control values
0419: if (properties[i].getValue() != null) {
0420: // fold control names to lower case; preserve
0421: // value case as provided by profiler
0422: String propertyName = properties[i].getName()
0423: .toLowerCase();
0424: String propertyValue = properties[i].getValue();
0425: // detect duplicate control names which indicates multiple
0426: // values: must duplicate locator paths for each value; different
0427: // control values are simply appended to all locator paths
0428: if (propertyName.equals(lastPropertyName)) {
0429: // duplicate last locator paths set, stripping last matching
0430: // control value from each, appending new value, and adding new
0431: // valued set to collection of paths
0432: ArrayList multipleValuePaths = new ArrayList(
0433: lastPathsCount);
0434: Iterator pathsIter = paths.iterator();
0435: for (int count = 0; (pathsIter.hasNext() && (count < lastPathsCount)); count++) {
0436: StringBuffer path = (StringBuffer) pathsIter
0437: .next();
0438: StringBuffer multipleValuePath = new StringBuffer(
0439: path.toString());
0440: multipleValuePath
0441: .setLength(multipleValuePath
0442: .length()
0443: - lastPropertyValueLength
0444: - 1);
0445: multipleValuePath.append(propertyValue);
0446: multipleValuePath
0447: .append(Folder.PATH_SEPARATOR_CHAR);
0448: multipleValuePaths
0449: .add(multipleValuePath);
0450: }
0451: paths.addAll(multipleValuePaths);
0452:
0453: // make sure trailing multiple valued properties are
0454: // ignored by advancing the profile locator iterator
0455: // which is reset for each unique property value sets
0456: skipProfileLocatorIterations++;
0457: } else {
0458: // construct locator path folders with control properties
0459: Iterator pathsIter = paths.iterator();
0460: while (pathsIter.hasNext()) {
0461: StringBuffer path = (StringBuffer) pathsIter
0462: .next();
0463: path
0464: .append(Folder.RESERVED_FOLDER_PREFIX);
0465: path.append(propertyName);
0466: path.append(Folder.PATH_SEPARATOR_CHAR);
0467: path.append(propertyValue);
0468: path.append(Folder.PATH_SEPARATOR_CHAR);
0469: }
0470:
0471: // reset last locator property vars
0472: pathDepth++;
0473: lastPathsCount = paths.size();
0474: lastPropertyValueLength = propertyValue
0475: .length();
0476: lastPropertyName = propertyName;
0477:
0478: // reset advance of the the profile locator iterator
0479: skipProfileLocatorIterations = 0;
0480: }
0481: } else {
0482: // make sure multiple trailing null valued properties are
0483: // ignored along with the last property values if more
0484: // than one is present by advancing the profile locator
0485: // iterator
0486: skipProfileLocatorIterations++;
0487: }
0488: } else {
0489: // make sure multiple trailing request path properties are
0490: // ignored if more than one is present by advancing the
0491: // profile locator iterator
0492: skipProfileLocatorIterations++;
0493: }
0494: }
0495:
0496: // if required, advance profile locator iterations
0497: for (int skip = skipProfileLocatorIterations; ((skip > 0) && (locatorIter
0498: .hasNext())); skip--) {
0499: locatorIter.next();
0500: }
0501:
0502: // append any generated paths to locator search paths and
0503: // append root path if at end of locator path group, (locator
0504: // path roots are not returned by profiler iterator if not
0505: // explicitly navigated)
0506: if ((pathDepth > 0) || navigatedPathRoot) {
0507: locatorSearchPaths.addAll(addLocatorSearchPathsAt,
0508: paths);
0509: addLocatorSearchPathsAt += paths.size();
0510: }
0511: if ((pathDepth == 1) && !navigatedPathRoot) {
0512: locatorSearchPaths.add(addLocatorSearchPathsAt++,
0513: new StringBuffer(pathRoot));
0514: }
0515:
0516: // reset locator search path ordering since navigated root
0517: // paths are generated by the iterator based algorithm above
0518: // right to left instead of left to right as expected
0519: if ((pathDepth == 0) && navigatedPathRoot) {
0520: addLocatorSearchPathsAt = 0;
0521: }
0522:
0523: // if end of locator path group and have not navigated to
0524: // a new root path or there are no more locator iterations,
0525: // insert the paths into the search path results
0526: if (((pathDepth <= 1) && !navigatedPathRoot)
0527: || !locatorIter.hasNext()) {
0528: // add locator paths to unique search paths preserving
0529: // search order; move non-unique paths to end of search
0530: // path list to favor more specific paths over common
0531: // root paths, (i.e. '/' should be last)
0532: Iterator locatorSearchPathsIter = locatorSearchPaths
0533: .iterator();
0534: while (locatorSearchPathsIter.hasNext()) {
0535: SiteViewSearchPath searchPath = new SiteViewSearchPath(
0536: locatorName, locatorSearchPathsIter.next()
0537: .toString());
0538: // test search path uniqueness
0539: int existsAt = searchPaths.indexOf(searchPath);
0540: if (existsAt != -1) {
0541: if (existsAt < (searchPaths.size() - 1)) {
0542: // push existing search path to end of paths
0543: searchPaths.add(searchPaths
0544: .remove(existsAt));
0545: }
0546: } else {
0547: // add new unique search path to end of paths
0548: searchPaths.add(searchPath);
0549: }
0550: }
0551:
0552: // clear merged locator search paths
0553: locatorSearchPaths.clear();
0554: addLocatorSearchPathsAt = 0;
0555: }
0556: }
0557: return searchPaths;
0558: }
0559:
0560: /**
0561: * SiteView - basic constructor
0562: *
0563: * @param pageManager PageManager component instance
0564: */
0565: public SiteView(PageManager pageManager) {
0566: this (pageManager, (List) null);
0567: }
0568:
0569: /**
0570: * getPageManager - return PageManager component instance
0571: *
0572: * @return PageManager instance
0573: */
0574: public PageManager getPageManager() {
0575: return pageManager;
0576: }
0577:
0578: /**
0579: * getSearchPaths - return ordered search paths list that
0580: * defines this view
0581: *
0582: * @return search paths list
0583: */
0584: public List getSearchPaths() {
0585: return searchPaths;
0586: }
0587:
0588: /**
0589: * getSearchPathsString - return search paths as string
0590: *
0591: * @return search paths list as comma separated string
0592: */
0593: public String getSearchPathsString() {
0594: return searchPathsString;
0595: }
0596:
0597: /**
0598: * getRootFolderProxy - create and return root folder proxy instance
0599: *
0600: * @return root folder proxy
0601: * @throws FolderNotFoundException if not found
0602: * @throws SecurityException if view access not granted
0603: */
0604: public Folder getRootFolderProxy() throws FolderNotFoundException {
0605: // latently construct and return root folder proxy
0606: if (rootFolderProxy == null) {
0607: try {
0608: // the folder and profile locator name of the root
0609: // folder proxy in the view is the locator name of the
0610: // first search path since search paths are valid
0611: SiteViewSearchPath searchPath = (SiteViewSearchPath) searchPaths
0612: .get(0);
0613: String path = searchPath.toString();
0614: String locatorName = searchPath.getLocatorName();
0615:
0616: // get concrete root folder from page manager
0617: // and construct proxy
0618: Folder rootFolder = pageManager.getFolder(path);
0619: rootFolderProxy = FolderProxy.newInstance(this ,
0620: locatorName, null, rootFolder);
0621: } catch (NodeException ne) {
0622: FolderNotFoundException fnfe = new FolderNotFoundException(
0623: "Root folder not found");
0624: fnfe.initCause(ne);
0625: throw fnfe;
0626: } catch (NodeNotFoundException nnfe) {
0627: FolderNotFoundException fnfe = new FolderNotFoundException(
0628: "Root folder not found");
0629: fnfe.initCause(nnfe);
0630: throw fnfe;
0631: }
0632: }
0633: return rootFolderProxy;
0634: }
0635:
0636: /**
0637: * getNodeProxy - get single folder, page, or link proxy
0638: * at relative or absolute path
0639: *
0640: * @param path single node path
0641: * @param currentNode current folder or page for relative paths or null
0642: * @param onlyViewable node required to be viewable
0643: * @param onlyVisible node required to be visible, (or current)
0644: * @return folder, page, or link node proxy
0645: * @throws NodeNotFoundException if not found
0646: * @throws SecurityException if view access not granted
0647: */
0648: public Node getNodeProxy(String path, Node currentNode,
0649: boolean onlyViewable, boolean onlyVisible)
0650: throws NodeNotFoundException {
0651: // determine current folder and page
0652: String currentPath = path;
0653: Folder currentFolder = null;
0654: Page currentPage = null;
0655: if (currentNode instanceof Page) {
0656: currentPage = (Page) currentNode;
0657: currentFolder = (Folder) currentPage.getParent();
0658: } else if (currentNode instanceof Folder) {
0659: currentFolder = (Folder) currentNode;
0660: }
0661:
0662: // match current page path
0663: if (currentPath.equals(CURRENT_PAGE_PATH)
0664: || currentPath.equals(ALT_CURRENT_PAGE_PATH)) {
0665: // return current page if specified, (assume viewable)
0666: return currentPage;
0667: }
0668:
0669: // convert absolute path to a root relative search
0670: // and default current folder
0671: if (currentPath.startsWith(Folder.PATH_SEPARATOR)) {
0672: currentPath = currentPath.substring(1);
0673: currentFolder = null;
0674: }
0675: if (currentFolder == null) {
0676: currentFolder = getRootFolderProxy();
0677: }
0678:
0679: // search for path based on current folder
0680: while ((currentPath.length() > 0)
0681: && !currentPath.equals(Folder.PATH_SEPARATOR)) {
0682: // parse relative sub-folder from path
0683: int separatorIndex = currentPath
0684: .indexOf(Folder.PATH_SEPARATOR);
0685: if (separatorIndex != -1) {
0686: // isolate sub-folder and continue search
0687: // using remaining paths
0688: String subfolder = currentPath.substring(0,
0689: separatorIndex);
0690: currentPath = currentPath.substring(separatorIndex + 1);
0691: if (subfolder.equals("..")) {
0692: // adjust current folder if parent exists
0693: if (currentFolder.getParent() != null) {
0694: currentFolder = (Folder) currentFolder
0695: .getParent();
0696: } else {
0697: throw new NodeNotFoundException(
0698: "Specified path " + path
0699: + " not found.");
0700: }
0701: } else if (!subfolder.equals(".")) {
0702: // access sub-folder or return null if nonexistent
0703: // or access forbidden
0704: try {
0705: currentFolder = currentFolder
0706: .getFolder(subfolder);
0707: } catch (NodeException ne) {
0708: NodeNotFoundException nnfe = new NodeNotFoundException(
0709: "Specified path " + path
0710: + " not found.");
0711: nnfe.initCause(ne);
0712: throw nnfe;
0713: } catch (NodeNotFoundException nnfe) {
0714: NodeNotFoundException nnfeWrapper = new NodeNotFoundException(
0715: "Specified path " + path
0716: + " not found.");
0717: nnfeWrapper.initCause(nnfe);
0718: throw nnfeWrapper;
0719: }
0720: }
0721: } else {
0722: // access remaining path as page, folder, or link node
0723: // proxy; return null if not found or not viewable/visible
0724: // and visibility is required
0725: try {
0726: NodeSet children = currentFolder.getAll();
0727: if (children != null) {
0728: Node node = children.get(currentPath);
0729: if ((node != null)
0730: && (!onlyVisible || !node.isHidden() || (node == currentPage))
0731: && (!onlyViewable || isProxyViewable(
0732: node, onlyVisible))) {
0733: return node;
0734: }
0735: }
0736: } catch (NodeException ne) {
0737: NodeNotFoundException nnfe = new NodeNotFoundException(
0738: "Specified path " + path + " not found.");
0739: nnfe.initCause(ne);
0740: throw nnfe;
0741: }
0742: throw new NodeNotFoundException("Specified path "
0743: + path + " not found or viewable/visible.");
0744: }
0745: }
0746:
0747: // path maps to current folder; return if viewable/visible
0748: // or visibility not required
0749: if ((!onlyVisible || !currentFolder.isHidden())
0750: && (!onlyViewable || isProxyViewable(currentFolder,
0751: onlyVisible))) {
0752: return currentFolder;
0753: }
0754: throw new NodeNotFoundException("Specified path " + path
0755: + " not found or viewable/visible.");
0756: }
0757:
0758: /**
0759: * getNodeProxies - get folder, page, or link proxies at
0760: * relative or absolute path using simple path
0761: * wildcards and character classes
0762: *
0763: * @param regexpPath regular expression node path
0764: * @param currentNode current folder or page for relative paths or null
0765: * @param onlyViewable nodes required to be viewable flag
0766: * @param onlyVisible node required to be visible, (or current)
0767: * @return list of folder, page, or link node proxies
0768: */
0769: public List getNodeProxies(String regexpPath, Node currentNode,
0770: boolean onlyViewable, boolean onlyVisible) {
0771: // determine current folder and page
0772: String currentRegexpPath = regexpPath;
0773: Folder currentFolder = null;
0774: Page currentPage = null;
0775: if (currentNode instanceof Page) {
0776: currentPage = (Page) currentNode;
0777: currentFolder = (Folder) currentPage.getParent();
0778: } else if (currentNode instanceof Folder) {
0779: currentFolder = (Folder) currentNode;
0780: }
0781:
0782: // match current page path
0783: if (currentRegexpPath.equals(CURRENT_PAGE_PATH)
0784: || currentRegexpPath.equals(ALT_CURRENT_PAGE_PATH)) {
0785: if (currentPage != null) {
0786: // return current page, (assume viewable)
0787: List proxies = new ArrayList(1);
0788: proxies.add(currentPage);
0789: return proxies;
0790: } else {
0791: // current page not specified
0792: return null;
0793: }
0794: }
0795:
0796: // convert absolute path to a root relative search
0797: // and default current folder
0798: if (currentRegexpPath.startsWith(Folder.PATH_SEPARATOR)) {
0799: currentRegexpPath = currentRegexpPath.substring(1);
0800: currentFolder = null;
0801: }
0802: if (currentFolder == null) {
0803: try {
0804: currentFolder = getRootFolderProxy();
0805: } catch (FolderNotFoundException fnfe) {
0806: return null;
0807: } catch (SecurityException se) {
0808: return null;
0809: }
0810: }
0811:
0812: // search for path based on current folder
0813: while ((currentRegexpPath.length() > 0)
0814: && !currentRegexpPath.equals(Folder.PATH_SEPARATOR)) {
0815: // parse relative sub-folder from path
0816: int separatorIndex = currentRegexpPath
0817: .indexOf(Folder.PATH_SEPARATOR);
0818: if (separatorIndex != -1) {
0819: // isolate sub-folder and continue search
0820: // using remaining paths
0821: String subfolder = currentRegexpPath.substring(0,
0822: separatorIndex);
0823: currentRegexpPath = currentRegexpPath
0824: .substring(separatorIndex + 1);
0825: if (subfolder.equals("..")) {
0826: // adjust current folder if parent exists
0827: if (currentFolder.getParent() != null) {
0828: currentFolder = (Folder) currentFolder
0829: .getParent();
0830: } else {
0831: return null;
0832: }
0833: } else if (!subfolder.equals(".")) {
0834: try {
0835: // check for regular expression pattern
0836: String subfolderPattern = pathRegexpPattern(subfolder);
0837: if (subfolderPattern != null) {
0838: // follow all matching sub-folders
0839: NodeSet subfolders = currentFolder
0840: .getFolders();
0841: if (subfolders != null) {
0842: subfolders = subfolders
0843: .inclusiveSubset(subfolderPattern);
0844: if (subfolders != null) {
0845: // recursively process sub-folders if more than
0846: // one match, access single sub-folder, or return
0847: // null if nonexistent
0848: if (subfolders.size() > 1) {
0849: // recursively process matching sub-folders
0850: List proxies = null;
0851: Iterator subfoldersIter = subfolders
0852: .iterator();
0853: while (subfoldersIter.hasNext()) {
0854: currentFolder = (Folder) subfoldersIter
0855: .next();
0856: List subfolderProxies = getNodeProxies(
0857: currentRegexpPath,
0858: currentFolder,
0859: onlyViewable,
0860: onlyVisible);
0861: if ((subfolderProxies != null)
0862: && !subfolderProxies
0863: .isEmpty()) {
0864: if (proxies == null) {
0865: proxies = new ArrayList();
0866: }
0867: proxies
0868: .addAll(subfolderProxies);
0869: }
0870: }
0871: return proxies;
0872: } else if (subfolders.size() == 1) {
0873: // access single sub-folder
0874: currentFolder = (Folder) subfolders
0875: .iterator().next();
0876: } else {
0877: // no matching sub-folders
0878: return null;
0879: }
0880: } else {
0881: // no matching sub-folders
0882: return null;
0883: }
0884: } else {
0885: // no sub-folders
0886: return null;
0887: }
0888: } else {
0889: // access single sub-folder or return null if
0890: // nonexistent by throwing exception
0891: currentFolder = currentFolder
0892: .getFolder(subfolder);
0893: }
0894: } catch (NodeException ne) {
0895: // could not access sub-folders
0896: return null;
0897: } catch (NodeNotFoundException nnfe) {
0898: // could not access sub-folders
0899: return null;
0900: } catch (SecurityException se) {
0901: // could not access sub-folders
0902: return null;
0903: }
0904: }
0905: } else {
0906: try {
0907: // get all children of current folder
0908: NodeSet children = currentFolder.getAll();
0909: if (children != null) {
0910: // check for regular expression pattern
0911: String pathPattern = pathRegexpPattern(currentRegexpPath);
0912: if (pathPattern != null) {
0913: // copy children matching remaining path pattern as
0914: // page, folder, or link proxies if viewable/visible or
0915: // visibilty not required
0916: children = children
0917: .inclusiveSubset(pathPattern);
0918: if ((children != null)
0919: && !children.isEmpty()) {
0920: List proxies = null;
0921: Iterator childrenIter = children
0922: .iterator();
0923: while (childrenIter.hasNext()) {
0924: Node child = (Node) childrenIter
0925: .next();
0926: if ((!onlyVisible
0927: || !child.isHidden() || (child == currentPage))
0928: && (!onlyViewable || isProxyViewable(
0929: child, onlyVisible))) {
0930: if (proxies == null) {
0931: proxies = new ArrayList(
0932: children.size());
0933: }
0934: proxies.add(child);
0935: }
0936: }
0937: return proxies;
0938: }
0939: } else {
0940: // access remaining path as page, folder, or link
0941: // node proxy; return null if not found or not
0942: // viewable and visiblity is required
0943: Node child = children
0944: .get(currentRegexpPath);
0945: if ((child != null)
0946: && (!onlyVisible
0947: || !child.isHidden() || (child == currentPage))
0948: && (!onlyViewable || isProxyViewable(
0949: child, onlyVisible))) {
0950: List proxies = new ArrayList(1);
0951: proxies.add(currentFolder);
0952: return proxies;
0953: }
0954: }
0955: }
0956:
0957: } catch (NodeException ne) {
0958: } catch (SecurityException se) {
0959: }
0960:
0961: // no children match or available
0962: return null;
0963: }
0964: }
0965:
0966: // path maps to current folder; return if viewable/visible
0967: // or visibility not required
0968: if ((!onlyVisible || !currentFolder.isHidden())
0969: && (!onlyViewable || isProxyViewable(currentFolder,
0970: onlyVisible))) {
0971: List proxies = new ArrayList(1);
0972: proxies.add(currentFolder);
0973: return proxies;
0974: }
0975: return null;
0976: }
0977:
0978: /**
0979: * pathRegexpPattern - tests for and converts simple path wildcard
0980: * and character class regular exressions to
0981: * perl5/standard java pattern syntax
0982: *
0983: * @param regexp - candidate path regular expression
0984: * @return - converted pattern or null if no regular expression
0985: */
0986: private static String pathRegexpPattern(String regexp) {
0987: // convert expression to pattern
0988: StringBuffer pattern = null;
0989: for (int i = 0, limit = regexp.length(); (i < limit); i++) {
0990: char regexpChar = regexp.charAt(i);
0991: switch (regexpChar) {
0992: case '*':
0993: case '.':
0994: case '?':
0995: case '[':
0996: if (pattern == null) {
0997: pattern = new StringBuffer(regexp.length() * 2);
0998: pattern.append(regexp.substring(0, i));
0999: }
1000: switch (regexpChar) {
1001: case '*':
1002: pattern.append(".*");
1003: break;
1004: case '.':
1005: pattern.append("\\.");
1006: break;
1007: case '?':
1008: pattern.append('.');
1009: break;
1010: case '[':
1011: pattern.append('[');
1012: break;
1013: }
1014: break;
1015: default:
1016: if (pattern != null) {
1017: pattern.append(regexpChar);
1018: }
1019: break;
1020: }
1021: }
1022:
1023: // return converted pattern or null if not a regular expression
1024: if (pattern != null)
1025: return pattern.toString();
1026: return null;
1027: }
1028:
1029: /**
1030: * isProxyViewable - tests for node proxy visibility in view
1031: *
1032: * @param nodeProxy test node proxy
1033: * @param onlyVisible nodes required to be visible
1034: * @return - viewable flag
1035: */
1036: private static boolean isProxyViewable(Node nodeProxy,
1037: boolean onlyVisible) {
1038: // pages and links are always considered viewable;
1039: // folders must be tested for viewable and visibile
1040: // child nodes
1041: if (nodeProxy instanceof Folder) {
1042: try {
1043: NodeSet children = ((Folder) nodeProxy).getAll();
1044: if (children != null) {
1045: Iterator childrenIter = children.iterator();
1046: while (childrenIter.hasNext()) {
1047: Node child = (Node) childrenIter.next();
1048: if ((!onlyVisible || !child.isHidden())
1049: && isProxyViewable(child, onlyVisible)) {
1050: return true;
1051: }
1052: }
1053: }
1054: } catch (NodeException ne) {
1055: } catch (SecurityException se) {
1056: }
1057: return false;
1058: }
1059: return true;
1060: }
1061:
1062: /**
1063: * getStandardMenuNames - get set of available standard menu names
1064: *
1065: * @return menu names set
1066: */
1067: public Set getStandardMenuNames() {
1068: // return constant standard menu names
1069: return STANDARD_MENU_NAMES;
1070: }
1071:
1072: /**
1073: * getStandardMenuDefinitionLocators - get list of available standard
1074: * menu definition locators
1075: *
1076: * @return menu definition locators list
1077: */
1078: public List getStandardMenuDefinitionLocators() {
1079: // return constant standard menu definition locators
1080: return STANDARD_MENU_DEFINITION_LOCATORS;
1081: }
1082:
1083: /**
1084: * getMenuDefinitionLocators - get list of view node proxy menu
1085: * definition locators; implemented here
1086: * to hide view proxy manipulation from
1087: * more general portal site implementation
1088: *
1089: * @param node node proxy
1090: * @return definition locator list
1091: */
1092: public List getMenuDefinitionLocators(Node node) {
1093: // access node proxy from specified node and
1094: // return associated definition locators
1095: NodeProxy nodeProxy = NodeProxy.getNodeProxy(node);
1096: if (nodeProxy != null) {
1097: return nodeProxy.getMenuDefinitionLocators();
1098: }
1099: return null;
1100: }
1101:
1102: /**
1103: * getMenuDefinitionLocator - get named view node proxy menu
1104: * definition locator; implemented here
1105: * to hide view proxy manipulation from
1106: * more general portal site implementation
1107: *
1108: * @param node node proxy
1109: * @param name menu definition name
1110: * @return menu definition locator
1111: */
1112: public SiteViewMenuDefinitionLocator getMenuDefinitionLocator(
1113: Node node, String name) {
1114: // access node proxy from specified node and
1115: // return associated definition locators
1116: NodeProxy nodeProxy = NodeProxy.getNodeProxy(node);
1117: if (nodeProxy != null) {
1118: return nodeProxy.getMenuDefinitionLocator(name);
1119: }
1120: return null;
1121: }
1122:
1123: /**
1124: * getProfileLocatorName - get view node proxy profile locator name;
1125: * implemented here to hide view proxy manipulation
1126: * from more general portal site implementation
1127: *
1128: * @param node node proxy
1129: * @return profile locator name
1130: */
1131: public String getProfileLocatorName(Node node) {
1132: SiteViewProxy siteViewProxy = SiteViewProxy
1133: .getSiteViewProxy(node);
1134: if (siteViewProxy != null) {
1135: return siteViewProxy.getLocatorName();
1136: }
1137: return null;
1138: }
1139:
1140: /**
1141: * getManagedPage - get concrete page instance from page proxy;
1142: * implemented here to hide view proxy manipulation
1143: * from more general portal site implementation
1144: *
1145: * @param page page proxy
1146: * @return managed page
1147: */
1148: public Page getManagedPage(Page page) {
1149: // access page proxy from specified page and
1150: // return associated delegate managed page
1151: PageProxy pageProxy = (PageProxy) NodeProxy.getNodeProxy(page);
1152: if (pageProxy != null) {
1153: return pageProxy.getPage();
1154: }
1155: return null;
1156: }
1157: }
|