View Javadoc

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 }