001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017 package org.apache.logging.log4j.message; 018 019 import org.apache.logging.log4j.status.StatusLogger; 020 021 import java.io.IOException; 022 import java.io.ObjectInputStream; 023 import java.util.Locale; 024 import java.util.MissingResourceException; 025 import java.util.ResourceBundle; 026 027 /** 028 * This class is not the recommended way to Localize messages. It is provided to provide some level 029 * of compatibility with Log4j 1.x. 030 * 031 * The recommended way to localize messages is to simply log a message id. Log events should 032 * then be recorded without formatting into some kind of data store. The application that is 033 * used to read the events and display them to the user should also localize and format the 034 * messages for the end user. 035 */ 036 public class LocalizedMessage extends ParameterizedMessage implements LoggerNameAwareMessage 037 { 038 private static final long serialVersionUID = 3893703791567290742L; 039 040 private String bundleId; 041 042 private transient ResourceBundle bundle; 043 044 private Locale locale; 045 046 private transient StatusLogger logger = StatusLogger.getLogger(); 047 048 private String loggerName; 049 050 public LocalizedMessage(String messagePattern, String[] stringArgs, Throwable throwable) { 051 super(messagePattern, stringArgs, throwable); 052 setup(null, null, null); 053 } 054 055 056 public LocalizedMessage(String bundleId, String key, String[] stringArgs, 057 Throwable throwable) { 058 super(key, stringArgs, throwable); 059 setup(bundleId, null, null); 060 } 061 062 public LocalizedMessage(ResourceBundle bundle, String key, String[] stringArgs, 063 Throwable throwable) { 064 super(key, stringArgs, throwable); 065 setup(null, bundle, null); 066 } 067 068 public LocalizedMessage(String bundleId, Locale locale, String key, String[] stringArgs, 069 Throwable throwable) { 070 super(key, stringArgs, throwable); 071 setup(bundleId, null, locale); 072 } 073 074 public LocalizedMessage(ResourceBundle bundle, Locale locale, String key, String[] stringArgs, 075 Throwable throwable) { 076 super(key, stringArgs, throwable); 077 setup(null, bundle, locale); 078 } 079 080 public LocalizedMessage(Locale locale, String key, String[] stringArgs, Throwable throwable) { 081 super(key, stringArgs, throwable); 082 setup(null, null, locale); 083 } 084 085 086 /** 087 * <p>This method returns a LocalizedMessage which contains the arguments converted to String 088 * as well as an optional Throwable.</p> 089 * <p/> 090 * <p>If the last argument is a Throwable and is NOT used up by a placeholder in the message 091 * pattern it is returned in LocalizedMessage.getThrowable() and won't be contained in the 092 * created String[].<br/> 093 * If it is used up ParameterizedMessage.getThrowable() will return null even if the last 094 * argument was a Throwable!</p> 095 * 096 * @param messagePattern the message pattern that to be checked for placeholders. 097 * @param arguments the argument array to be converted. 098 */ 099 public LocalizedMessage(String messagePattern, Object[] arguments) { 100 super(messagePattern, arguments); 101 setup(null, null, null); 102 } 103 104 public LocalizedMessage(String bundleId, String key, Object[] arguments) { 105 super(key, arguments); 106 setup(bundleId, null, null); 107 } 108 109 public LocalizedMessage(ResourceBundle bundle, String key, Object[] arguments) { 110 super(key, arguments); 111 setup(null, bundle, null); 112 } 113 114 public LocalizedMessage(String bundleId, Locale locale, String key, Object[] arguments) { 115 super(key, arguments); 116 setup(bundleId, null, locale); 117 } 118 119 public LocalizedMessage(ResourceBundle bundle, Locale locale, String key, Object[] arguments) { 120 super(key, arguments); 121 setup(null, bundle, locale); 122 } 123 124 public LocalizedMessage(Locale locale, String key, Object[] arguments) { 125 super(key, arguments); 126 setup(null, null, locale); 127 } 128 129 public LocalizedMessage(String messagePattern, Object arg) { 130 super(messagePattern, arg); 131 setup(null, null, null); 132 } 133 134 public LocalizedMessage(String bundleId, String key, Object arg) { 135 super(key, arg); 136 setup(bundleId, null, null); 137 } 138 139 public LocalizedMessage(ResourceBundle bundle, String key, Object arg) { 140 super(key, arg); 141 setup(null, bundle, null); 142 } 143 144 public LocalizedMessage(String bundleId, Locale locale, String key, Object arg) { 145 super(key, arg); 146 setup(bundleId, null, locale); 147 } 148 149 public LocalizedMessage(ResourceBundle bundle, Locale locale, String key, Object arg) { 150 super(key, arg); 151 setup(null, bundle, locale); 152 } 153 154 public LocalizedMessage(Locale locale, String key, Object arg) { 155 super(key, arg); 156 setup(null, null, locale); 157 } 158 159 public LocalizedMessage(String messagePattern, Object arg1, Object arg2) { 160 super(messagePattern, arg1, arg2); 161 setup(null, null, null); 162 } 163 164 public LocalizedMessage(String bundleId, String key, Object arg1, Object arg2) { 165 super(key, arg1, arg2); 166 setup(bundleId, null, null); 167 } 168 169 public LocalizedMessage(ResourceBundle bundle, String key, Object arg1, Object arg2) { 170 super(key, arg1, arg2); 171 setup(null, bundle, null); 172 } 173 174 public LocalizedMessage(String bundleId, Locale locale, String key, Object arg1, Object arg2) { 175 super(key, arg1, arg2); 176 setup(bundleId, null, locale); 177 } 178 179 public LocalizedMessage(ResourceBundle bundle, Locale locale, String key, Object arg1, 180 Object arg2) { 181 super(key, arg1, arg2); 182 setup(null, bundle, locale); 183 } 184 185 public LocalizedMessage(Locale locale, String key, Object arg1, Object arg2) { 186 super(key, arg1, arg2); 187 setup(null, null, locale); 188 } 189 190 /** 191 * Set the name of the Logger. 192 * @param name The name of the Logger. 193 */ 194 public void setLoggerName(String name) { 195 this.loggerName = name; 196 } 197 198 /** 199 * Returns the name of the Logger. 200 * @return the name of the Logger. 201 */ 202 public String getLoggerName() { 203 return this.loggerName; 204 } 205 206 private void setup(String bundleId, ResourceBundle bundle, Locale locale) { 207 this.bundleId = bundleId; 208 this.bundle = bundle; 209 this.locale = locale; 210 } 211 212 /** 213 * Returns the formatted message after looking up the format in the resource bundle. 214 * @param messagePattern The key for the resource bundle or the pattern if the bundle doesn't contain the key. 215 * @param args The parameters. 216 * @return The formatted message String. 217 */ 218 @Override 219 public String formatMessage(String messagePattern, String[] args) { 220 ResourceBundle bundle = this.bundle; 221 if (bundle == null) { 222 if (bundleId != null) { 223 bundle = getBundle(bundleId, locale, false); 224 } else { 225 bundle = getBundle(loggerName, locale, true); 226 } 227 } 228 String msgPattern = (bundle == null || !bundle.containsKey(messagePattern)) ? 229 messagePattern : bundle.getString(messagePattern); 230 return format(msgPattern, args); 231 } 232 233 /** 234 * Override this to use a ResourceBundle.Control in Java 6 235 * @param key The key to the bundle. 236 * @param locale The locale to use when formatting the message. 237 * @param loop If true the key will be treated as a package or class name and a resource bundle will 238 * be located based on all or part of the package name. If false the key is expected to be the exact bundle id. 239 * @return The ResourceBundle. 240 */ 241 protected ResourceBundle getBundle(String key, Locale locale, boolean loop) { 242 ResourceBundle rb = null; 243 244 if (key == null) { 245 return null; 246 } 247 try { 248 if (locale != null) { 249 rb = ResourceBundle.getBundle(key, locale); 250 } else { 251 rb = ResourceBundle.getBundle(key); 252 } 253 } catch (MissingResourceException ex) { 254 if (!loop) { 255 logger.debug("Unable to locate ResourceBundle " + key); 256 return null; 257 } 258 } 259 260 String substr = key; 261 int i; 262 while (rb == null && (i = substr.lastIndexOf('.')) > 0) { 263 substr = substr.substring(0, i); 264 try { 265 if (locale != null) { 266 rb = ResourceBundle.getBundle(substr, locale); 267 } else { 268 rb = ResourceBundle.getBundle(substr); 269 } 270 } catch (MissingResourceException ex) { 271 logger.debug("Unable to locate ResourceBundle " + substr); 272 } 273 } 274 return rb; 275 } 276 277 private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { 278 stream.defaultReadObject(); 279 bundle = null; 280 logger = StatusLogger.getLogger(); 281 } 282 }