1 /*
2 * Copyright 2006-2016 The JGUIraffe Team.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License")
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package net.sf.jguiraffe.resources;
17
18 import java.text.MessageFormat;
19 import java.util.Arrays;
20 import java.util.Locale;
21
22 import org.apache.commons.lang.ObjectUtils;
23
24 /**
25 * <p>
26 * A convenience class for dealing with localized messages that can have
27 * parameters.
28 * </p>
29 * <p>
30 * Instances of this class can be initialized with a resource group and a
31 * resource key of a message and optionally with a set of parameters. The text
32 * resource referred to can contain placeholders as supported by
33 * <code>java.text.MessageFormat</code>. When the message is to be displayed the
34 * {@link #resolve(ResourceManager, Locale)} method fetches the message text
35 * from the passed in {@link ResourceManager} and replaces the placeholders by
36 * actual parameter values.
37 * </p>
38 * <p>
39 * Instances of this class are immutable (provided that the parameters are
40 * immutable) and thus can be shared between multiple threads.
41 * </p>
42 *
43 * @author Oliver Heger
44 * @version $Id: Message.java 205 2012-01-29 18:29:57Z oheger $
45 */
46 public class Message
47 {
48 /** Constant for an empty parameters array. */
49 private static final Object[] NO_PARAMS = new Object[0];
50
51 /** Stores the resource group of this message. */
52 private final Object resourceGroup;
53
54 /** Stores the resource key of this message. */
55 private final Object resourceKey;
56
57 /** Stores an array with the parameter values. */
58 private final Object[] parameters;
59
60 /**
61 * Creates a new instance of <code>Message</code> and initializes it with a
62 * resource key. The default resource group is used. No parameters are set.
63 *
64 * @param resKey the resource key (must not be <b>null</b>)
65 * @throws IllegalArgumentException if the resource key is <b>null</b>
66 */
67 public Message(Object resKey)
68 {
69 this(null, resKey);
70 }
71
72 /**
73 * Creates a new instance of <code>Message</code> and initializes it with a
74 * resource group and a resource key. No parameters are set
75 *
76 * @param resGrp the resource group
77 * @param resKey the resource key (must not be <b>null</b>)
78 * @throws IllegalArgumentException if the resource key is <b>null</b>
79 */
80 public Message(Object resGrp, Object resKey)
81 {
82 checkResourceKey(resKey);
83 resourceGroup = resGrp;
84 resourceKey = resKey;
85 parameters = NO_PARAMS;
86 }
87
88 /**
89 * Creates a new instance of {@code Message} and initializes it with a
90 * resource group, a resource key, and a single parameter. This constructor
91 * can be used for the frequent case that only a single parameter is needed.
92 *
93 * @param resGrp the resource group (can be <b>null</b> for the default
94 * resource group)
95 * @param resKey the resource key (must not be <b>null</b>)
96 * @param param the single parameter of this {@code Message}
97 * @throws IllegalArgumentException if the resource key is <b>null</b>
98 */
99 public Message(Object resGrp, Object resKey, Object param)
100 {
101 checkResourceKey(resKey);
102 resourceGroup = resGrp;
103 resourceKey = resKey;
104 parameters = new Object[] {
105 param
106 };
107 }
108
109 /**
110 * Creates a new instance of {@code Message} and initializes it with a
111 * resource group, a resource key, and two parameters. This constructor can
112 * be used for the case that exactly two parameters are needed.
113 *
114 * @param resGrp the resource group (can be <b>null</b> for the default
115 * resource group)
116 * @param resKey the resource key (must not be <b>null</b>)
117 * @param param1 the first parameter of this {@code Message}
118 * @param param2 the second parameter of this {@code Message}
119 * @throws IllegalArgumentException if the resource key is <b>null</b>
120 */
121 public Message(Object resGrp, Object resKey, Object param1, Object param2)
122 {
123 checkResourceKey(resKey);
124 resourceGroup = resGrp;
125 resourceKey = resKey;
126 parameters = new Object[] {
127 param1, param2
128 };
129 }
130
131 /**
132 * Creates a new instance of {@code Message} and initializes it with a
133 * resource group, a resource key, and an arbitrary number of parameters
134 * that are passed as variable arguments. Use this constructor if the number
135 * of parameters is greater than 2. For one or two parameters there are
136 * specialized constructors that are more efficient as there is no need to
137 * create an array.
138 *
139 * @param resGrp the resource group
140 * @param resKey the resource key (must not be <b>null</b>)
141 * @param param1 the first parameter of this {@code Message}
142 * @param param2 the second parameter of this {@code Message}
143 * @param params an arbitrary number of additional parameters
144 * @throws IllegalArgumentException if the resource key is <b>null</b>
145 */
146 public Message(Object resGrp, Object resKey, Object param1, Object param2,
147 Object... params)
148 {
149 checkResourceKey(resKey);
150 resourceGroup = resGrp;
151 resourceKey = resKey;
152 int paramLength = (params == null) ? 0 : params.length;
153 parameters = new Object[2 + paramLength];
154 parameters[0] = param1;
155 parameters[1] = param2;
156 if (paramLength > 0)
157 {
158 System.arraycopy(params, 0, parameters, 2, params.length);
159 }
160 }
161
162 /**
163 * Creates an instance of {@code Message} with an arbitrary number of
164 * parameters. This factory method can be used instead of the constructors
165 * if the parameters are already available as {@code Object[]}.
166 *
167 * @param resGrp the resource group
168 * @param resKey the resource key (must not be <b>null</b>)
169 * @param params the parameters
170 * @return the {@code Message} instance
171 * @throws IllegalArgumentException if the resource key is <b>null</b>
172 */
173 public static Message createWithParameters(Object resGrp, Object resKey,
174 Object... params)
175 {
176 if (params == null || params.length == 0)
177 {
178 return new Message(resGrp, resKey);
179 }
180 else if (params.length == 1)
181 {
182 return new Message(resGrp, resKey, params[0]);
183 }
184 else if (params.length == 2)
185 {
186 return new Message(resGrp, resKey, params[0], params[1]);
187 }
188
189 else
190 {
191 // create a new array with the parameter indices greater than 2
192 Object[] varParams = new Object[params.length - 2];
193 System.arraycopy(params, 2, varParams, 0, varParams.length);
194 return new Message(resGrp, resKey, params[0], params[1],
195 (Object[]) varParams);
196 }
197 }
198
199 /**
200 * Creates a new {@code Message} instance with the same resource group and
201 * resource key as the passed in instance, but with different parameters.
202 *
203 * @param msg the original {@code Message} (must not be <b>null</b>)
204 * @param params the new parameters
205 * @return the new {@code Message} instance
206 * @throws IllegalArgumentException if the original {@code Message} is
207 * <b>null</b>
208 */
209 public static Message createFromMessage(Message msg, Object... params)
210 {
211 if (msg == null)
212 {
213 throw new IllegalArgumentException("Message must not be null!");
214 }
215
216 return createWithParameters(msg.getResourceGroup(), msg
217 .getResourceKey(), params);
218 }
219
220 /**
221 * Returns the resource group.
222 *
223 * @return the resource group
224 */
225 public Object getResourceGroup()
226 {
227 return resourceGroup;
228 }
229
230 /**
231 * Returns the resource key.
232 *
233 * @return the resource key
234 */
235 public Object getResourceKey()
236 {
237 return resourceKey;
238 }
239
240 /**
241 * Returns an array with the parameters stored in this {@code Message}
242 * instance. These parameters are applied to the resource text when calling
243 * the {@link #resolve(ResourceManager, Locale)} method. The array returned
244 * by this method is a copy of the actual parameters, so modifying it does
245 * not affect this {@code Message} instance.
246 *
247 * @return an array with the parameter values
248 */
249 public Object[] getParameters()
250 {
251 return (parameters.length == 0) ? parameters : parameters.clone();
252 }
253
254 /**
255 * Resolves this message and returns its text value in the given locale. If
256 * parameters are defined, they are replaced.
257 *
258 * @param resMan the resource manager
259 * @param locale the locale
260 * @return the text of the message
261 * @throws java.util.MissingResourceException if the resource cannot be resolved
262 */
263 public String resolve(ResourceManager resMan, Locale locale)
264 {
265 String txt = resMan.getText(locale, getResourceGroup(),
266 getResourceKey());
267 if (parameters != null)
268 {
269 // replace parameters
270 MessageFormat fmt = new MessageFormat(txt, locale);
271 txt = fmt.format(parameters, new StringBuffer(), null).toString();
272 }
273
274 return txt;
275 }
276
277 /**
278 * Tests if this message equals another object. This method returns
279 * <b>true</b> only if the other object is a <code>Message</code> object,
280 * too, and all of its properties are equal to the properties of this
281 * object.
282 *
283 * @param obj the other object
284 * @return a flag whether these objects are equal
285 */
286 @Override
287 public boolean equals(Object obj)
288 {
289 if (obj == null)
290 {
291 return false;
292 }
293 if (!(obj instanceof Message))
294 {
295 return false;
296 }
297
298 Message c = (Message) obj;
299 return getResourceKey().equals(c.getResourceKey())
300 && ObjectUtils.equals(getResourceGroup(), c.getResourceGroup())
301 && Arrays.equals(parameters, c.parameters);
302 }
303
304 /**
305 * Calculates a hash code for this message.
306 *
307 * @return a hash code
308 */
309 @Override
310 public int hashCode()
311 {
312 final int seed = 17;
313 final int factor = 31;
314
315 int result = seed;
316 result = factor * result + getResourceKey().hashCode();
317 if (getResourceGroup() != null)
318 {
319 result = factor * result + getResourceGroup().hashCode();
320 }
321 result = factor * result + Arrays.hashCode(parameters);
322
323 return result;
324 }
325
326 /**
327 * Returns a string representation of this object. This string contains the
328 * resource key and the resource group and the values of the parameters.
329 *
330 * @return a string for this object
331 */
332 @Override
333 public String toString()
334 {
335 StringBuilder buf = new StringBuilder();
336 buf.append("Message [");
337 if (getResourceGroup() != null)
338 {
339 buf.append(" group = ").append(getResourceGroup());
340 }
341 buf.append(" key = ").append(getResourceKey());
342 if (parameters.length > 0)
343 {
344 buf.append(" parameters = ");
345 buf.append(Arrays.toString(parameters));
346 }
347 return buf.toString();
348 }
349
350 /**
351 * Tests whether the resource key is specified. Otherwise throws an
352 * exception.
353 *
354 * @param resKey the resource key
355 * @throws IllegalArgumentException if the resource key is <b>null</b>
356 */
357 private static void checkResourceKey(Object resKey)
358 {
359 if (resKey == null)
360 {
361 throw new IllegalArgumentException("Resource key must not be null!");
362 }
363 }
364 }