View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements. See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache license, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License. You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the license for the specific language governing permissions and
    15   * limitations under the license.
    16   */
    17  package org.apache.logging.log4j.message;
    18
    19  import java.io.IOException;
    20  import java.io.ObjectInputStream;
    21  import java.io.ObjectOutputStream;
    22  import java.util.Locale;
    23  import java.util.MissingResourceException;
    24  import java.util.ResourceBundle;
    25
    26  import org.apache.logging.log4j.status.StatusLogger;
    27
    28  /**
    29   * Provides some level of compatibility with Log4j 1.x and convenience but is not the recommended way to Localize
    30   * messages.
    31   * <p>
    32   * The recommended way to localize messages is to log a message id. Log events should then be recorded without
    33   * formatting into a data store. The application that is used to read the events and display them to the user can then
    34   * localize and format the messages for the end user.
    35   * </p>
    36   */
    37  public class LocalizedMessage implements Message, LoggerNameAwareMessage {
    38      private static final long serialVersionUID = 3893703791567290742L;
    39
    40      private String baseName;
    41
    42      // ResourceBundle is not Serializable.
    43      private transient ResourceBundle resourceBundle;
    44
    45      private final Locale locale;
    46
    47      private transient StatusLogger logger = StatusLogger.getLogger();
    48
    49      private String loggerName;
    50      private String key;
    51      private String[] stringArgs;
    52      private transient Object[] argArray;
    53      private String formattedMessage;
    54      private transient Throwable throwable;
    55
    56      /**
    57       * Constructor with message pattern and arguments.
    58       *
    59       * @param messagePattern the message pattern that to be checked for placeholders.
    60       * @param arguments      the argument array to be converted.
    61       */
    62      public LocalizedMessage(final String messagePattern, final Object[] arguments) {
    63          this((ResourceBundle) null, (Locale) null, messagePattern, arguments);
    64      }
    65
    66      public LocalizedMessage(final String baseName, final String key, final Object[] arguments) {
    67          this(baseName, (Locale) null, key, arguments);
    68      }
    69
    70      public LocalizedMessage(final ResourceBundle bundle, final String key, final Object[] arguments) {
    71          this(bundle, (Locale) null, key, arguments);
    72      }
    73
    74      public LocalizedMessage(final String baseName, final Locale locale, final String key, final Object[] arguments) {
    75          this.key = key;
    76          this.argArray = arguments;
    77          this.throwable = null;
    78          this.baseName = baseName;
    79          this.resourceBundle = null;
    80          this.locale = locale;
    81      }
    82
    83      public LocalizedMessage(final ResourceBundle bundle, final Locale locale, final String key,
    84                              final Object[] arguments) {
    85          this.key = key;
    86          this.argArray = arguments;
    87          this.throwable = null;
    88          this.baseName = null;
    89          this.resourceBundle = bundle;
    90          this.locale = locale;
    91      }
    92
    93      public LocalizedMessage(final Locale locale, final String key, final Object[] arguments) {
    94          this((ResourceBundle) null, locale, key, arguments);
    95      }
    96
    97      public LocalizedMessage(final String messagePattern, final Object arg) {
    98          this((ResourceBundle) null, (Locale) null, messagePattern, new Object[] {arg});
    99      }
    100
    101     public LocalizedMessage(final String baseName, final String key, final Object arg) {
    102         this(baseName, (Locale) null, key, new Object[] {arg});
    103     }
    104
    105     public LocalizedMessage(final ResourceBundle bundle, final String key, final Object arg) {
    106         this(bundle, (Locale) null, key, new Object[] {arg});
    107     }
    108
    109     public LocalizedMessage(final String baseName, final Locale locale, final String key, final Object arg) {
    110         this(baseName, locale, key, new Object[] {arg});
    111     }
    112
    113     public LocalizedMessage(final ResourceBundle bundle, final Locale locale, final String key, final Object arg) {
    114         this(bundle, locale, key, new Object[] {arg});
    115     }
    116
    117     public LocalizedMessage(final Locale locale, final String key, final Object arg) {
    118         this((ResourceBundle) null, locale, key, new Object[] {arg});
    119     }
    120
    121     public LocalizedMessage(final String messagePattern, final Object arg1, final Object arg2) {
    122         this((ResourceBundle) null, (Locale) null, messagePattern, new Object[] {arg1, arg2});
    123     }
    124
    125     public LocalizedMessage(final String baseName, final String key, final Object arg1, final Object arg2) {
    126         this(baseName, (Locale) null, key, new Object[] {arg1, arg2});
    127     }
    128
    129     public LocalizedMessage(final ResourceBundle bundle, final String key, final Object arg1, final Object arg2) {
    130         this(bundle, (Locale) null, key, new Object[] {arg1, arg2});
    131     }
    132
    133     public LocalizedMessage(final String baseName, final Locale locale, final String key, final Object arg1,
    134                             final Object arg2) {
    135         this(baseName, locale, key, new Object[] {arg1, arg2});
    136     }
    137
    138     public LocalizedMessage(final ResourceBundle bundle, final Locale locale, final String key, final Object arg1,
    139                             final Object arg2) {
    140         this(bundle, locale, key, new Object[] {arg1, arg2});
    141     }
    142
    143     public LocalizedMessage(final Locale locale, final String key, final Object arg1, final Object arg2) {
    144         this((ResourceBundle) null, locale, key, new Object[] {arg1, arg2});
    145     }
    146
    147     /**
    148      * Set the name of the Logger.
    149      * @param name The name of the Logger.
    150      */
    151     @Override
    152     public void setLoggerName(final String name) {
    153         this.loggerName = name;
    154     }
    155
    156     /**
    157      * Returns the name of the Logger.
    158      * @return the name of the Logger.
    159      */
    160     @Override
    161     public String getLoggerName() {
    162         return this.loggerName;
    163     }
    164
    165     /**
    166      * Returns the formatted message after looking up the format in the resource bundle.
    167      * @return The formatted message String.
    168      */
    169     @Override
    170     public String getFormattedMessage() {
    171         if (formattedMessage != null) {
    172             return formattedMessage;
    173         }
    174         ResourceBundle bundle = this.resourceBundle;
    175         if (bundle == null) {
    176             if (baseName != null) {
    177                 bundle = getResourceBundle(baseName, locale, false);
    178             } else {
    179                 bundle = getResourceBundle(loggerName, locale, true);
    180             }
    181         }
    182         final String myKey = getFormat();
    183         final String msgPattern = (bundle == null || !bundle.containsKey(myKey)) ?
    184             myKey : bundle.getString(myKey);
    185         final Object[] array = argArray == null ? stringArgs : argArray;
    186         final FormattedMessage msg = new FormattedMessage(msgPattern, array);
    187         formattedMessage = msg.getFormattedMessage();
    188         throwable = msg.getThrowable();
    189         return formattedMessage;
    190     }
    191
    192     @Override
    193     public String getFormat() {
    194         return key;
    195     }
    196
    197     @Override
    198     public Object[] getParameters() {
    199         if (argArray != null) {
    200             return argArray;
    201         }
    202         return stringArgs;
    203     }
    204
    205     @Override
    206     public Throwable getThrowable() {
    207         return throwable;
    208     }
    209
    210     /**
    211      * Override this to use a ResourceBundle.Control in Java 6
    212      *
    213      * @param rbBaseName The base name of the resource bundle, a fully qualified class name.
    214      * @param resourceBundleLocale The locale to use when formatting the message.
    215      * @param loop If true the key will be treated as a package or class name and a resource bundle will
    216      * be located based on all or part of the package name. If false the key is expected to be the exact bundle id.
    217      * @return The ResourceBundle.
    218      */
    219     protected ResourceBundle getResourceBundle(final String rbBaseName, final Locale resourceBundleLocale, final boolean loop) {
    220         ResourceBundle rb = null;
    221
    222         if (rbBaseName == null) {
    223             return null;
    224         }
    225         try {
    226             if (resourceBundleLocale != null) {
    227                 rb = ResourceBundle.getBundle(rbBaseName, resourceBundleLocale);
    228             } else {
    229                 rb = ResourceBundle.getBundle(rbBaseName);
    230             }
    231         } catch (final MissingResourceException ex) {
    232             if (!loop) {
    233                 logger.debug("Unable to locate ResourceBundle " + rbBaseName);
    234                 return null;
    235             }
    236         }
    237
    238         String substr = rbBaseName;
    239         int i;
    240         while (rb == null && (i = substr.lastIndexOf('.')) > 0) {
    241             substr = substr.substring(0, i);
    242             try {
    243                 if (resourceBundleLocale != null) {
    244                     rb = ResourceBundle.getBundle(substr, resourceBundleLocale);
    245                 } else {
    246                     rb = ResourceBundle.getBundle(substr);
    247                 }
    248             } catch (final MissingResourceException ex) {
    249                 logger.debug("Unable to locate ResourceBundle " + substr);
    250             }
    251         }
    252         return rb;
    253     }
    254
    255     private void writeObject(final ObjectOutputStream out) throws IOException {
    256         out.defaultWriteObject();
    257         getFormattedMessage();
    258         out.writeUTF(formattedMessage);
    259         out.writeUTF(key);
    260         out.writeUTF(baseName);
    261         out.writeInt(argArray.length);
    262         stringArgs = new String[argArray.length];
    263         int i = 0;
    264         for (final Object obj : argArray) {
    265             stringArgs[i] = obj.toString();
    266             ++i;
    267         }
    268         out.writeObject(stringArgs);
    269     }
    270
    271     private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
    272         in.defaultReadObject();
    273         formattedMessage = in.readUTF();
    274         key = in.readUTF();
    275         baseName = in.readUTF();
    276         final int length = in.readInt();
    277         stringArgs = (String[]) in.readObject();
    278         logger = StatusLogger.getLogger();
    279         resourceBundle = null;
    280         argArray = null;
    281     }
    282 }