KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > freemarker > ext > beans > ResourceBundleModel


1 /*
2  * Copyright (c) 2003 The Visigoth Software Society. All rights
3  * reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in
14  * the documentation and/or other materials provided with the
15  * distribution.
16  *
17  * 3. The end-user documentation included with the redistribution, if
18  * any, must include the following acknowledgement:
19  * "This product includes software developed by the
20  * Visigoth Software Society (http://www.visigoths.org/)."
21  * Alternately, this acknowledgement may appear in the software itself,
22  * if and wherever such third-party acknowledgements normally appear.
23  *
24  * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the
25  * project contributors may be used to endorse or promote products derived
26  * from this software without prior written permission. For written
27  * permission, please contact visigoths@visigoths.org.
28  *
29  * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
30  * nor may "FreeMarker" or "Visigoth" appear in their names
31  * without prior written permission of the Visigoth Software Society.
32  *
33  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36  * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
37  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44  * SUCH DAMAGE.
45  * ====================================================================
46  *
47  * This software consists of voluntary contributions made by many
48  * individuals on behalf of the Visigoth Software Society. For more
49  * information on the Visigoth Software Society, please see
50  * http://www.visigoths.org/
51  */

52
53 package freemarker.ext.beans;
54
55 import java.text.MessageFormat JavaDoc;
56 import java.util.Hashtable JavaDoc;
57 import java.util.Iterator JavaDoc;
58 import java.util.Enumeration JavaDoc;
59 import java.util.List JavaDoc;
60 import java.util.Map JavaDoc;
61 import java.util.Set JavaDoc;
62 import java.util.MissingResourceException JavaDoc;
63 import java.util.ResourceBundle JavaDoc;
64
65 import freemarker.ext.util.ModelFactory;
66 import freemarker.template.ObjectWrapper;
67 import freemarker.template.TemplateMethodModelEx;
68 import freemarker.template.TemplateModel;
69 import freemarker.template.TemplateModelException;
70
71 /**
72  * <p>A hash model that wraps a resource bundle. Makes it convenient to store
73  * localized content in the data model. It also acts as a method model that will
74  * take a resource key and arbitrary number of arguments and will apply
75  * {@link MessageFormat} with arguments on the string represented by the key.</p>
76  *
77  * <p>Typical usages:</p>
78  * <ul>
79  * <li><tt>bundle.resourceKey</tt> will retrieve the object from resource bundle
80  * with key <tt>resourceKey</tt></li>
81  * <li><tt>bundle("patternKey", arg1, arg2, arg3)</tt> will retrieve the string
82  * from resource bundle with key <tt>patternKey</tt>, and will use it as a pattern
83  * for MessageFormat with arguments arg1, arg2 and arg3</li>
84  * </ul>
85  * @author Attila Szegedi
86  * @version $Id: ResourceBundleModel.java,v 1.22 2004/01/06 17:06:42 szegedia Exp $
87  */

88 public class ResourceBundleModel
89     extends
90     BeanModel
91     implements
92     TemplateMethodModelEx
93 {
94     static final ModelFactory FACTORY =
95         new ModelFactory()
96         {
97             public TemplateModel create(Object JavaDoc object, ObjectWrapper wrapper)
98             {
99                 return new ResourceBundleModel((ResourceBundle JavaDoc)object, (BeansWrapper)wrapper);
100             }
101         };
102
103     private Hashtable JavaDoc formats = null;
104
105     public ResourceBundleModel(ResourceBundle JavaDoc bundle, BeansWrapper wrapper)
106     {
107         super(bundle, wrapper);
108     }
109
110     /**
111      * Overridden to invoke the getObject method of the resource bundle.
112      */

113     protected TemplateModel invokeGenericGet(Map JavaDoc keyMap, Class JavaDoc clazz, String JavaDoc key)
114     throws
115         TemplateModelException
116     {
117         try
118         {
119             return wrap(((ResourceBundle JavaDoc)object).getObject(key));
120         }
121         catch(MissingResourceException JavaDoc e)
122         {
123             throw new TemplateModelException("No such key: " + key);
124         }
125     }
126
127     /**
128      * Returns true if this bundle contains no objects.
129      */

130     public boolean isEmpty()
131     {
132         return !((ResourceBundle JavaDoc)object).getKeys().hasMoreElements() &&
133             super.isEmpty();
134     }
135
136     public int size()
137     {
138         return keySet().size();
139     }
140
141     protected Set JavaDoc keySet()
142     {
143         Set JavaDoc set = super.keySet();
144         Enumeration JavaDoc e = ((ResourceBundle JavaDoc)object).getKeys();
145         while (e.hasMoreElements()) {
146             set.add(e.nextElement());
147         }
148         return set;
149     }
150
151     /**
152      * Takes first argument as a resource key, looks up a string in resource bundle
153      * with this key, then applies a MessageFormat.format on the string with the
154      * rest of the arguments. The created MessageFormats are cached for later reuse.
155      */

156     public Object JavaDoc exec(List JavaDoc arguments)
157         throws
158         TemplateModelException
159     {
160         // Must have at least one argument - the key
161
if(arguments.size() < 1)
162             throw new TemplateModelException("No message key was specified");
163         // Read it
164
Iterator JavaDoc it = arguments.iterator();
165         String JavaDoc key = unwrap((TemplateModel)it.next()).toString();
166         try
167         {
168             if(!it.hasNext())
169             {
170                 return wrap(((ResourceBundle JavaDoc)object).getObject(key));
171             }
172     
173             // Copy remaining arguments into an Object[]
174
int args = arguments.size() - 1;
175             Object JavaDoc[] params = new Object JavaDoc[args];
176             for(int i = 0; i < args; ++i)
177                 params[i] = unwrap((TemplateModel)it.next());
178     
179             // Invoke format
180
return new StringModel(format(key, params), wrapper);
181         }
182         catch(MissingResourceException JavaDoc e)
183         {
184             throw new TemplateModelException("No such key: " + key);
185         }
186         catch(Exception JavaDoc e)
187         {
188             throw new TemplateModelException(e.getMessage());
189         }
190     }
191
192     /**
193      * Provides direct access to caching format engine from code (instead of from script).
194      */

195     public String JavaDoc format(String JavaDoc key, Object JavaDoc[] params)
196         throws
197         MissingResourceException JavaDoc
198     {
199         // Check to see if we already have a cache for message formats
200
// and construct it if we don't
201
// NOTE: this block statement should be synchronized. However
202
// concurrent creation of two caches will have no harmful
203
// consequences, and we avoid a performance hit.
204
/* synchronized(this) */
205         {
206             if(formats == null)
207                 formats = new Hashtable JavaDoc();
208         }
209
210         MessageFormat JavaDoc format = null;
211         // Check to see if we already have a requested MessageFormat cached
212
// and construct it if we don't
213
// NOTE: this block statement should be synchronized. However
214
// concurrent creation of two formats will have no harmful
215
// consequences, and we avoid a performance hit.
216
/* synchronized(formats) */
217         {
218             format = (MessageFormat JavaDoc)formats.get(key);
219             if(format == null)
220             {
221                 format = new MessageFormat JavaDoc(((ResourceBundle JavaDoc)object).getString(key));
222                 formats.put(key, format);
223             }
224         }
225
226         // Perform the formatting. We synchronize on it in case it
227
// contains date formatting, which is not thread-safe.
228
synchronized(format)
229         {
230             return format.format(params);
231         }
232     }
233
234     public ResourceBundle JavaDoc getBundle()
235     {
236         return (ResourceBundle JavaDoc)object;
237     }
238 }
239
Popular Tags