1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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.text.Format;
23 import java.text.MessageFormat;
24 import java.util.Arrays;
25 import java.util.Locale;
26 import java.util.regex.Pattern;
27
28
29
30
31
32 public class FormattedMessage implements Message {
33
34 private static final long serialVersionUID = -665975803997290697L;
35 private static final int HASHVAL = 31;
36 private static final String FORMAT_SPECIFIER = "%(\\d+\\$)?([-#+ 0,(\\<]*)?(\\d+)?(\\.\\d+)?([tT])?([a-zA-Z%])";
37 private static final Pattern MSG_PATTERN = Pattern.compile(FORMAT_SPECIFIER);
38
39 private String messagePattern;
40 private transient Object[] argArray;
41 private String[] stringArgs;
42 private transient String formattedMessage;
43 private final Throwable throwable;
44 private Message message;
45 private final Locale locale;
46
47
48
49
50
51
52
53
54 public FormattedMessage(final Locale locale, final String messagePattern, final Object arg) {
55 this(locale, messagePattern, new Object[] { arg }, null);
56 }
57
58
59
60
61
62
63
64
65
66 public FormattedMessage(final Locale locale, final String messagePattern, final Object arg1, final Object arg2) {
67 this(locale, messagePattern, new Object[] { arg1, arg2 });
68 }
69
70
71
72
73
74
75
76
77 public FormattedMessage(final Locale locale, final String messagePattern, final Object... arguments) {
78 this(locale, messagePattern, arguments, null);
79 }
80
81
82
83
84
85
86
87
88
89 public FormattedMessage(final Locale locale, final String messagePattern, final Object[] arguments, final Throwable throwable) {
90 this.locale = locale;
91 this.messagePattern = messagePattern;
92 this.argArray = arguments;
93 this.throwable = throwable;
94 }
95
96
97
98
99
100
101 public FormattedMessage(final String messagePattern, final Object arg) {
102 this(messagePattern, new Object[] { arg }, null);
103 }
104
105
106
107
108
109
110
111 public FormattedMessage(final String messagePattern, final Object arg1, final Object arg2) {
112 this(messagePattern, new Object[] { arg1, arg2 });
113 }
114
115
116
117
118
119
120 public FormattedMessage(final String messagePattern, final Object... arguments) {
121 this(messagePattern, arguments, null);
122 }
123
124
125
126
127
128
129
130 public FormattedMessage(final String messagePattern, final Object[] arguments, final Throwable throwable) {
131 this.locale = Locale.getDefault(Locale.Category.FORMAT);
132 this.messagePattern = messagePattern;
133 this.argArray = arguments;
134 this.throwable = throwable;
135 }
136
137
138 @Override
139 public boolean equals(final Object o) {
140 if (this == o) {
141 return true;
142 }
143 if (o == null || getClass() != o.getClass()) {
144 return false;
145 }
146
147 final FormattedMessage that = (FormattedMessage) o;
148
149 if (messagePattern != null ? !messagePattern.equals(that.messagePattern) : that.messagePattern != null) {
150 return false;
151 }
152 if (!Arrays.equals(stringArgs, that.stringArgs)) {
153 return false;
154 }
155
156 return true;
157 }
158
159
160
161
162
163 @Override
164 public String getFormat() {
165 return messagePattern;
166 }
167
168
169
170
171
172 @Override
173 public String getFormattedMessage() {
174 if (formattedMessage == null) {
175 if (message == null) {
176 message = getMessage(messagePattern, argArray, throwable);
177 }
178 formattedMessage = message.getFormattedMessage();
179 }
180 return formattedMessage;
181 }
182
183 protected Message getMessage(final String msgPattern, final Object[] args, final Throwable aThrowable) {
184 try {
185 final MessageFormat format = new MessageFormat(msgPattern);
186 final Format[] formats = format.getFormats();
187 if (formats != null && formats.length > 0) {
188 return new MessageFormatMessage(locale, msgPattern, args);
189 }
190 } catch (final Exception ignored) {
191
192 }
193 try {
194 if (MSG_PATTERN.matcher(msgPattern).find()) {
195 return new StringFormattedMessage(locale, msgPattern, args);
196 }
197 } catch (final Exception ignored) {
198
199 }
200 return new ParameterizedMessage(msgPattern, args, aThrowable);
201 }
202
203
204
205
206
207 @Override
208 public Object[] getParameters() {
209 if (argArray != null) {
210 return argArray;
211 }
212 return stringArgs;
213 }
214
215 @Override
216 public Throwable getThrowable() {
217 if (throwable != null) {
218 return throwable;
219 }
220 if (message == null) {
221 message = getMessage(messagePattern, argArray, null);
222 }
223 return message.getThrowable();
224 }
225
226
227 @Override
228 public int hashCode() {
229 int result = messagePattern != null ? messagePattern.hashCode() : 0;
230 result = HASHVAL * result + (stringArgs != null ? Arrays.hashCode(stringArgs) : 0);
231 return result;
232 }
233
234 private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
235 in.defaultReadObject();
236 formattedMessage = in.readUTF();
237 messagePattern = in.readUTF();
238 final int length = in.readInt();
239 stringArgs = new String[length];
240 for (int i = 0; i < length; ++i) {
241 stringArgs[i] = in.readUTF();
242 }
243 }
244
245 @Override
246 public String toString() {
247 return getFormattedMessage();
248 }
249
250 private void writeObject(final ObjectOutputStream out) throws IOException {
251 out.defaultWriteObject();
252 getFormattedMessage();
253 out.writeUTF(formattedMessage);
254 out.writeUTF(messagePattern);
255 out.writeInt(argArray.length);
256 stringArgs = new String[argArray.length];
257 int i = 0;
258 for (final Object obj : argArray) {
259 final String string = String.valueOf(obj);
260 stringArgs[i] = string;
261 out.writeUTF(string);
262 ++i;
263 }
264 }
265 }