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.ade.galleries; 029 030import org.opencms.file.CmsObject; 031import org.opencms.file.CmsResource; 032import org.opencms.file.CmsResourceFilter; 033import org.opencms.file.CmsVfsResourceNotFoundException; 034import org.opencms.main.CmsLog; 035import org.opencms.main.OpenCms; 036import org.opencms.search.galleries.CmsGallerySearch; 037import org.opencms.search.galleries.CmsGallerySearchResult; 038import org.opencms.security.CmsSecurityException; 039import org.opencms.util.CmsMacroResolver; 040import org.opencms.util.CmsUUID; 041import org.opencms.xml.content.I_CmsXmlContentLocation; 042import org.opencms.xml.content.I_CmsXmlContentValueLocation; 043import org.opencms.xml.types.CmsXmlVfsFileValue; 044 045import java.util.ArrayList; 046import java.util.Collection; 047import java.util.Collections; 048import java.util.HashMap; 049import java.util.List; 050import java.util.Locale; 051import java.util.Map; 052import java.util.Set; 053 054import org.apache.commons.logging.Log; 055 056/** 057 * Replacement configuration for the 'add content' dialog. 058 * 059 * <p>A replacement configuration contains a list of entries, one for each type, 060 * with a list of resources for each type and optionally a title string for each of the resources. 061 * The list of resources replaces the search results that would be normally shown for the type 062 * in the 'add content' dialog. 063 */ 064public class CmsAddContentRestriction { 065 066 /** 067 * Contains the replacements (and titles of the replacements) for a single type. 068 */ 069 public static class TypeEntry { 070 071 /** The location from which this entry was read. */ 072 private String m_origin; 073 074 /** The replacement titles for the search results, with the corresponding structure ids as keys. */ 075 private Map<CmsUUID, String> m_replacedTitles = new HashMap<>(); 076 077 /** The resources to replace the search result for the configured type with. */ 078 private List<CmsResource> m_resources = new ArrayList<>(); 079 080 /** The name of the resource type. */ 081 private String m_type; 082 083 /** 084 * Creates a new entry. 085 * 086 * @param type the name of the resource type 087 * @param resources the resources to use as a replacement 088 * @param titleReplacements a map from structure ids to replacement titles for those 089 * @param origin the place from which this entry was read 090 */ 091 public TypeEntry( 092 String type, 093 List<CmsResource> resources, 094 Map<CmsUUID, String> titleReplacements, 095 String origin) { 096 097 m_type = type; 098 m_resources = new ArrayList<>(resources); 099 m_replacedTitles = new HashMap<>(titleReplacements); 100 m_origin = origin; 101 } 102 103 /** 104 * Gets the location from which this entry was read. 105 * 106 * @return the location from which the entry was read 107 */ 108 public String getOrigin() { 109 110 return m_origin; 111 } 112 113 /** 114 * Gets the results to be displayed in the 'add content' dialog. 115 * 116 * @param cms the CMS context 117 * @return the results to display 118 */ 119 @SuppressWarnings("synthetic-access") 120 public List<CmsGallerySearchResult> getResults(CmsObject cms) { 121 122 List<CmsGallerySearchResult> result = new ArrayList<>(); 123 Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms); 124 CmsMacroResolver macroResolver = new CmsMacroResolver(); 125 macroResolver.setCmsObject(cms); 126 macroResolver.setMessages(OpenCms.getWorkplaceManager().getMessages(locale)); 127 128 for (CmsResource res : m_resources) { 129 try { 130 // Read resources again because the user may not be allowed to access them, 131 // or they may have been moved since the replacement configuration was read 132 CmsResource currentRes = cms.readResource( 133 res.getStructureId(), 134 CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 135 136 CmsGallerySearchResult singleResult = CmsGallerySearch.searchById( 137 cms, 138 res.getStructureId(), 139 locale); 140 String replacementTitle = m_replacedTitles.get(currentRes.getStructureId()); 141 if (replacementTitle != null) { 142 replacementTitle = macroResolver.resolveMacros(replacementTitle); 143 singleResult = singleResult.withTitle(replacementTitle); 144 } 145 result.add(singleResult); 146 } catch (CmsVfsResourceNotFoundException | CmsSecurityException e) { 147 LOG.debug("filtered resource " + res.getRootPath() + " (" + res.getStructureId() + ")"); 148 } catch (Exception e) { 149 LOG.error(e.getLocalizedMessage(), e); 150 } 151 } 152 return result; 153 } 154 155 /** 156 * Gets the type. 157 * 158 * @return the type 159 */ 160 public String getType() { 161 162 return m_type; 163 } 164 } 165 166 /** Empty configuration. */ 167 public static final CmsAddContentRestriction EMPTY = new CmsAddContentRestriction(); 168 169 /** XML node name. */ 170 public static final String N_ENTRY = "Entry"; 171 172 /** XML node name. */ 173 public static final String N_RESOURCE = "Resource"; 174 175 /** XML node name. */ 176 public static final String N_TITLE = "Title"; 177 178 /** XML node name. */ 179 public static final String N_TYPE = "Type"; 180 181 /** The name of the resource type from which the configuration is read. */ 182 public static final String TYPE_NAME = "add_content_replacement"; 183 184 /** Logger instance for this class. */ 185 private static final Log LOG = CmsLog.getLog(CmsAddContentRestriction.class); 186 187 /** The configuration entries, with their types as keys. */ 188 private Map<String, TypeEntry> m_entries = new HashMap<>(); 189 190 /** 191 * Creates a new configuration from a list of entries. 192 * 193 * @param entries the list of configuration entries 194 */ 195 public CmsAddContentRestriction(Collection<TypeEntry> entries) { 196 197 for (TypeEntry replacer : entries) { 198 m_entries.put(replacer.getType(), replacer); 199 } 200 } 201 202 /** 203 * Creates an empty configuration where nothing is replaced. 204 */ 205 private CmsAddContentRestriction() { 206 207 // do nothing 208 } 209 210 /** 211 * Reads a content restriction from an XML content. 212 * 213 * @param cms the CMS context 214 * @param parent the parent location 215 * @param nodeName the name of the XML elements containing the content restrictions 216 * 217 * @return the content restriction 218 */ 219 public static CmsAddContentRestriction read(CmsObject cms, I_CmsXmlContentLocation parent, String nodeName) { 220 221 List<TypeEntry> entries = new ArrayList<>(); 222 for (I_CmsXmlContentValueLocation entryLoc : parent.getSubValues(nodeName)) { 223 TypeEntry entry = readEntry(cms, entryLoc); 224 entries.add(entry); 225 } 226 return new CmsAddContentRestriction(entries); 227 228 } 229 230 /** 231 * Reads the entry for a single type from the configuration. 232 * 233 * @param cms the CMS context 234 * @param location the location from which to read the entry 235 * 236 * @return the entry that was read 237 */ 238 public static TypeEntry readEntry(CmsObject cms, I_CmsXmlContentValueLocation location) { 239 240 String type = location.getSubValue(N_TYPE).getValue().getStringValue(cms).trim(); 241 Map<CmsUUID, String> titleMap = new HashMap<>(); 242 List<CmsResource> resourceList = new ArrayList<>(); 243 for (I_CmsXmlContentValueLocation entryLoc : location.getSubValues(N_ENTRY)) { 244 CmsXmlVfsFileValue resoureValue = (CmsXmlVfsFileValue)(entryLoc.getSubValue(N_RESOURCE).getValue()); 245 CmsResource resource = resoureValue.getLink(cms).getResource(); 246 if (resource != null) { 247 resourceList.add(resource); 248 I_CmsXmlContentValueLocation titleLoc = entryLoc.getSubValue(N_TITLE); 249 if (titleLoc != null) { 250 String title = titleLoc.getValue().getStringValue(cms); 251 titleMap.put(resource.getStructureId(), title); 252 } 253 } 254 } 255 return new TypeEntry(type, resourceList, titleMap, location.getValue().getDocument().getFile().getRootPath()); 256 } 257 258 /** 259 * Gets the replaced results for a specific resource type. 260 * 261 * @param cms the CMS context 262 * @param type the type name 263 * 264 * @return the replacement results for the given type 265 */ 266 public List<CmsGallerySearchResult> getResult(CmsObject cms, String type) { 267 268 TypeEntry replacer = m_entries.get(type); 269 if (replacer == null) { 270 return null; 271 } 272 return replacer.getResults(cms); 273 } 274 275 /** 276 * Gets the set of names of types for which the search results are replaced. 277 * 278 * @return the set of types for which there are replacements configured 279 */ 280 public Set<String> getTypes() { 281 282 return Collections.unmodifiableSet(m_entries.keySet()); 283 } 284 285 /** 286 * Merges this configuration and a child configuration into a new configuration object, where an entry for a type in the child 287 * overrides an entry for the same type in the parent. 288 * 289 * @param child the child configuration 290 * @return the merged configuration 291 */ 292 public CmsAddContentRestriction merge(CmsAddContentRestriction child) { 293 294 Map<String, TypeEntry> combinedMap = new HashMap<>(); 295 combinedMap.putAll(m_entries); 296 combinedMap.putAll(child.m_entries); 297 return new CmsAddContentRestriction(combinedMap.values()); 298 299 } 300 301}