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.Arrays;
23  import java.util.IllegalFormatException;
24  import java.util.Locale;
25  
26  import org.apache.logging.log4j.Logger;
27  import org.apache.logging.log4j.status.StatusLogger;
28  
29  /**
30   * Handles messages that consist of a format string conforming to {@link java.util.Formatter}.
31   */
32  public class StringFormattedMessage implements Message {
33  
34      private static final Logger LOGGER = StatusLogger.getLogger();
35  
36      private static final long serialVersionUID = -665975803997290697L;
37  
38      private static final int HASHVAL = 31;
39  
40      private String messagePattern;
41      private transient Object[] argArray;
42      private String[] stringArgs;
43      private transient String formattedMessage;
44      private transient Throwable throwable;
45      private final Locale locale;
46      
47     /**
48      * Constructs a message.
49      * 
50      * @param locale the locale for this message format
51      * @param messagePattern the pattern for this message format
52      * @param arguments The objects to format
53      * @since 2.6
54      */
55      public StringFormattedMessage(final Locale locale, final String messagePattern, final Object... arguments) {
56          this.locale = locale;
57          this.messagePattern = messagePattern;
58          this.argArray = arguments;
59          if (arguments != null && arguments.length > 0 && arguments[arguments.length - 1] instanceof Throwable) {
60              this.throwable = (Throwable) arguments[arguments.length - 1];
61          }
62      }
63  
64      /**
65       * Constructs a message.
66       * 
67       * @param messagePattern the pattern for this message format
68       * @param arguments The objects to format
69       * @since 2.6
70       */
71      public StringFormattedMessage(final String messagePattern, final Object... arguments) {
72          this(Locale.getDefault(Locale.Category.FORMAT), messagePattern, arguments);
73      }
74  
75      /**
76       * Returns the formatted message.
77       * @return the formatted message.
78       */
79      @Override
80      public String getFormattedMessage() {
81          if (formattedMessage == null) {
82              formattedMessage = formatMessage(messagePattern, argArray);
83          }
84          return formattedMessage;
85      }
86  
87      /**
88       * Returns the message pattern.
89       * @return the message pattern.
90       */
91      @Override
92      public String getFormat() {
93          return messagePattern;
94      }
95  
96      /**
97       * Returns the message parameters.
98       * @return the message parameters.
99       */
100     @Override
101     public Object[] getParameters() {
102         if (argArray != null) {
103             return argArray;
104         }
105         return stringArgs;
106     }
107 
108     protected String formatMessage(final String msgPattern, final Object... args) {
109         try {
110             return String.format(locale, msgPattern, args);
111         } catch (final IllegalFormatException ife) {
112             LOGGER.error("Unable to format msg: " + msgPattern, ife);
113             return msgPattern;
114         }
115     }
116 
117     @Override
118     public boolean equals(final Object o) {
119         if (this == o) {
120             return true;
121         }
122         if (o == null || getClass() != o.getClass()) {
123             return false;
124         }
125 
126         final StringFormattedMessage that = (StringFormattedMessage) o;
127 
128         if (messagePattern != null ? !messagePattern.equals(that.messagePattern) : that.messagePattern != null) {
129             return false;
130         }
131 
132         return Arrays.equals(stringArgs, that.stringArgs);
133     }
134 
135     @Override
136     public int hashCode() {
137         int result = messagePattern != null ? messagePattern.hashCode() : 0;
138         result = HASHVAL * result + (stringArgs != null ? Arrays.hashCode(stringArgs) : 0);
139         return result;
140     }
141 
142 
143     @Override
144     public String toString() {
145         return getFormattedMessage();
146     }
147 
148     private void writeObject(final ObjectOutputStream out) throws IOException {
149         out.defaultWriteObject();
150         getFormattedMessage();
151         out.writeUTF(formattedMessage);
152         out.writeUTF(messagePattern);
153         out.writeInt(argArray.length);
154         stringArgs = new String[argArray.length];
155         int i = 0;
156         for (final Object obj : argArray) {
157             final String string = String.valueOf(obj);
158             stringArgs[i] = string;
159             out.writeUTF(string);
160             ++i;
161         }
162     }
163 
164     private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
165         in.defaultReadObject();
166         formattedMessage = in.readUTF();
167         messagePattern = in.readUTF();
168         final int length = in.readInt();
169         stringArgs = new String[length];
170         for (int i = 0; i < length; ++i) {
171             stringArgs[i] = in.readUTF();
172         }
173     }
174 
175     /**
176      * Return the throwable passed to the Message.
177      *
178      * @return the Throwable.
179      */
180     @Override
181     public Throwable getThrowable() {
182         return throwable;
183     }
184 }