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