1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package com.puppycrawl.tools.checkstyle.api;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.InputStreamReader;
24 import java.io.Reader;
25 import java.io.Serializable;
26 import java.net.URL;
27 import java.net.URLConnection;
28 import java.text.MessageFormat;
29 import java.util.Arrays;
30 import java.util.Collections;
31 import java.util.HashMap;
32 import java.util.Locale;
33 import java.util.Map;
34 import java.util.MissingResourceException;
35 import java.util.PropertyResourceBundle;
36 import java.util.ResourceBundle;
37 import java.util.ResourceBundle.Control;
38
39
40
41
42
43
44
45
46
47
48 public final class LocalizedMessage
49 implements Comparable<LocalizedMessage>, Serializable
50 {
51
52 private static final long serialVersionUID = 5675176836184862150L;
53
54
55 private static final int HASH_MULT = 29;
56
57
58 private static Locale sLocale = Locale.getDefault();
59
60
61
62
63
64 private static final Map<String, ResourceBundle> BUNDLE_CACHE =
65 Collections.synchronizedMap(new HashMap<String, ResourceBundle>());
66
67
68 private final int lineNo;
69
70 private final int colNo;
71
72
73 private final SeverityLevel severityLevel;
74
75
76 private final String moduleId;
77
78
79 private static final SeverityLevel DEFAULT_SEVERITY = SeverityLevel.ERROR;
80
81
82 private final String key;
83
84
85 private final Object[] args;
86
87
88 private final String bundle;
89
90
91 private final Class<?> sourceClass;
92
93
94 private final String customMessage;
95
96 @Override
97 public boolean equals(Object object)
98 {
99 if (this == object) {
100 return true;
101 }
102 if (!(object instanceof LocalizedMessage)) {
103 return false;
104 }
105
106 final LocalizedMessage localizedMessage = (LocalizedMessage) object;
107
108 if (colNo != localizedMessage.colNo) {
109 return false;
110 }
111 if (lineNo != localizedMessage.lineNo) {
112 return false;
113 }
114 if (!key.equals(localizedMessage.key)) {
115 return false;
116 }
117
118 if (!Arrays.equals(args, localizedMessage.args)) {
119 return false;
120 }
121
122
123
124
125 return true;
126 }
127
128 @Override
129 public int hashCode()
130 {
131 int result;
132 result = lineNo;
133 result = HASH_MULT * result + colNo;
134 result = HASH_MULT * result + key.hashCode();
135 for (final Object element : args) {
136 result = HASH_MULT * result + element.hashCode();
137 }
138 return result;
139 }
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154 public LocalizedMessage(int lineNo,
155 int colNo,
156 String bundle,
157 String key,
158 Object[] args,
159 SeverityLevel severityLevel,
160 String moduleId,
161 Class<?> sourceClass,
162 String customMessage)
163 {
164 this.lineNo = lineNo;
165 this.colNo = colNo;
166 this.key = key;
167 this.args = null == args ? null : args.clone();
168 this.bundle = bundle;
169 this.severityLevel = severityLevel;
170 this.moduleId = moduleId;
171 this.sourceClass = sourceClass;
172 this.customMessage = customMessage;
173 }
174
175
176
177
178
179
180
181
182
183
184
185
186
187 public LocalizedMessage(int lineNo,
188 int colNo,
189 String bundle,
190 String key,
191 Object[] args,
192 String moduleId,
193 Class<?> sourceClass,
194 String customMessage)
195 {
196 this(lineNo,
197 colNo,
198 bundle,
199 key,
200 args,
201 DEFAULT_SEVERITY,
202 moduleId,
203 sourceClass,
204 customMessage);
205 }
206
207
208
209
210
211
212
213
214
215
216
217
218
219 public LocalizedMessage(int lineNo,
220 String bundle,
221 String key,
222 Object[] args,
223 SeverityLevel severityLevel,
224 String moduleId,
225 Class<?> sourceClass,
226 String customMessage)
227 {
228 this(lineNo, 0, bundle, key, args, severityLevel, moduleId,
229 sourceClass, customMessage);
230 }
231
232
233
234
235
236
237
238
239
240
241
242
243
244 public LocalizedMessage(
245 int lineNo,
246 String bundle,
247 String key,
248 Object[] args,
249 String moduleId,
250 Class<?> sourceClass,
251 String customMessage)
252 {
253 this(lineNo, 0, bundle, key, args, DEFAULT_SEVERITY, moduleId,
254 sourceClass, customMessage);
255 }
256
257
258 public static void clearCache()
259 {
260 synchronized (BUNDLE_CACHE) {
261 BUNDLE_CACHE.clear();
262 }
263 }
264
265
266 public String getMessage()
267 {
268
269 final String customMessage = getCustomMessage();
270 if (customMessage != null) {
271 return customMessage;
272 }
273
274 try {
275
276
277
278
279 final ResourceBundle bundle = getBundle(this.bundle);
280 final String pattern = bundle.getString(key);
281 return MessageFormat.format(pattern, args);
282 }
283 catch (final MissingResourceException ex) {
284
285
286
287 return MessageFormat.format(key, args);
288 }
289 }
290
291
292
293
294
295
296 private String getCustomMessage()
297 {
298
299 if (customMessage == null) {
300 return null;
301 }
302
303 return MessageFormat.format(customMessage, args);
304 }
305
306
307
308
309
310
311
312
313 private ResourceBundle getBundle(String bundleName)
314 {
315 synchronized (BUNDLE_CACHE) {
316 ResourceBundle bundle = BUNDLE_CACHE
317 .get(bundleName);
318 if (bundle == null) {
319 bundle = ResourceBundle.getBundle(bundleName, sLocale,
320 sourceClass.getClassLoader(), new UTF8Control());
321 BUNDLE_CACHE.put(bundleName, bundle);
322 }
323 return bundle;
324 }
325 }
326
327
328 public int getLineNo()
329 {
330 return lineNo;
331 }
332
333
334 public int getColumnNo()
335 {
336 return colNo;
337 }
338
339
340 public SeverityLevel getSeverityLevel()
341 {
342 return severityLevel;
343 }
344
345
346 public String getModuleId()
347 {
348 return moduleId;
349 }
350
351
352
353
354
355
356
357 public String getKey()
358 {
359 return key;
360 }
361
362
363 public String getSourceName()
364 {
365 return sourceClass.getName();
366 }
367
368
369 public static void setLocale(Locale locale)
370 {
371 sLocale = locale;
372 }
373
374
375
376
377
378
379 @Override
380 public int compareTo(LocalizedMessage other)
381 {
382 if (getLineNo() == other.getLineNo()) {
383 if (getColumnNo() == other.getColumnNo()) {
384 return getMessage().compareTo(other.getMessage());
385 }
386 return getColumnNo() < other.getColumnNo() ? -1 : 1;
387 }
388
389 return getLineNo() < other.getLineNo() ? -1 : 1;
390 }
391
392
393
394
395
396
397
398
399
400 private static class UTF8Control extends Control
401 {
402 @Override
403 public ResourceBundle newBundle(String aBaseName, Locale aLocale, String aFormat,
404 ClassLoader aLoader, boolean aReload) throws IllegalAccessException,
405 InstantiationException, IOException
406 {
407
408 final String bundleName = toBundleName(aBaseName, aLocale);
409 final String resourceName = toResourceName(bundleName, "properties");
410 ResourceBundle bundle = null;
411 InputStream stream = null;
412 if (aReload) {
413 final URL url = aLoader.getResource(resourceName);
414 if (url != null) {
415 final URLConnection connection = url.openConnection();
416 if (connection != null) {
417 connection.setUseCaches(false);
418 stream = connection.getInputStream();
419 }
420 }
421 }
422 else {
423 stream = aLoader.getResourceAsStream(resourceName);
424 }
425 if (stream != null) {
426 try (Reader streamReader = new InputStreamReader(stream, "UTF-8")) {
427
428 bundle = new PropertyResourceBundle(streamReader);
429 } finally {
430 stream.close();
431 }
432 }
433 return bundle;
434 }
435 }
436 }