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
018 package org.apache.logging.log4j.message;
019
020 import java.io.IOException;
021 import java.io.ObjectInputStream;
022 import java.io.ObjectOutputStream;
023 import java.text.MessageFormat;
024 import java.util.Arrays;
025 import java.util.IllegalFormatException;
026
027 import org.apache.logging.log4j.Logger;
028 import org.apache.logging.log4j.status.StatusLogger;
029
030 /**
031 * Handles messages that consist of a format string conforming to java.text.MessageFormat.
032 *
033 * @serial In version 2.1, due to a bug in the serialization format, the serialization format was changed along with
034 * its {@code serialVersionUID} value.
035 */
036 public class MessageFormatMessage implements Message {
037
038 private static final Logger LOGGER = StatusLogger.getLogger();
039
040 private static final long serialVersionUID = 1L;
041
042 private static final int HASHVAL = 31;
043
044 private String messagePattern;
045 private transient Object[] parameters;
046 private String[] serializedParameters;
047 private transient String formattedMessage;
048 private transient Throwable throwable;
049
050 public MessageFormatMessage(final String messagePattern, final Object... parameters) {
051 this.messagePattern = messagePattern;
052 this.parameters = parameters;
053 final int length = parameters == null ? 0 : parameters.length;
054 if (length > 0 && parameters[length - 1] instanceof Throwable) {
055 this.throwable = (Throwable) parameters[length - 1];
056 }
057 }
058
059 /**
060 * Returns the formatted message.
061 * @return the formatted message.
062 */
063 @Override
064 public String getFormattedMessage() {
065 if (formattedMessage == null) {
066 formattedMessage = formatMessage(messagePattern, parameters);
067 }
068 return formattedMessage;
069 }
070
071 /**
072 * Returns the message pattern.
073 * @return the message pattern.
074 */
075 @Override
076 public String getFormat() {
077 return messagePattern;
078 }
079
080 /**
081 * Returns the message parameters.
082 * @return the message parameters.
083 */
084 @Override
085 public Object[] getParameters() {
086 if (parameters != null) {
087 return parameters;
088 }
089 return serializedParameters;
090 }
091
092 protected String formatMessage(final String msgPattern, final Object... args) {
093 try {
094 return MessageFormat.format(msgPattern, args);
095 } catch (final IllegalFormatException ife) {
096 LOGGER.error("Unable to format msg: " + msgPattern, ife);
097 return msgPattern;
098 }
099 }
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 }