001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.jsp.util; 029 030import org.opencms.file.CmsObject; 031import org.opencms.file.CmsResource; 032import org.opencms.main.CmsException; 033import org.opencms.main.CmsLog; 034import org.opencms.relations.CmsCategory; 035import org.opencms.relations.CmsCategoryService; 036import org.opencms.util.CmsCollectionsGenericWrapper; 037 038import java.util.ArrayList; 039import java.util.Iterator; 040import java.util.List; 041import java.util.Map; 042import java.util.regex.Pattern; 043 044import org.apache.commons.collections.Transformer; 045import org.apache.commons.logging.Log; 046 047/** Bean for easy access to categories of a resource in JSPs. */ 048public class CmsJspCategoryAccessBean { 049 050 /** The log object for this class. */ 051 private static final Log LOG = CmsLog.getLog(CmsJspCategoryAccessBean.class); 052 053 /** The wrapped list of categories. */ 054 List<CmsCategory> m_categories; 055 056 /** The path of the main category. All categories of {@link #m_categories} are sub-categories of the main category. */ 057 String m_mainCategoryPath; 058 059 /** Map from the path of a main category to wrappers that hold only the sub-categories of that main category. */ 060 Map<String, CmsJspCategoryAccessBean> m_subCategories; 061 062 /** The CMS context to use. */ 063 private CmsObject m_cms; 064 065 /** 066 * Default constructor. 067 * 068 * @param cms the current {@link CmsObject}. 069 * @param resource the resource for which the categories should be read. 070 */ 071 public CmsJspCategoryAccessBean(CmsObject cms, CmsResource resource) { 072 this(cms, getCategories(cms, resource), ""); 073 } 074 075 /** 076 * Internal constructor for creating wrappers with a subset of the categories. 077 * 078 * @param cms the CMS context to use 079 * @param categories the original categories. 080 * @param mainCategoryPath path of the main category for which only sub-categories should be wrapped. 081 */ 082 CmsJspCategoryAccessBean(CmsObject cms, List<CmsCategory> categories, String mainCategoryPath) { 083 m_cms = cms; 084 m_mainCategoryPath = mainCategoryPath.isEmpty() || mainCategoryPath.endsWith("/") 085 ? mainCategoryPath 086 : mainCategoryPath + "/"; 087 088 if (m_mainCategoryPath.isEmpty()) { 089 m_categories = categories; 090 } else { 091 List<CmsCategory> filteredCategories = new ArrayList<CmsCategory>(); 092 for (CmsCategory category : categories) { 093 if (category.getPath().startsWith(m_mainCategoryPath) 094 && !category.getPath().equals(m_mainCategoryPath)) { 095 filteredCategories.add(category); 096 } 097 } 098 m_categories = filteredCategories; 099 } 100 m_categories = CmsCategoryService.getInstance().localizeCategories( 101 cms, 102 m_categories, 103 cms.getRequestContext().getLocale()); 104 } 105 106 /** 107 * Reads the categories for the given resource. 108 * 109 * @param cms the {@link CmsObject} used for reading the categories. 110 * @param resource the resource for which the categories should be read. 111 * @return the categories assigned to the given resource. 112 */ 113 private static List<CmsCategory> getCategories(CmsObject cms, CmsResource resource) { 114 115 if ((null != resource) && (null != cms)) { 116 try { 117 return CmsCategoryService.getInstance().readResourceCategories(cms, resource); 118 } catch (CmsException e) { 119 LOG.error(e.getLocalizedMessage(), e); 120 } 121 } 122 return new ArrayList<CmsCategory>(0); 123 } 124 125 /** 126 * Returns all wrapped categories. 127 * 128 * @return all wrapped categories. 129 */ 130 public List<CmsCategory> getAllItems() { 131 132 return m_categories; 133 } 134 135 /** 136 * Returns <code>true</code> if there is no category wrapped, otherwise <code>false</code>. 137 * 138 * @return <code>true</code> if there is no category wrapped, otherwise <code>false</code>. 139 */ 140 public boolean getIsEmpty() { 141 142 return m_categories.isEmpty(); 143 } 144 145 /** 146 * Returns only the leaf categories of the wrapped categories. 147 * 148 * The method assumes that categories are ordered in the list, i.e., parents are directly followed by their children. 149 * 150 * NOTE: In the complete category tree a leaf of the wrapped tree part may not be a leaf. 151 * 152 * @return only the leaf categories of the wrapped categories. 153 */ 154 public List<CmsCategory> getLeafItems() { 155 156 List<CmsCategory> result = new ArrayList<CmsCategory>(); 157 if (m_categories.isEmpty()) { 158 return result; 159 } 160 Iterator<CmsCategory> it = m_categories.iterator(); 161 CmsCategory current = it.next(); 162 while (it.hasNext()) { 163 CmsCategory next = it.next(); 164 if (!next.getPath().startsWith(current.getPath())) { 165 result.add(current); 166 } 167 current = next; 168 } 169 result.add(current); 170 return result; 171 } 172 173 /** 174 * Returns a map from a category path to the wrapper of all the sub-categories of the category with the path given as key. 175 * 176 * @return a map from a category path to all sub-categories of the path's category. 177 */ 178 public Map<String, CmsJspCategoryAccessBean> getSubCategories() { 179 180 if (m_subCategories == null) { 181 m_subCategories = CmsCollectionsGenericWrapper.createLazyMap(new Transformer() { 182 183 @SuppressWarnings("synthetic-access") 184 public Object transform(Object pathPrefix) { 185 186 return new CmsJspCategoryAccessBean(m_cms, m_categories, (String)pathPrefix); 187 } 188 189 }); 190 } 191 return m_subCategories; 192 } 193 194 /** 195 * Returns all categories that are direct children of the current main category. 196 * 197 * @return all categories that are direct children of the current main category. 198 */ 199 public List<CmsCategory> getTopItems() { 200 201 List<CmsCategory> categories = new ArrayList<CmsCategory>(); 202 String matcher = Pattern.quote(m_mainCategoryPath) + "[^/]*/"; 203 for (CmsCategory category : m_categories) { 204 if (category.getPath().matches(matcher)) { 205 categories.add(category); 206 } 207 } 208 return categories; 209 } 210}