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.xml.templatemapper; 029 030import org.opencms.ade.containerpage.shared.CmsFormatterConfig; 031import org.opencms.cache.CmsVfsMemoryObjectCache; 032import org.opencms.file.CmsFile; 033import org.opencms.file.CmsObject; 034import org.opencms.file.CmsResourceFilter; 035import org.opencms.gwt.shared.CmsTemplateContextInfo; 036import org.opencms.loader.CmsTemplateContext; 037import org.opencms.loader.CmsTemplateContextManager; 038import org.opencms.loader.I_CmsTemplateContextProvider; 039import org.opencms.main.CmsException; 040import org.opencms.main.CmsLog; 041import org.opencms.main.OpenCms; 042import org.opencms.util.CmsUUID; 043import org.opencms.xml.containerpage.CmsContainerBean; 044import org.opencms.xml.containerpage.CmsContainerElementBean; 045import org.opencms.xml.containerpage.CmsContainerPageBean; 046import org.opencms.xml.containerpage.CmsGroupContainerBean; 047 048import java.io.ByteArrayInputStream; 049import java.util.ArrayList; 050import java.util.HashMap; 051import java.util.HashSet; 052import java.util.List; 053import java.util.Map; 054import java.util.Set; 055 056import javax.servlet.ServletRequest; 057 058import org.apache.commons.collections.Transformer; 059import org.apache.commons.logging.Log; 060 061import org.dom4j.Document; 062import org.dom4j.io.SAXReader; 063 064/** 065 * Responsible for mapping formatters, containers and settings to different formatters, containers and settings according to 066 * the configuration file /system/config/template-mapping.xml.<p> 067 * 068 */ 069public final class CmsTemplateMapper { 070 071 /** The logger instance for this class. */ 072 static final Log LOG = CmsLog.getLog(CmsTemplateMapper.class); 073 074 /** Flag which controls whether this is enabled. */ 075 protected boolean m_enabled; 076 077 /** The path to the mapper configuration. */ 078 protected String m_configPath; 079 080 /** Flag to enable mode for saving. */ 081 private boolean m_forSave; 082 083 /** 084 * Creates a new instance.<p> 085 * 086 * @param configPath the template mapper configuration VFS path 087 */ 088 public CmsTemplateMapper(String configPath) { 089 090 if (configPath != null) { 091 m_enabled = true; 092 m_configPath = configPath; 093 } else { 094 m_enabled = false; 095 } 096 } 097 098 /** 099 * Hidden default constructor, because this is a singleton.<p> 100 */ 101 private CmsTemplateMapper() { 102 103 m_enabled = true; 104 } 105 106 /** 107 * Gets a template mapper. 108 * 109 * @return a template mapper 110 */ 111 public static CmsTemplateMapper get() { 112 113 return new CmsTemplateMapper(); 114 } 115 116 /** 117 * Gets the template mapper for the current request.<p> 118 * 119 * @param request the current request 120 * 121 * @return the template mapper 122 */ 123 public static CmsTemplateMapper get(ServletRequest request) { 124 125 return new CmsTemplateMapper(getTemplateMapperConfig(request)); 126 } 127 128 /** 129 * Checks if the selected template context is "templatemapper". 130 * 131 * @param request the current request 132 * @return true if the selected template context is "templatemapper" 133 */ 134 public static String getTemplateMapperConfig(ServletRequest request) { 135 136 String result = null; 137 CmsTemplateContext templateContext = (CmsTemplateContext)request.getAttribute( 138 CmsTemplateContextManager.ATTR_TEMPLATE_CONTEXT); 139 if (templateContext != null) { 140 I_CmsTemplateContextProvider provider = templateContext.getProvider(); 141 if (provider instanceof I_CmsTemplateMappingContextProvider) { 142 result = ((I_CmsTemplateMappingContextProvider)provider).getMappingConfigurationPath( 143 templateContext.getKey()); 144 } 145 } 146 return result; 147 } 148 149 /** 150 * Sets the for-save mode.<p> 151 * 152 * @param forSave true if for-save mode should be enabled 153 */ 154 public void setForSave(boolean forSave) { 155 156 m_forSave = forSave; 157 } 158 159 /** 160 * Transforms a container page bean.<p> 161 * 162 * @param cms the current CMS context 163 * @param input the bean to be transformed 164 * @param rootPath the root path of the page 165 * 166 * @return the transformed bean 167 */ 168 public CmsContainerPageBean transformContainerpageBean(CmsObject cms, CmsContainerPageBean input, String rootPath) { 169 170 CmsTemplateMapperConfiguration config = getConfiguration(cms); 171 if ((config == null) || !config.isEnabledForPath(rootPath)) { 172 return input; 173 } 174 List<CmsContainerBean> newContainers = new ArrayList<>(); 175 for (CmsContainerBean container : input.getContainers().values()) { 176 List<CmsContainerElementBean> elements = container.getElements(); 177 List<CmsContainerElementBean> newElements = new ArrayList<>(); 178 for (CmsContainerElementBean element : elements) { 179 CmsContainerElementBean newElement = transformContainerElement(cms, config, element); 180 if (newElement != null) { 181 newElements.add(newElement); 182 } 183 } 184 CmsContainerBean newContainer = new CmsContainerBean( 185 container.getName(), 186 container.getType(), 187 container.getParentInstanceId(), 188 container.isRootContainer(), 189 newElements); 190 newContainers.add(newContainer); 191 } 192 CmsContainerPageBean result = new CmsContainerPageBean(newContainers); 193 return result; 194 } 195 196 /** 197 * Transforms a container element bean used for detail elements.<p> 198 * 199 * @param cms the current CMS context 200 * @param input the bean to be transformed 201 * @param rootPath the root path of the page 202 * 203 * @return the transformed bean 204 */ 205 public CmsContainerElementBean transformDetailElement( 206 CmsObject cms, 207 CmsContainerElementBean input, 208 String rootPath) { 209 210 CmsTemplateMapperConfiguration config = getConfiguration(cms); 211 if ((config == null) || !config.isEnabledForPath(rootPath)) { 212 return input; 213 } 214 return transformContainerElement(cms, config, input); 215 216 } 217 218 /** 219 * Transforms a group container bean.<p> 220 * 221 * @param cms the current CMS context 222 * @param input the input bean to be transformed 223 * @param rootPath the root path of the container page 224 * 225 * @return the transformed bean 226 */ 227 public CmsGroupContainerBean transformGroupContainer(CmsObject cms, CmsGroupContainerBean input, String rootPath) { 228 229 CmsTemplateMapperConfiguration config = getConfiguration(cms); 230 if ((config == null) || !config.isEnabledForPath(rootPath)) { 231 return input; 232 } 233 List<CmsContainerElementBean> newElements = new ArrayList<>(); 234 for (CmsContainerElementBean element : input.getElements()) { 235 CmsContainerElementBean newElement = transformContainerElement(cms, config, element); 236 if (newElement != null) { 237 newElements.add(newElement); 238 } 239 } 240 Set<String> transformedTypes = new HashSet<>(); 241 Set<String> oldTypes = input.getTypes(); 242 if (oldTypes == null) { 243 oldTypes = new HashSet<>(); 244 } 245 for (String type : oldTypes) { 246 String newType = config.getMappedElementGroupType(type); 247 if (newType == null) { 248 newType = type; 249 } 250 transformedTypes.add(newType); 251 } 252 253 CmsGroupContainerBean result = new CmsGroupContainerBean( 254 input.getTitle(), 255 input.getDescription(), 256 newElements, 257 transformedTypes); 258 return result; 259 } 260 261 /** 262 * Helper method to transform a single container element.<p> 263 * @param cms the CMS context 264 * @param config the configuration 265 * @param element the container element to be transformed 266 * 267 * @return the transformed bean 268 */ 269 protected CmsContainerElementBean transformContainerElement( 270 CmsObject cms, 271 CmsTemplateMapperConfiguration config, 272 CmsContainerElementBean element) { 273 274 if (m_forSave) { 275 try { 276 element.initResource(cms); 277 } catch (Exception e) { 278 LOG.error(e.getLocalizedMessage(), e); 279 return null; 280 } 281 } 282 Map<String, String> settings = element.getIndividualSettings(); 283 if (settings == null) { 284 settings = new HashMap<>(); 285 } 286 Map<String, String> newSettings = new HashMap<>(); 287 for (Map.Entry<String, String> entry : settings.entrySet()) { 288 String key = entry.getKey(); 289 if (CmsTemplateContextInfo.SETTING.equals(key)) { 290 continue; 291 } 292 String value = entry.getValue(); 293 if (value == null) { 294 continue; 295 } 296 String newValue = value; 297 if (key.startsWith(CmsFormatterConfig.FORMATTER_SETTINGS_KEY)) { 298 if (CmsUUID.isValidUUID(value)) { 299 String newId = config.getMappedFormatterConfiguration(value); 300 if (newId != null) { 301 newValue = newId; 302 } 303 } else if (value.startsWith(CmsFormatterConfig.SCHEMA_FORMATTER_ID)) { 304 String schemaFormatterIdStr = value.substring(CmsFormatterConfig.SCHEMA_FORMATTER_ID.length()); 305 if (CmsUUID.isValidUUID(schemaFormatterIdStr)) { 306 CmsUUID schemaFormatterId = new CmsUUID(schemaFormatterIdStr); 307 CmsUUID mappedFormatterId = config.getMappedFormatterJspId(schemaFormatterId); 308 if (mappedFormatterId != null) { 309 newValue = CmsFormatterConfig.SCHEMA_FORMATTER_ID + mappedFormatterId; 310 } 311 } 312 } 313 } 314 newSettings.put(key, newValue); 315 } 316 CmsContainerElementBean newElement = element.clone(); 317 newElement.updateIndividualSettings(newSettings); 318 CmsUUID formatterId = element.getFormatterId(); 319 if ((formatterId == null) && m_forSave) { 320 try { 321 if (element.isGroupContainer(cms)) { 322 // ID for group-container.jsp 323 formatterId = new CmsUUID("e7029fa2-761e-11e0-bd7f-9ffeadaf4d46"); 324 newElement.setFormatterId(formatterId); 325 } else if (OpenCms.getResourceManager().matchResourceType( 326 "function", 327 element.getResource().getTypeId())) { 328 formatterId = new CmsUUID("087ba7c9-e7fc-4336-acb8-d3416a4eb1fd"); 329 newElement.setFormatterId(formatterId); 330 } 331 } catch (CmsException e) { 332 LOG.warn(e.getLocalizedMessage(), e); 333 } 334 } 335 CmsUUID mappedFormatterJspId = config.getMappedFormatterJspId(formatterId); 336 if (mappedFormatterJspId != null) { 337 newElement.setFormatterId(mappedFormatterJspId); 338 } 339 return newElement; 340 } 341 342 /** 343 * Loads the configuration file, using CmsVfsMemoryObjectCache for caching. 344 * 345 * @param cms the CMS context 346 * @return the template mapper configuration 347 */ 348 private CmsTemplateMapperConfiguration getConfiguration(final CmsObject cms) { 349 350 if (!m_enabled) { 351 return CmsTemplateMapperConfiguration.EMPTY_CONFIG; 352 } 353 354 if (m_configPath == null) { 355 m_configPath = OpenCms.getSystemInfo().getConfigFilePath(cms, "template-mapping.xml"); 356 } 357 358 return (CmsTemplateMapperConfiguration)(CmsVfsMemoryObjectCache.getVfsMemoryObjectCache().loadVfsObject( 359 cms, 360 m_configPath, 361 new Transformer() { 362 363 @Override 364 public Object transform(Object input) { 365 366 try { 367 CmsFile file = cms.readFile(m_configPath, CmsResourceFilter.IGNORE_EXPIRATION); 368 SAXReader saxBuilder = new SAXReader(); 369 try (ByteArrayInputStream stream = new ByteArrayInputStream(file.getContents())) { 370 Document document = saxBuilder.read(stream); 371 CmsTemplateMapperConfiguration config = new CmsTemplateMapperConfiguration(cms, document); 372 return config; 373 } 374 } catch (Exception e) { 375 LOG.warn(e.getLocalizedMessage(), e); 376 return new CmsTemplateMapperConfiguration(); // empty configuration, does not do anything 377 } 378 379 } 380 })); 381 } 382 383}