All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opencms.jsp.CmsJspNavBuilder Maven / Gradle / Ivy

Go to download

OpenCms is an enterprise-ready, easy to use website content management system based on Java and XML technology. Offering a complete set of features, OpenCms helps content managers worldwide to create and maintain beautiful websites fast and efficiently.

There is a newer version: 17.0
Show newest version
/*
 * This library is part of OpenCms -
 * the Open Source Content Management System
 *
 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * For further information about Alkacon Software GmbH & Co. KG, please see the
 * company website: http://www.alkacon.com
 *
 * For further information about OpenCms, please see the
 * project website: http://www.opencms.org
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.opencms.jsp;

import org.opencms.file.CmsObject;
import org.opencms.file.CmsProperty;
import org.opencms.file.CmsPropertyDefinition;
import org.opencms.file.CmsResource;
import org.opencms.file.CmsResourceFilter;
import org.opencms.file.types.CmsResourceTypeFolder;
import org.opencms.file.types.I_CmsResourceType;
import org.opencms.main.CmsException;
import org.opencms.main.CmsLog;
import org.opencms.main.OpenCms;
import org.opencms.util.CmsFileUtil;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.apache.commons.logging.Log;

/**
 * Bean to provide a convenient way to build navigation structures based on the
 * {@link org.opencms.jsp.CmsJspNavElement}.

* * Use this together with the {@link org.opencms.jsp.CmsJspActionElement} * to obtain navigation information based on the current users permissions. * For example, use {@link #getNavigationForFolder(String)} and pass the * value of the current OpenCms user context uri obtained * from {@link org.opencms.file.CmsRequestContext#getUri()} as argument to obtain a list * of all items in the navigation of the current folder. Then use a simple scriptlet to * iterate over these items and create a HTML navigation.

* * @since 6.0.0 * * @see org.opencms.jsp.CmsJspNavElement */ public class CmsJspNavBuilder { /** * Navigation builder context. * * Stored in nav elements so they can ask the navigation builder for sub-navigation entries, with appropriate resource filter etc. */ public static class NavContext { /** The resource filter used. */ private CmsResourceFilter m_filter; /** The nav builder used. */ private CmsJspNavBuilder m_navBuilder; /** The visibility option used. */ private Visibility m_visibility; /** * Creates a new instance. * * @param navBuilder the navigation builder * @param visibility the visibility * @param filter the resource filter */ public NavContext(CmsJspNavBuilder navBuilder, Visibility visibility, CmsResourceFilter filter) { super(); m_visibility = visibility; m_filter = filter; m_navBuilder = navBuilder; } /** * Gets the resource filter. * * @return the resource filter */ public CmsResourceFilter getFilter() { return m_filter; } /** * Gets the navigation builder. * * @return the navigation builder */ public CmsJspNavBuilder getNavBuilder() { return m_navBuilder; } /** * Gets the visibility setting. * * @return the visibility setting */ public Visibility getVisibility() { return m_visibility; } } /** The visibility mode. */ public static enum Visibility { /** All entries. */ all, /** Navigation including hidden entries. */ includeHidden, /** Navigation only. */ navigation } /** Default file property value to mark navigation level folders. */ public static final String NAVIGATION_LEVEL_FOLDER = "##navigation_level_folder##"; /** The log object for this class. */ private static final Log LOG = CmsLog.getLog(CmsJspNavBuilder.class); /** The current CMS context. */ protected CmsObject m_cms; /** The locale for which the property should be read. */ protected Locale m_locale; /** The current request URI. */ protected String m_requestUri; /** The current request folder. */ protected String m_requestUriFolder; /** * Empty constructor, so that this bean can be initialized from a JSP.

*/ public CmsJspNavBuilder() { // empty } /** * Default constructor.

* * @param cms context provider for the current request */ public CmsJspNavBuilder(CmsObject cms) { init(cms, null); } /** * Constructor for a version that reads properties according to a locale.

* * @param cms context provider for the current request * @param locale the locale for which properties should be accessed */ public CmsJspNavBuilder(CmsObject cms, Locale locale) { init(cms, locale); } /** * Returns the full name (including VFS path) of the default file for this navigation element * or null if the navigation element is not a folder.

* * The default file of a folder is determined by the value of the property * default-file or the system wide property setting.

* * @param cms the CMS object * @param folder full name of the folder * * @return the name of the default file * * @deprecated use {@link CmsObject#readDefaultFile(String)} instead */ @Deprecated public static String getDefaultFile(CmsObject cms, String folder) { if (folder.endsWith("/")) { try { CmsResource defaultFile = cms.readDefaultFile(folder); if (defaultFile != null) { return cms.getSitePath(defaultFile); } } catch (CmsException e) { LOG.debug(e.getLocalizedMessage(), e); } return folder; } return null; } /** * Collect all navigation elements from the files in the given folder, * navigation elements are of class {@link CmsJspNavElement}.

* * @param cms context provider for the current request * @param folder the selected folder * * @return a sorted (ascending to navigation position) list of navigation elements * * @deprecated use {@link #getNavigationForFolder(String)} instead */ @Deprecated public static List getNavigationForFolder(CmsObject cms, String folder) { return new CmsJspNavBuilder(cms).getNavigationForFolder(folder); } /** * Build a navigation for the folder that is either minus levels up * from the given folder, or that is plus levels down from the * root folder towards the given folder.

* * If level is set to zero the root folder is used by convention.

* * @param cms context provider for the current request * @param folder the selected folder * @param level if negative, walk this many levels up, if positive, walk this many * levels down from root folder * * @return a sorted (ascending to navigation position) list of navigation elements * * @deprecated use {@link #getNavigationForFolder(String, int)} instead */ @Deprecated public static List getNavigationForFolder(CmsObject cms, String folder, int level) { return new CmsJspNavBuilder(cms).getNavigationForFolder(folder, level); } /** * Returns a navigation element for the named resource.

* * @param cms context provider for the current request * @param resource the resource name to get the navigation information for, * must be a full path name, e.g. "/docs/index.html" * * @return a navigation element for the given resource * * @deprecated use {@link #getNavigationForResource(String)} instead */ @Deprecated public static CmsJspNavElement getNavigationForResource(CmsObject cms, String resource) { return new CmsJspNavBuilder(cms).getNavigationForResource(resource); } /** * Builds a tree navigation for the folders between the provided start and end level.

* * A tree navigation includes all navigation elements that are required to display a tree structure. * However, the data structure is a simple list. * Each of the navigation elements in the list has the {@link CmsJspNavElement#getNavTreeLevel()} set * to the level it belongs to. Use this information to distinguish between the navigation levels.

* * @param cms context provider for the current request * @param folder the selected folder * @param startlevel the start level * @param endlevel the end level * * @return a sorted list of navigation elements with the navigation tree level property set * * @deprecated use {@link #getNavigationForResource(String)} instead */ @Deprecated public static List getNavigationTreeForFolder( CmsObject cms, String folder, int startlevel, int endlevel) { return new CmsJspNavBuilder(cms).getNavigationTreeForFolder(folder, startlevel, endlevel); } /** * This method builds a complete navigation tree with entries of all branches * from the specified folder.

* * For an unlimited depth of the navigation (i.e. no endLevel), * set the endLevel to a value < 0.

* * * @param cms the current CMS context * @param folder the root folder of the navigation tree * @param endLevel the end level of the navigation * * @return list of navigation elements, in depth first order * * @deprecated use {@link #getNavigationForResource(String)} instead */ @Deprecated public static List getSiteNavigation(CmsObject cms, String folder, int endLevel) { return new CmsJspNavBuilder(cms).getSiteNavigation(folder, endLevel); } /** * Returns whether the given resource is a folder and is marked to be a navigation level folder.

* * @param cms the cms context * @param resource the resource * * @return true if the resource is marked to be a navigation level folder */ public static boolean isNavLevelFolder(CmsObject cms, CmsResource resource) { if (resource.isFolder()) { I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(resource); if (CmsResourceTypeFolder.RESOURCE_TYPE_NAME.equals(type.getTypeName())) { try { CmsProperty prop = cms.readPropertyObject( resource, CmsPropertyDefinition.PROPERTY_DEFAULT_FILE, false); return !prop.isNullProperty() && NAVIGATION_LEVEL_FOLDER.equals(prop.getValue()); } catch (CmsException e) { LOG.debug(e.getMessage(), e); } } } return false; } /** * Gets the CMS context used for building the navigation. * * @return the CMS context */ public CmsObject getCmsObject() { return m_cms; } /** * Build a "bread crumb" path navigation to the current folder.

* * @return ArrayList sorted list of navigation elements * * @see #getNavigationBreadCrumb(String, int, int, boolean) */ public List getNavigationBreadCrumb() { return getNavigationBreadCrumb(m_requestUriFolder, 0, -1, true); } /** * Build a "bread crumb" path navigation to the current folder.

* * @param startlevel the start level, if negative, go down |n| steps from selected folder * @param currentFolder include the selected folder in navigation or not * * @return sorted list of navigation elements * * @see #getNavigationBreadCrumb(String, int, int, boolean) */ public List getNavigationBreadCrumb(int startlevel, boolean currentFolder) { return getNavigationBreadCrumb(m_requestUriFolder, startlevel, -1, currentFolder); } /** * Build a "bread crumb" path navigation to the current folder.

* * @param startlevel the start level, if negative, go down |n| steps from selected folder * @param endlevel the end level, if -1, build navigation to selected folder * * @return sorted list of navigation elements * * @see #getNavigationBreadCrumb(String, int, int, boolean) */ public List getNavigationBreadCrumb(int startlevel, int endlevel) { return getNavigationBreadCrumb(m_requestUriFolder, startlevel, endlevel, true); } /** * Build a "bread crumb" path navigation to the given folder.

* * The startlevel marks the point where the navigation starts from, if negative, * the count of steps to go down from the given folder.

* * The endlevel is the maximum level of the navigation path, set it to -1 to build the * complete navigation to the given folder.

* * You can include the given folder in the navigation by setting currentFolder to * true, otherwise false.

* * @param folder the selected folder * @param startlevel the start level, if negative, go down |n| steps from selected folder * @param endlevel the end level, if -1, build navigation to selected folder * @param currentFolder include the selected folder in navigation or not * * @return sorted list of navigation elements */ public List getNavigationBreadCrumb( String folder, int startlevel, int endlevel, boolean currentFolder) { List result = new ArrayList(); int level = CmsResource.getPathLevel(folder); // decrease folder level if current folder is not displayed if (!currentFolder) { level -= 1; } // check current level and change endlevel if it is higher or -1 if ((level < endlevel) || (endlevel == -1)) { endlevel = level; } // if startlevel is negative, display only |startlevel| links if (startlevel < 0) { startlevel = endlevel + startlevel + 1; if (startlevel < 0) { startlevel = 0; } } // create the list of navigation elements for (int i = startlevel; i <= endlevel; i++) { String navFolder = CmsResource.getPathPart(folder, i); CmsJspNavElement e = getNavigationForResource(navFolder); if (e != null) { // add element to list result.add(e); } } return result; } /** * Collect all navigation elements from the files of the folder of the current request URI.

* * @return a sorted (ascending to navigation position) list of navigation elements */ public List getNavigationForFolder() { return getNavigationForFolder(m_requestUriFolder); } /** * Build a navigation for the folder that is either minus levels up * from of the folder of the current request URI, or that is plus levels down from the * root folder towards the current request URI.

* * If level is set to zero the root folder is used by convention.

* * @param level if negative, walk this many levels up, if positive, walk this many * levels down from root folder * @return a sorted (ascending to navigation position) list of navigation elements */ public List getNavigationForFolder(int level) { return getNavigationForFolder(m_requestUriFolder, level); } /** * Collect all navigation visible elements from the files in the given folder.

* * @param folder the selected folder * * @return A sorted (ascending to navigation position) list of navigation elements */ public List getNavigationForFolder(String folder) { return getNavigationForFolder(folder, Visibility.navigation, CmsResourceFilter.DEFAULT); } /** * Build a navigation for the folder that is either minus levels up * from the given folder, or that is plus levels down from the * root folder towards the given folder.

* * If level is set to zero the root folder is used by convention.

* * @param folder the selected folder * @param level if negative, walk this many levels up, if positive, walk this many * levels down from root folder * * @return a sorted (ascending to navigation position) list of navigation elements */ public List getNavigationForFolder(String folder, int level) { folder = CmsResource.getFolderPath(folder); // If level is one just use root folder if (level == 0) { return getNavigationForFolder("/"); } String navfolder = CmsResource.getPathPart(folder, level); // If navigation folder found use it to build navigation if (navfolder != null) { return getNavigationForFolder(navfolder); } // Nothing found, return empty list return Collections. emptyList(); } /** * Collect all navigation elements from the files in the given folder.

* * @param folder the selected folder * @param visibility the visibility mode * @param resourceFilter the filter to use reading the resources * * @return A sorted (ascending to navigation position) list of navigation elements */ public List getNavigationForFolder( String folder, Visibility visibility, CmsResourceFilter resourceFilter) { folder = CmsFileUtil.removeTrailingSeparator(folder); List result = new ArrayList(); List resources = null; try { resources = m_cms.getResourcesInFolder(folder, resourceFilter); } catch (Exception e) { // should never happen LOG.error(e.getLocalizedMessage(), e); } if (resources == null) { return Collections. emptyList(); } boolean includeAll = visibility == Visibility.all; boolean includeHidden = visibility == Visibility.includeHidden; for (CmsResource r : resources) { CmsJspNavElement element = getNavigationForResource(m_cms.getSitePath(r), resourceFilter); if ((element != null) && (includeAll || (element.isInNavigation() && (includeHidden || !element.isHiddenNavigationEntry())))) { element.setNavContext(new NavContext(this, visibility, resourceFilter)); result.add(element); } } Collections.sort(result); return result; } /** * Returns a navigation element for the resource of the current request URI.

* * @return a navigation element for the resource of the current request URI */ public CmsJspNavElement getNavigationForResource() { return getNavigationForResource(m_requestUri); } /** * Returns a navigation element for the named resource.

* * @param sitePath the resource name to get the navigation information for, * must be a full path name, e.g. "/docs/index.html" * * @return a navigation element for the given resource */ public CmsJspNavElement getNavigationForResource(String sitePath) { CmsJspNavElement result = getNavigationForResource(sitePath, CmsResourceFilter.DEFAULT, false); if ((result != null) && (result.getNavContext() == null)) { result.setNavContext(new NavContext(this, Visibility.navigation, CmsResourceFilter.DEFAULT)); } return result; } /** * Returns a navigation element for the named resource.

* * @param sitePath the resource name to get the navigation information for, * must be a full path name, e.g. "/docs/index.html" * @param reourceFilter the resource filter * * @return a navigation element for the given resource */ public CmsJspNavElement getNavigationForResource(String sitePath, CmsResourceFilter reourceFilter) { return getNavigationForResource(sitePath, reourceFilter, false); } /** * Builds a tree navigation for the folders between the provided start and end level.

* * @param startlevel the start level * @param endlevel the end level * * @return a sorted list of navigation elements with the navigation tree level property set * * @see #getNavigationTreeForFolder(String, int, int) */ public List getNavigationTreeForFolder(int startlevel, int endlevel) { return getNavigationTreeForFolder(m_requestUriFolder, startlevel, endlevel); } /** * Builds a tree navigation for the folders between the provided start and end level.

* * @param folder the selected folder * @param startlevel the start level * @param endlevel the end level * * @return a sorted list of navigation elements with the navigation tree level property set */ public List getNavigationTreeForFolder(String folder, int startlevel, int endlevel) { folder = CmsResource.getFolderPath(folder); // Make sure start and end level make sense if (endlevel < startlevel) { return Collections. emptyList(); } int currentlevel = CmsResource.getPathLevel(folder); if (currentlevel < endlevel) { endlevel = currentlevel; } if (startlevel == endlevel) { return getNavigationForFolder(CmsResource.getPathPart(folder, startlevel), startlevel); } List result = new ArrayList(); float parentcount = 0; for (int i = startlevel; i <= endlevel; i++) { String currentfolder = CmsResource.getPathPart(folder, i); List entries = getNavigationForFolder(currentfolder); // Check for parent folder if (parentcount > 0) { for (CmsJspNavElement e : entries) { e.setNavPosition(e.getNavPosition() + parentcount); } } // Add new entries to result result.addAll(entries); Collections.sort(result); // Finally spread the values of the navigation items so that there is enough room for further items float pos = 0; int count = 0; String nextfolder = CmsResource.getPathPart(folder, i + 1); parentcount = 0; for (CmsJspNavElement e : result) { pos = 10000 * (++count); e.setNavPosition(pos); if (e.getResourceName().startsWith(nextfolder)) { parentcount = pos; } } if (parentcount == 0) { parentcount = pos; } } return result; } /** * This method builds a complete site navigation tree with entries of all branches.

* * @see #getSiteNavigation(String, int) * * @return list of navigation elements, in depth first order */ public List getSiteNavigation() { return getSiteNavigation("/", Visibility.navigation, -1); } /** * This method builds a complete navigation tree with entries of all branches * from the specified folder.

* * @param folder folder the root folder of the navigation tree * @param endLevel the end level of the navigation * * @return list of navigation elements, in depth first order */ public List getSiteNavigation(String folder, int endLevel) { return getSiteNavigation(folder, Visibility.navigation, endLevel); } /** * This method builds a complete navigation tree with entries of all branches * from the specified folder.

* * @param folder folder the root folder of the navigation tree * @param visibility controls whether entries hidden from navigation or not in navigation at all should be included * @param endLevel the end level of the navigation * * @return list of navigation elements, in depth first order */ public List getSiteNavigation(String folder, Visibility visibility, int endLevel) { folder = CmsFileUtil.addTrailingSeparator(folder); // check if a specific end level was given, if not, build the complete navigation boolean noLimit = false; if (endLevel < 0) { noLimit = true; } List list = new ArrayList(); // get the navigation for this folder List curnav = getNavigationForFolder(folder, visibility, CmsResourceFilter.DEFAULT); // loop through all navigation entries for (CmsJspNavElement ne : curnav) { // add the navigation entry to the result list list.add(ne); // check if navigation entry is a folder or navigation level and below the max level -> if so, get the navigation from this folder as well if ((ne.isFolderLink() || ne.isNavigationLevel()) && (noLimit || (ne.getNavTreeLevel() < endLevel))) { List subnav = getSiteNavigation( m_cms.getSitePath(ne.getResource()), visibility, endLevel); // copy the result of the subfolder to the result list list.addAll(subnav); } } return list; } /** * Initializes this bean.

* * @param cms the current cms context */ public void init(CmsObject cms) { init(cms, null, cms.getRequestContext().getUri()); } /** * Initializes this bean.

* * @param cms the current cms context * @param locale the locale for which properties should be read */ public void init(CmsObject cms, Locale locale) { init(cms, locale, cms.getRequestContext().getUri()); } /** * Initializes this bean.

* * @param cms the current cms context * @param locale the locale for which properties should be read * @param requestUri the request URI */ public void init(CmsObject cms, Locale locale, String requestUri) { m_cms = cms; m_locale = locale; m_requestUri = requestUri; m_requestUriFolder = CmsResource.getFolderPath(m_requestUri); } /** * Collect all navigation elements from the files in the given folder.

* * @param folder the selected folder * @param includeInvisible true to include elements not visible in navigation * @param resourceFilter the filter to use reading the resources * @param shallow true for a shallow look up, not regarding next level resources * * @return A sorted (ascending to navigation position) list of navigation elements */ private List getNavigationForFolder( String folder, boolean includeInvisible, CmsResourceFilter resourceFilter, boolean shallow) { folder = CmsResource.getFolderPath(folder); List result = new ArrayList(); List resources; try { resources = m_cms.getResourcesInFolder(folder, resourceFilter); } catch (Exception e) { // should never happen LOG.error(e.getLocalizedMessage(), e); return Collections. emptyList(); } for (CmsResource r : resources) { CmsJspNavElement element = getNavigationForResource(m_cms.getSitePath(r), resourceFilter, shallow); if ((element != null) && (includeInvisible || element.isInNavigation())) { result.add(element); } } Collections.sort(result); return result; } /** * Returns a navigation element for the named resource.

* * @param sitePath the resource name to get the navigation information for, * must be a full path name, e.g. "/docs/index.html" * @param resourceFilter the filter to use reading the resources * @param shallow true for a shallow look up, not regarding next level resources * * @return a navigation element for the given resource */ private CmsJspNavElement getNavigationForResource( String sitePath, CmsResourceFilter resourceFilter, boolean shallow) { CmsResource resource; Map propertiesMap; int level = CmsResource.getPathLevel(sitePath); if (sitePath.endsWith("/")) { level--; } try { resource = m_cms.readResource(sitePath, resourceFilter); List properties = m_cms.readPropertyObjects(resource, false); propertiesMap = CmsProperty.toMap(properties); if (resource.isFolder()) { if (resourceFilter.equals(CmsResourceFilter.DEFAULT) && !NAVIGATION_LEVEL_FOLDER.equals( propertiesMap.get(CmsPropertyDefinition.PROPERTY_DEFAULT_FILE))) { try { CmsResource defaultFile = m_cms.readDefaultFile(resource, resourceFilter); if ((defaultFile != null) && !defaultFile.isReleasedAndNotExpired(m_cms.getRequestContext().getRequestTime())) { // do not show navigation entries for unreleased or expired resources return null; } } catch (@SuppressWarnings("unused") CmsException e) { // may happen if permissions are not sufficient can be ignored } } if (!sitePath.endsWith("/")) { sitePath = sitePath + "/"; } if (!shallow && (NAVIGATION_LEVEL_FOLDER.equals( propertiesMap.get(CmsPropertyDefinition.PROPERTY_DEFAULT_FILE)))) { // this folder is marked as a navigation level, set the site path to the first sub element List subElements = getNavigationForFolder(sitePath, false, resourceFilter, true); if (!subElements.isEmpty()) { CmsJspNavElement subElement = subElements.get(0); subElement = getNavigationForResource(subElement.getSitePath(), resourceFilter, false); sitePath = subElement.getSitePath(); } } } } catch (Exception e) { // may happen if permissions are not sufficient LOG.warn(e.getLocalizedMessage(), e); return null; } return new CmsJspNavElement(sitePath, resource, propertiesMap, level, m_locale); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy