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 GmbH & Co. KG, 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; 029 030import org.opencms.cache.CmsVfsMemoryObjectCache; 031import org.opencms.file.CmsFile; 032import org.opencms.file.CmsObject; 033import org.opencms.i18n.CmsMessages; 034import org.opencms.main.CmsException; 035import org.opencms.main.CmsLog; 036import org.opencms.main.OpenCms; 037import org.opencms.util.CmsMacroResolver; 038import org.opencms.util.CmsStringUtil; 039import org.opencms.xml.content.CmsXmlContent; 040import org.opencms.xml.content.CmsXmlContentFactory; 041 042import java.util.Locale; 043 044import org.apache.commons.logging.Log; 045 046/** 047 * The xml messages overwrite some methods of the general CmsMessages class to get keys from an individual configuration file.<p> 048 * 049 * As fallback if no file was specified or no value was found for the desired key, 050 * a common CmsMessages object is used to get the localized value.<p> 051 * 052 * @since 6.5.4 053 */ 054public class CmsXmlMessages extends CmsMessages { 055 056 /** The log object for this class. */ 057 private static final Log LOG = CmsLog.getLog(CmsXmlMessages.class); 058 059 /** The locale to use for getting localized String values. */ 060 private Locale m_locale; 061 062 /** The content holding the localized values. */ 063 private CmsXmlContent m_localizationContent; 064 065 /** The initialized messages used as fallback if no value was found in the configuration file. */ 066 private CmsMessages m_messages; 067 068 /** The (optional) xPath prefix to the element nodes. */ 069 private String m_pathPrefix; 070 071 /** 072 * Constructor, with parameters.<p> 073 * 074 * Creates the necessary member objects using the passed arguments.<p> 075 * 076 * @param messages the messages object to use as fallback 077 * @param configurationFileName the absolute path (including site root!) to the configuration file containing localized keys 078 * @param pathPrefix the (optional) xPath prefix to the element nodes 079 * @param locale the locale to use for localization 080 */ 081 public CmsXmlMessages(CmsMessages messages, String configurationFileName, String pathPrefix, Locale locale) { 082 083 m_messages = messages; 084 initLocalizationContent(configurationFileName); 085 initPathPrefix(pathPrefix); 086 m_locale = locale; 087 } 088 089 /** 090 * Constructor, with parameters.<p> 091 * 092 * Creates the necessary member objects using the passed arguments.<p> 093 * 094 * @param bundleName the name of the ResourceBundle to use 095 * @param configurationFileName the absolute path (including site root!) to the configuration file containing localized keys 096 * @param pathPrefix the (optional) xPath prefix to the element nodes 097 * @param locale the locale to use for localization 098 */ 099 public CmsXmlMessages(String bundleName, String configurationFileName, String pathPrefix, Locale locale) { 100 101 m_messages = new CmsMessages(bundleName, locale); 102 initLocalizationContent(configurationFileName); 103 initPathPrefix(pathPrefix); 104 m_locale = locale; 105 } 106 107 /** 108 * Returns the messages.<p> 109 * 110 * @return the messages 111 */ 112 public CmsMessages getMessages() { 113 114 return m_messages; 115 } 116 117 /** 118 * Returns the localized resource String from the configuration file, if not found or set from the resource bundle.<p> 119 * 120 * @see org.opencms.i18n.CmsMessages#key(java.lang.String) 121 */ 122 @Override 123 public String key(String keyName) { 124 125 if (hasConfigValue(keyName)) { 126 return getConfigValue(keyName); 127 } 128 return m_messages.key(keyName); 129 } 130 131 /** 132 * Returns the localized resource String from the configuration file, if not found or set from the resource bundle.<p> 133 * 134 * @see org.opencms.i18n.CmsMessages#key(java.lang.String, java.lang.Object) 135 */ 136 @Override 137 public String key(String key, Object arg0) { 138 139 if (hasConfigValue(key)) { 140 return getConfigValue(key, new Object[] {arg0}); 141 } 142 return m_messages.key(key, arg0); 143 } 144 145 /** 146 * Returns the localized resource String from the configuration file, if not found or set from the resource bundle.<p> 147 * 148 * @see org.opencms.i18n.CmsMessages#key(java.lang.String, java.lang.Object, java.lang.Object) 149 */ 150 @Override 151 public String key(String key, Object arg0, Object arg1) { 152 153 if (hasConfigValue(key)) { 154 return getConfigValue(key, new Object[] {arg0, arg1}); 155 } 156 return m_messages.key(key, arg0, arg1); 157 } 158 159 /** 160 * Returns the localized resource String from the configuration file, if not found or set from the resource bundle.<p> 161 * 162 * @see org.opencms.i18n.CmsMessages#key(java.lang.String, java.lang.Object, java.lang.Object, java.lang.Object) 163 */ 164 @Override 165 public String key(String key, Object arg0, Object arg1, Object arg2) { 166 167 if (hasConfigValue(key)) { 168 return getConfigValue(key, new Object[] {arg0, arg1, arg2}); 169 } 170 return m_messages.key(key, arg0, arg1, arg2); 171 } 172 173 /** 174 * Returns the localized resource String from the configuration file, if not found or set from the resource bundle.<p> 175 * 176 * @see org.opencms.i18n.CmsMessages#key(java.lang.String, java.lang.Object[]) 177 */ 178 @Override 179 public String key(String key, Object[] args) { 180 181 if (hasConfigValue(key)) { 182 return getConfigValue(key, args); 183 } 184 return m_messages.key(key, args); 185 } 186 187 /** 188 * Returns the localized resource String from the configuration file, if not found or set from the resource bundle.<p> 189 * 190 * @see org.opencms.i18n.CmsMessages#keyDefault(java.lang.String, java.lang.String) 191 */ 192 @Override 193 public String keyDefault(String keyName, String defaultValue) { 194 195 if (hasConfigValue(keyName)) { 196 return getConfigValue(keyName); 197 } 198 return m_messages.keyDefault(keyName, defaultValue); 199 } 200 201 /** 202 * Sets the messages.<p> 203 * 204 * @param messages the messages 205 */ 206 public void setMessages(CmsMessages messages) { 207 208 m_messages = messages; 209 } 210 211 /** 212 * Returns the value for the given key from the configuration file.<p> 213 * @param key the key to get the value for 214 * @return the value for the given key 215 */ 216 protected String getConfigValue(String key) { 217 218 if (m_localizationContent != null) { 219 try { 220 return m_localizationContent.getStringValue(null, m_pathPrefix + key, m_locale); 221 } catch (NullPointerException e) { 222 // a cms object is needed, log this error 223 if (LOG.isErrorEnabled()) { 224 LOG.error(Messages.get().getBundle().key(Messages.ERR_NULL_CMSOBJECT_0)); 225 } 226 } 227 } 228 return null; 229 } 230 231 /** 232 * Returns the substituted value for the given key and arguments from the configuration file.<p> 233 * 234 * @param key the key to get the value for 235 * @param args the arguments that should be substituted 236 * @return the substituted value for the given key and arguments 237 */ 238 protected String getConfigValue(String key, Object[] args) { 239 240 String value = getConfigValue(key); 241 CmsMacroResolver resolver = CmsMacroResolver.newInstance(); 242 for (int i = 0; i < args.length; i++) { 243 resolver.addMacro(String.valueOf(i), args[i].toString()); 244 } 245 return resolver.resolveMacros(value); 246 } 247 248 /** 249 * Checks if the given key is provided in the configuration file.<p> 250 * 251 * @param key the key to check 252 * @return true if the given key is provided in the configuration file, otherwise false 253 */ 254 protected boolean hasConfigValue(String key) { 255 256 return CmsStringUtil.isNotEmptyOrWhitespaceOnly(getConfigValue(key)); 257 } 258 259 /** 260 * Initializes the content used for localizing the output.<p> 261 * 262 * @param configurationFileName the absolute path including site root to the configuration file containing localized keys 263 */ 264 protected void initLocalizationContent(String configurationFileName) { 265 266 CmsObject cms = null; 267 try { 268 // this will always be in the root site 269 cms = OpenCms.initCmsObject(OpenCms.getDefaultUsers().getUserGuest()); 270 } catch (CmsException e) { 271 // error initializing cms object, log error 272 if (LOG.isErrorEnabled()) { 273 LOG.error( 274 Messages.get().getBundle().key( 275 Messages.ERR_INVALID_INIT_USER_1, 276 OpenCms.getDefaultUsers().getUserGuest())); 277 } 278 } 279 if ((cms != null) && CmsStringUtil.isNotEmptyOrWhitespaceOnly(configurationFileName)) { 280 // try to get XML content from cache 281 Object o = CmsVfsMemoryObjectCache.getVfsMemoryObjectCache().getCachedObject(cms, configurationFileName); 282 if (o != null) { 283 // found the cached XML content, use it 284 m_localizationContent = (CmsXmlContent)o; 285 return; 286 } 287 try { 288 CmsFile configFile = cms.readFile(configurationFileName); 289 m_localizationContent = CmsXmlContentFactory.unmarshal(cms, configFile); 290 // store unmarshaled content in cache 291 CmsVfsMemoryObjectCache.getVfsMemoryObjectCache().putCachedObject( 292 cms, 293 configurationFileName, 294 m_localizationContent); 295 } catch (CmsException e) { 296 // ignore, no configuration file found 297 } 298 } 299 } 300 301 /** 302 * Initializes the (optional) xPath prefix to the element nodes.<p> 303 * 304 * @param pathPrefix the (optional) xPath prefix to the element nodes 305 */ 306 protected void initPathPrefix(String pathPrefix) { 307 308 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(pathPrefix)) { 309 m_pathPrefix = pathPrefix; 310 } else { 311 m_pathPrefix = ""; 312 } 313 } 314 315}