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