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.configuration.formatters; 029 030import org.opencms.main.OpenCms; 031import org.opencms.util.CmsStringUtil; 032import org.opencms.util.CmsUUID; 033import org.opencms.xml.containerpage.CmsFunctionFormatterBean; 034import org.opencms.xml.containerpage.CmsXmlDynamicFunctionHandler; 035import org.opencms.xml.containerpage.I_CmsFormatterBean; 036 037import java.util.Collection; 038import java.util.HashMap; 039import java.util.HashSet; 040import java.util.Map; 041import java.util.Set; 042import java.util.regex.Pattern; 043 044/** 045 * This class represents the changes which can be made to formatters in a sitemap configuration file.<p> 046 */ 047public class CmsFormatterChangeSet implements Cloneable { 048 049 /** The prefix used for types in the Add/RemoveFormatter fields in the configuration. */ 050 public static final String PREFIX_TYPE = "type_"; 051 052 /** The debug path to identify the configuration where this is coming from. */ 053 @SuppressWarnings("unused") 054 private String m_debugPath; 055 056 /** The set of structure ids of added functions. */ 057 private Set<CmsUUID> m_functions; 058 059 /** Ids of functions to remove. */ 060 private Set<CmsUUID> m_functionsToRemove = new HashSet<>(); 061 062 /** The path pattern to match formatters accessible from the current site. */ 063 private Pattern m_pathPattern; 064 065 /** A flag, indicating if all formatters that are not explicitly added should be removed. */ 066 private boolean m_removeAllNonExplicitlyAdded; 067 068 /** True if functions are removed. */ 069 private boolean m_removeFunctions; 070 071 /** A map which indicates whether schema formatters for a type (which is the key) should be added (value=true) or removed (value=False). */ 072 private Map<String, Boolean> m_typeUpdateSet = new HashMap<String, Boolean>(); 073 074 /** A map which indicates whether a formatter (whose id is the key) should be added (value=true) or removed (value= false). */ 075 private Map<CmsUUID, Boolean> m_updateSet = new HashMap<CmsUUID, Boolean>(); 076 077 /** 078 * Creates an empty formatter change set.<p> 079 */ 080 public CmsFormatterChangeSet() { 081 082 // do nothing 083 } 084 085 /** 086 * Creates a new formatter change set.<p> 087 * 088 * @param toRemove the formatter keys to remove 089 * @param toAdd the formatter keys to add 090 * @param siteRoot the site root of the current config 091 * @param removeAllNonExplicitlyAdded flag, indicating if all formatters that are not explicitly added should be removed 092 * @param removeFunctions if true, all functions are removed 093 * @param functions the set of functions to enable 094 * @param functionsToRemove the set of functions to remove 095 */ 096 public CmsFormatterChangeSet( 097 Collection<String> toRemove, 098 Collection<String> toAdd, 099 String siteRoot, 100 boolean removeAllNonExplicitlyAdded, 101 boolean removeFunctions, 102 Set<CmsUUID> functions, 103 Set<CmsUUID> functionsToRemove) { 104 105 this(); 106 m_removeFunctions = removeFunctions; 107 m_functions = functions; 108 m_functionsToRemove = functionsToRemove != null ? functionsToRemove : new HashSet<>(); 109 110 initialize(toRemove, toAdd, siteRoot, removeAllNonExplicitlyAdded); 111 112 } 113 114 /** 115 * Produces the key for a given resource type.<p> 116 * 117 * @param typeName the resource type name 118 * @return the key to use 119 */ 120 public static String keyForType(String typeName) { 121 122 return "type_" + typeName; 123 } 124 125 /** 126 * Applies this change set to a list of external (non schema-based) formatters.<p> 127 * 128 * @param formatterIndex the collection of formatters on which this change set should operate 129 * @param externalFormatters the formatter collection which should be used to add formatters which are not already present in 'formatters' 130 */ 131 public void applyToFormatters( 132 CmsFormatterIndex formatterIndex, 133 CmsFormatterConfigurationCacheState externalFormatters) { 134 135 formatterIndex.removeIf(formatter -> { 136 if ((formatter instanceof CmsFunctionFormatterBean) && m_removeFunctions) { 137 return true; 138 } 139 if (!(formatter instanceof CmsFunctionFormatterBean) && m_removeAllNonExplicitlyAdded) { 140 return true; 141 } 142 return false; 143 144 }); 145 146 Map<CmsUUID, Boolean> updateSetWithFunctions = new HashMap<>(m_updateSet); 147 for (CmsUUID id : m_functionsToRemove) { 148 updateSetWithFunctions.put(id, Boolean.FALSE); 149 } 150 151 if (m_functions != null) { 152 for (CmsUUID id : m_functions) { 153 updateSetWithFunctions.put(id, Boolean.TRUE); 154 } 155 } 156 157 for (Map.Entry<CmsUUID, Boolean> updateEntry : updateSetWithFunctions.entrySet()) { 158 CmsUUID id = updateEntry.getKey(); 159 Boolean value = updateEntry.getValue(); 160 if (value.booleanValue()) { 161 I_CmsFormatterBean addedFormatter = externalFormatters.getFormatters().get(id); 162 if (addedFormatter != null) { 163 formatterIndex.addFormatter(addedFormatter); 164 } 165 } else { 166 formatterIndex.remove(id); 167 } 168 } 169 170 if (m_pathPattern != null) { 171 formatterIndex.removeIf(formatter -> { 172 String location = formatter.getLocation(); 173 return (location != null) && !m_pathPattern.matcher(location).matches(); 174 }); 175 } 176 } 177 178 /** 179 * Applies the changes (addition or removal of schema formatters) to a set of resource type names, 180 * adding resource types for which schema formatters should be added and removing those for which 181 * schema formatters should be removed.<p> 182 * 183 * @param types the set of types to apply the changes to 184 */ 185 public void applyToTypes(Set<String> types) { 186 187 if (m_removeAllNonExplicitlyAdded) { 188 types.removeIf(type -> !CmsXmlDynamicFunctionHandler.TYPE_FUNCTION.equals(type)); 189 } 190 for (Map.Entry<String, Boolean> typeUpdateEntry : m_typeUpdateSet.entrySet()) { 191 String typeName = typeUpdateEntry.getKey(); 192 Boolean add = typeUpdateEntry.getValue(); 193 if (add.booleanValue()) { 194 types.add(typeName); 195 } else { 196 types.remove(typeName); 197 } 198 } 199 } 200 201 /** 202 * Creates a clone of this object, but with the 'remove all functions/formatters' flags set to false. 203 * 204 * @return a clone which disables removall of all functions/formatters 205 */ 206 public CmsFormatterChangeSet cloneWithNoRemovals() { 207 208 try { 209 CmsFormatterChangeSet result = (CmsFormatterChangeSet)clone(); 210 result.m_removeAllNonExplicitlyAdded = false; 211 result.m_removeFunctions = false; 212 return result; 213 } catch (CloneNotSupportedException e) { 214 return null; 215 } 216 217 } 218 219 /** 220 * Sets the debug path. 221 * 222 * @param debugPath the debug path 223 */ 224 public void setDebugPath(String debugPath) { 225 226 m_debugPath = debugPath; 227 } 228 229 /** 230 * Initializes this formatter change set with the values from the sitemap configuration.<p> 231 * 232 * @param toRemove the keys for the formatters to remove 233 * @param toAdd the keys for the formatters to add 234 * @param siteRoot the site root of the current config 235 * @param removeAllNonExplicitlyAdded flag, indicating if all formatters that are not explicitly added should be removed 236 */ 237 private void initialize( 238 Collection<String> toRemove, 239 Collection<String> toAdd, 240 String siteRoot, 241 boolean removeAllNonExplicitlyAdded) { 242 243 m_removeAllNonExplicitlyAdded = removeAllNonExplicitlyAdded; 244 245 for (String removeKey : toRemove) { 246 if (CmsUUID.isValidUUID(removeKey)) { 247 m_updateSet.put(new CmsUUID(removeKey), Boolean.FALSE); 248 } else if (removeKey.startsWith(PREFIX_TYPE)) { 249 m_typeUpdateSet.put(removePrefix(removeKey), Boolean.FALSE); 250 } 251 } 252 for (String addKey : toAdd) { 253 if (CmsUUID.isValidUUID(addKey)) { 254 m_updateSet.put(new CmsUUID(addKey), Boolean.TRUE); 255 } else if (addKey.startsWith(PREFIX_TYPE)) { 256 m_typeUpdateSet.put(removePrefix(addKey), Boolean.TRUE); 257 } 258 } 259 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(siteRoot)) { 260 if (!siteRoot.endsWith("/")) { 261 siteRoot += "/"; 262 } 263 String regex = "^(/system/|" + OpenCms.getSiteManager().getSharedFolder() + "|" + siteRoot + ").*"; 264 265 m_pathPattern = Pattern.compile(regex); 266 } 267 } 268 269 /** 270 * Removes a prefix from the given key.<p> 271 * 272 * @param key the key 273 * 274 * @return the key with the prefix removed 275 */ 276 private String removePrefix(String key) { 277 278 if (key.startsWith(PREFIX_TYPE)) { 279 return key.substring(PREFIX_TYPE.length()); 280 } 281 return key; 282 } 283 284}