View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.config.i18n;
8   
9   import java.text.MessageFormat;
10  import java.util.Locale;
11  import java.util.MissingResourceException;
12  import java.util.ResourceBundle;
13  
14  import org.apache.commons.logging.Log;
15  import org.apache.commons.logging.LogFactory;
16  
17  
18  public abstract class MessageFactory
19  {
20      /**
21       * This error code is used for {@link Message} instances that are not read from a
22       * resource bundles but are created only with a string.
23       */
24      private static final int STATIC_ERROR_CODE = -1;
25      private static final transient Object[] EMPTY_ARGS = new Object[]{};
26  
27      protected transient Log logger = LogFactory.getLog(getClass());
28      // since java 6 only
29      //protected final ReloadControl control = new ReloadControl();
30  
31      /**
32       * Computes the bundle's full path 
33       * (<code>META-INF/services/org/mule/i18n/&lt;bundleName&gt;-messages.properties</code>) from
34       * <code>bundleName</code>.
35       * 
36       * @param bundleName Name of the bundle without the &quot;messages&quot; suffix and without
37       *          file extension.
38       */
39      protected static String getBundlePath(String bundleName)
40      {
41          return "META-INF.services.org.mule.i18n." + bundleName + "-messages";
42      }
43      
44      /**
45       * Factory method to create a new {@link Message} instance that is filled with the formatted
46       * message with id <code>code</code> from the resource bundle <code>bundlePath</code>.
47       * 
48       * @param bundlePath complete path to the resource bundle for lookup
49       * @param code numeric code of the message
50       * @param arg
51       * @see #getBundlePath(String)
52       */
53      protected Message createMessage(String bundlePath, int code, Object arg)
54      {
55          return createMessage(bundlePath, code, new Object[] {arg});
56      }
57      
58      /**
59       * Factory method to create a new {@link Message} instance that is filled with the formatted
60       * message with id <code>code</code> from the resource bundle <code>bundlePath</code>.
61       * 
62       * @param bundlePath complete path to the resource bundle for lookup
63       * @param code numeric code of the message
64       * @param arg1
65       * @param arg2
66       * @see #getBundlePath(String)
67       */
68      protected Message createMessage(String bundlePath, int code, Object arg1, Object arg2)
69      {
70          return createMessage(bundlePath, code, new Object[] {arg1, arg2});
71      }
72      
73      /**
74       * Factory method to create a new {@link Message} instance that is filled with the formatted
75       * message with id <code>code</code> from the resource bundle <code>bundlePath</code>.
76       * 
77       * @param bundlePath complete path to the resource bundle for lookup
78       * @param code numeric code of the message
79       * @param arg1
80       * @param arg2
81       * @param arg3
82       * @see #getBundlePath(String)
83       */
84      protected Message createMessage(String bundlePath, int code, Object arg1, Object arg2, 
85          Object arg3)
86      {
87          return createMessage(bundlePath, code, new Object[] {arg1, arg2, arg3});
88      }
89      
90      /**
91       * Factory method to create a new {@link Message} instance that is filled with the formatted
92       * message with id <code>code</code> from the resource bundle <code>bundlePath</code>.
93       * 
94       * <b>Attention:</b> do not confuse this method with 
95       * <code>createMessage(String, int, Object)</code>.
96       * 
97       * @param bundlePath complete path to the resource bundle for lookup
98       * @param code numeric code of the message
99       * @param arguments
100      * @see #getBundlePath(String)
101      */
102     protected Message createMessage(String bundlePath, int code, Object... arguments)
103     {
104         String messageString = getString(bundlePath, code, arguments);
105         return new Message(messageString, code, arguments);
106     }
107 
108     /**
109      * Factory method to create a new {@link Message} instance that is filled with the formatted
110      * message with id <code>code</code> from the resource bundle <code>bundlePath</code>.
111      * 
112      * @param bundlePath complete path to the resource bundle for lookup
113      * @param code numeric code of the message
114      */
115     protected Message createMessage(String bundlePath, int code)
116     {
117         String messageString = getString(bundlePath, code, null);
118         return new Message(messageString, code, EMPTY_ARGS);
119     }
120 
121     /**
122      * Factory method to create a {@link Message} instance that is not read from a resource bundle.
123      * 
124      * @param message Message's message text
125      * @return a Messsage instance that has an error code of -1 and no arguments.
126      */
127     public static Message createStaticMessage(String message)
128     {
129         return new Message(message, STATIC_ERROR_CODE, EMPTY_ARGS);
130     }    
131 
132     /**
133      * Factory method to read the message with code <code>code</code> from the resource bundle.
134      * 
135      * @param bundlePath complete path to the resource bundle for lookup
136      * @param code numeric code of the message
137      * @return formatted error message as {@link String}
138      */
139     protected String getString(String bundlePath, int code)
140     {
141         return getString(bundlePath, code, null);
142     }
143     
144     /**
145      * Factory method to read the message with code <code>code</code> from the resource bundle.
146      * 
147      * @param bundlePath complete path to the resource bundle for lookup
148      * @param code numeric code of the message
149      * @param arg
150      * @return formatted error message as {@link String}
151      */
152     protected String getString(String bundlePath, int code, Object arg)
153     {
154         Object[] arguments = new Object[] {arg};
155         return getString(bundlePath, code, arguments);
156     }
157     
158     /**
159      * Factory method to read the message with code <code>code</code> from the resource bundle.
160      * 
161      * @param bundlePath complete path to the resource bundle for lookup
162      * @param code numeric code of the message
163      * @param arg1
164      * @param arg2
165      * @return formatted error message as {@link String}
166      */
167     protected String getString(String bundlePath, int code, Object arg1, Object arg2)
168     {
169         Object[] arguments = new Object[] {arg1, arg2};
170         return getString(bundlePath, code, arguments);
171     }
172 
173     protected String getString(String bundlePath, int code, Object[] args)
174     {
175         // We will throw a MissingResourceException if the bundle name is invalid
176         // This happens if the code references a bundle name that just doesn't exist
177         ResourceBundle bundle = getBundle(bundlePath);
178 
179         try
180         {
181             String m = bundle.getString(String.valueOf(code));
182             if (m == null)
183             {
184                 logger.error("Failed to find message for id " + code + " in resource bundle " + bundlePath);
185                 return "";
186             }
187 
188             return MessageFormat.format(m, args);
189         }
190         catch (MissingResourceException e)
191         {
192             logger.error("Failed to find message for id " + code + " in resource bundle " + bundlePath);
193             return "";
194         }
195     }
196 
197     /**
198      * @throws MissingResourceException if resource is missing
199      */
200     private ResourceBundle getBundle(String bundlePath)
201     {
202         Locale locale = Locale.getDefault();
203         if (logger.isTraceEnabled())
204         {
205             logger.trace("Loading resource bundle: " + bundlePath + " for locale " + locale);
206         }
207         ResourceBundle bundle = ResourceBundle.getBundle(bundlePath, locale, getClassLoader());
208         return bundle;
209     }
210 
211     /**
212      * Override this method to return the classloader for the bundle/module which 
213      * contains the needed resource files.
214      */
215     protected ClassLoader getClassLoader()
216     {
217         final ClassLoader ccl = Thread.currentThread().getContextClassLoader();
218         // if there's a deployment classloader present, use it for finding resources
219         return ccl == null ? getClass().getClassLoader() : ccl;
220     }
221 
222     // since java 6 only
223     /*static class ReloadControl extends ResourceBundle.Control
224     {
225         boolean needsReload = true;
226 
227         @Override
228         public boolean needsReload(String baseName, Locale locale, String format, ClassLoader loader, ResourceBundle bundle, long loadTime)
229         {
230             // TODO always for now
231             return true;
232         }
233 
234         @Override
235         public long getTimeToLive(String baseName, Locale locale)
236         {
237             if (needsReload)
238             {
239                 // must be zero, as other 'DONT_CACHE' constant doesn't work here, and is -1
240                 return 0;
241             }
242 
243             return ResourceBundle.Control.TTL_NO_EXPIRATION_CONTROL;
244         }
245     }*/
246 }
247 
248