blob: b201020d000962d34cbb03c38a8e2222472b2fd4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache license, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the license for the specific language governing permissions and
* limitations under the license.
*/
package org.apache.logging.log4j.message;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import org.apache.logging.log4j.status.StatusLogger;
/**
* Provides some level of compatibility with Log4j 1.x and convenience but is not the recommended way to Localize
* messages.
* <p>
* The recommended way to localize messages is to log a message id. Log events should then be recorded without
* formatting into a data store. The application that is used to read the events and display them to the user can then
* localize and format the messages for the end user.
* </p>
*/
public class LocalizedMessage implements Message, LoggerNameAwareMessage {
private static final long serialVersionUID = 3893703791567290742L;
private String baseName;
// ResourceBundle is not Serializable.
private transient ResourceBundle resourceBundle;
private final Locale locale;
private transient StatusLogger logger = StatusLogger.getLogger();
private String loggerName;
private String key;
private String[] stringArgs;
private transient Object[] argArray;
private String formattedMessage;
private transient Throwable throwable;
/**
* Constructor with message pattern and arguments.
*
* @param messagePattern the message pattern that to be checked for placeholders.
* @param arguments the argument array to be converted.
*/
public LocalizedMessage(final String messagePattern, final Object[] arguments) {
this((ResourceBundle) null, (Locale) null, messagePattern, arguments);
}
public LocalizedMessage(final String baseName, final String key, final Object[] arguments) {
this(baseName, (Locale) null, key, arguments);
}
public LocalizedMessage(final ResourceBundle bundle, final String key, final Object[] arguments) {
this(bundle, (Locale) null, key, arguments);
}
public LocalizedMessage(final String baseName, final Locale locale, final String key, final Object[] arguments) {
this.key = key;
this.argArray = arguments;
this.throwable = null;
this.baseName = baseName;
this.resourceBundle = null;
this.locale = locale;
}
public LocalizedMessage(final ResourceBundle bundle, final Locale locale, final String key,
final Object[] arguments) {
this.key = key;
this.argArray = arguments;
this.throwable = null;
this.baseName = null;
this.resourceBundle = bundle;
this.locale = locale;
}
public LocalizedMessage(final Locale locale, final String key, final Object[] arguments) {
this((ResourceBundle) null, locale, key, arguments);
}
public LocalizedMessage(final String messagePattern, final Object arg) {
this((ResourceBundle) null, (Locale) null, messagePattern, new Object[] {arg});
}
public LocalizedMessage(final String baseName, final String key, final Object arg) {
this(baseName, (Locale) null, key, new Object[] {arg});
}
/**
* @param bundle The ResourceBundle for this message.
* @param key The key of the message in the bundle.
* @since 2.8
*/
public LocalizedMessage(final ResourceBundle bundle, final String key) {
this(bundle, (Locale) null, key, new Object[] {});
}
public LocalizedMessage(final ResourceBundle bundle, final String key, final Object arg) {
this(bundle, (Locale) null, key, new Object[] {arg});
}
public LocalizedMessage(final String baseName, final Locale locale, final String key, final Object arg) {
this(baseName, locale, key, new Object[] {arg});
}
public LocalizedMessage(final ResourceBundle bundle, final Locale locale, final String key, final Object arg) {
this(bundle, locale, key, new Object[] {arg});
}
public LocalizedMessage(final Locale locale, final String key, final Object arg) {
this((ResourceBundle) null, locale, key, new Object[] {arg});
}
public LocalizedMessage(final String messagePattern, final Object arg1, final Object arg2) {
this((ResourceBundle) null, (Locale) null, messagePattern, new Object[] {arg1, arg2});
}
public LocalizedMessage(final String baseName, final String key, final Object arg1, final Object arg2) {
this(baseName, (Locale) null, key, new Object[] {arg1, arg2});
}
public LocalizedMessage(final ResourceBundle bundle, final String key, final Object arg1, final Object arg2) {
this(bundle, (Locale) null, key, new Object[] {arg1, arg2});
}
public LocalizedMessage(final String baseName, final Locale locale, final String key, final Object arg1,
final Object arg2) {
this(baseName, locale, key, new Object[] {arg1, arg2});
}
public LocalizedMessage(final ResourceBundle bundle, final Locale locale, final String key, final Object arg1,
final Object arg2) {
this(bundle, locale, key, new Object[] {arg1, arg2});
}
public LocalizedMessage(final Locale locale, final String key, final Object arg1, final Object arg2) {
this((ResourceBundle) null, locale, key, new Object[] {arg1, arg2});
}
/**
* Set the name of the Logger.
*
* @param name The name of the Logger.
*/
@Override
public void setLoggerName(final String name) {
this.loggerName = name;
}
/**
* Returns the name of the Logger.
*
* @return the name of the Logger.
*/
@Override
public String getLoggerName() {
return this.loggerName;
}
/**
* Returns the formatted message after looking up the format in the resource bundle.
*
* @return The formatted message String.
*/
@Override
public String getFormattedMessage() {
if (formattedMessage != null) {
return formattedMessage;
}
ResourceBundle bundle = this.resourceBundle;
if (bundle == null) {
if (baseName != null) {
bundle = getResourceBundle(baseName, locale, false);
} else {
bundle = getResourceBundle(loggerName, locale, true);
}
}
final String myKey = getFormat();
final String msgPattern = (bundle == null || !bundle.containsKey(myKey)) ? myKey : bundle.getString(myKey);
final Object[] array = argArray == null ? stringArgs : argArray;
final FormattedMessage msg = new FormattedMessage(msgPattern, array);
formattedMessage = msg.getFormattedMessage();
throwable = msg.getThrowable();
return formattedMessage;
}
@Override
public String getFormat() {
return key;
}
@Override
public Object[] getParameters() {
if (argArray != null) {
return argArray;
}
return stringArgs;
}
@Override
public Throwable getThrowable() {
return throwable;
}
/**
* Override this to use a ResourceBundle.Control in Java 6
*
* @param rbBaseName The base name of the resource bundle, a fully qualified class name.
* @param resourceBundleLocale The locale to use when formatting the message.
* @param loop If true the key will be treated as a package or class name and a resource bundle will be located
* based on all or part of the package name. If false the key is expected to be the exact bundle id.
* @return The ResourceBundle.
*/
protected ResourceBundle getResourceBundle(final String rbBaseName, final Locale resourceBundleLocale,
final boolean loop) {
ResourceBundle rb = null;
if (rbBaseName == null) {
return null;
}
try {
if (resourceBundleLocale != null) {
rb = ResourceBundle.getBundle(rbBaseName, resourceBundleLocale);
} else {
rb = ResourceBundle.getBundle(rbBaseName);
}
} catch (final MissingResourceException ex) {
if (!loop) {
logger.debug("Unable to locate ResourceBundle " + rbBaseName);
return null;
}
}
String substr = rbBaseName;
int i;
while (rb == null && (i = substr.lastIndexOf('.')) > 0) {
substr = substr.substring(0, i);
try {
if (resourceBundleLocale != null) {
rb = ResourceBundle.getBundle(substr, resourceBundleLocale);
} else {
rb = ResourceBundle.getBundle(substr);
}
} catch (final MissingResourceException ex) {
logger.debug("Unable to locate ResourceBundle " + substr);
}
}
return rb;
}
@Override
public String toString() {
return getFormattedMessage();
}
private void writeObject(final ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
getFormattedMessage();
out.writeUTF(formattedMessage);
out.writeUTF(key);
out.writeUTF(baseName);
out.writeInt(argArray.length);
stringArgs = new String[argArray.length];
int i = 0;
for (final Object obj : argArray) {
stringArgs[i] = obj.toString();
++i;
}
out.writeObject(stringArgs);
}
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
formattedMessage = in.readUTF();
key = in.readUTF();
baseName = in.readUTF();
in.readInt();
stringArgs = (String[]) in.readObject();
logger = StatusLogger.getLogger();
resourceBundle = null;
argArray = null;
}
}