2009/05/20 - Apache Shale has been retired.

For more information, please explore the Attic.

View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to you under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.shale.util;
19  
20  import java.beans.Beans;
21  import java.util.ArrayList;
22  import java.util.Collection;
23  import java.util.Collections;
24  import java.util.Enumeration;
25  import java.util.HashMap;
26  import java.util.HashSet;
27  import java.util.List;
28  import java.util.Locale;
29  import java.util.Map;
30  import java.util.MissingResourceException;
31  import java.util.ResourceBundle;
32  import java.util.Set;
33  import javax.faces.component.UIViewRoot;
34  
35  import javax.faces.context.FacesContext;
36  
37  /***
38   * <p>Utility class emulating the behavior of the standard JSF Core Library
39   * tag <code>&lt;f:loadBundle&gt;</code>.  This class is designed to be used
40   * as a managed bean, and exposes a <code>map</code> property containing the
41   * messages in the resoruce bundle specified by the <code>basename</code>
42   * property, localized for the <code>Locale</code> specified on the current
43   * request.</p>
44   *
45   * <p>A typical use of this class would be to declare a managed bean like this:</p>
46   * <pre>
47   *    &lt;managed-bean&gt;
48   *      &lt;managed-bean-name&gt;bundle&lt;/managed-bean-name&gt;
49   *      &lt;managed-bean-class&gt;
50   *        org.apache.shale.util.LoadBundle
51   *      &lt;/managed-bean-class&gt;
52   *      &lt;managed-bean-scope&gt;request&lt;/managed-bean-scope&gt;
53   *      &lt;managed-property&gt;
54   *        &lt;property-name&gt;basename&lt;/property-name&gt;
55   *        &lt;value&gt;com.mycompany.mypackage.Bundle&lt;/value&gt;
56   *      &lt;/managed-property&gt;
57   *    &lt;/managed-bean&gt;
58   * </pre>
59   *
60   * <p>This will result in creation of a request scope object whose <code>map</code>
61   * property will return a <code>Map</code> representing the localized messages for
62   * the <code>com.mycompany.mypackage.Bundle</code> resource bundle.  You can look
63   * up localized messages in this <code>Map</code> by evaluating a value binding
64   * expression like this:</p>
65   * <blockquote>
66   *   <code>#{messages.['message.key']}</code>
67   * </blockquote>
68   * <p>where <code>message.key</code> is the key for which to retrieve a
69   * localized message.</p>
70   *
71   * <p>(Since 1.0.1) <strong>IMPLEMENTATION NOTE</strong> - For backwards
72   * compatibility in applications that utilized the 1.0.0 version of this
73   * class, the following sort of expression resolves to the same value:</p>
74   * <blockquote>
75   *   <code>#{messages.map['message.key']}</code>
76   * </blockquote>
77   */
78  public class LoadBundle {
79  
80     // ------------------------------------------------------------- Constructors
81  
82  
83     /*** Creates a new instance of LoadBundle. */
84     public LoadBundle() {
85          this(null);
86     }
87  
88  
89     /*** <p>Creates a new instance of LoadBundle for the specified bundle.</p>
90      *
91      * @param basename Base resource bundle name for this <code>LoadBundle</code>
92      */
93     public LoadBundle(String basename) {
94         this.basename = basename;
95     }
96  
97  
98     // --------------------------------------------------------- Static Variables
99  
100 
101    /***
102     * <p>The default <code>Locale</code> for this application.</p>
103     */
104    private static final Locale defaultLocale = Locale.getDefault();
105 
106 
107    // --------------------------------------------------------------- Properties
108 
109 
110    /***
111     * <p>The base resource bundle name for this <code>LoadBundle</code> instance.</p>
112     */
113    private String basename = null;
114 
115 
116    /***
117     * <p>Return the base resource bundle name for this <code>LoadBundle</code>
118     * instance.</p>
119     */
120    public String getBasename() {
121        return this.basename;
122    }
123 
124 
125    /***
126     * <p>Set the base resource bundle name for this <code>LoadBundle</code>
127     * instance.</p>
128     *
129     * @param basename The new base resource bundle name
130     */
131    public void setBasename(String basename) {
132        this.basename = basename;
133    }
134 
135 
136    // ----------------------------------------------------------- Public Methods
137 
138 
139    /***
140     * <p>Return a <code>Map</code> whose keys and values represent the content
141     * of the application resource bundle specified by the <code>basename</code>
142     * property, localized for the <code>Locale</code> stored in the
143     * <code>UIViewRoot</code> for the current request.</p>
144     *
145     * @exception IllegalStateException if we are not inside a Faces request,
146     *  or if there is not a current view root with a valid locale
147     */
148    public Map getMap() throws IllegalStateException {
149 
150        // Validate our current state
151        if (basename == null) {
152            if (Beans.isDesignTime()) {
153                return Collections.EMPTY_MAP;
154            }
155            throw new IllegalStateException("The 'basename' property cannot be null"); // FIXME - i18n
156        }
157        FacesContext context = FacesContext.getCurrentInstance();
158        UIViewRoot root = null;
159        Locale locale = null;
160        if (context != null) {
161            root = context.getViewRoot();
162        }
163        if (root != null) {
164            locale = root.getLocale();
165        }
166        if (locale == null) {
167            throw new IllegalStateException("Cannot retrieve locale-specific map if there " +
168                    "is not a current Faces request, containing a valid view root, with" +
169                    "a Locale instance inside.");
170        }
171 
172        // Look up the requested resource bundle
173        final ResourceBundle bundle = getBundle(basename, locale);
174        if (bundle == null) {
175            throw new IllegalArgumentException
176              ("No resource bundle found for base name '" + basename + "' and locale '" + locale + "'"); // FIXME - i18n
177        }
178 
179        // Construct and return an immutable Map representing these contents
180        Map map = new Map() {
181 
182            public void clear() {
183                throw new UnsupportedOperationException();
184            }
185 
186            public boolean containsKey(Object key) {
187                boolean result = false;
188                if (key != null) {
189                    result = bundle.getObject(key.toString()) != null;
190                }
191                return result;
192            }
193 
194            public boolean containsValue(Object value) {
195                Enumeration keys = bundle.getKeys();
196                while (keys.hasMoreElements()) {
197                    Object val = bundle.getObject(keys.nextElement().toString());
198                    if ((val != null) && val.equals(value)) {
199                        return true;
200                    }
201                }
202                return false;
203            }
204 
205 
206            public Set entrySet() {
207                Map map = new HashMap();
208                Enumeration keys = bundle.getKeys();
209                while (keys.hasMoreElements()) {
210                    String key = keys.nextElement().toString();
211                    Object value = bundle.getObject(key);
212                    map.put(key, value);
213                }
214                return map.entrySet();
215            }
216 
217            public boolean equals(Object o) {
218                if ((o == null) || !(o instanceof Map)) {
219                    return false;
220                }
221                return entrySet().equals(((Map) o).entrySet());
222            }
223 
224            public Object get(Object key) {
225                if (key == null) {
226                    return null;
227                }
228                try {
229                    return bundle.getObject(key.toString());
230                } catch (MissingResourceException e) {
231                    return "???" + key.toString() + "???";
232                }
233            }
234 
235            public int hashCode() {
236                return bundle.hashCode();
237            }
238 
239            public boolean isEmpty() {
240                Enumeration keys = bundle.getKeys();
241                while (keys.hasMoreElements()) {
242                    return false;
243                }
244                return true;
245            }
246 
247            public Set keySet() {
248                Set set = new HashSet();
249                Enumeration keys = bundle.getKeys();
250                while (keys.hasMoreElements()) {
251                    set.add(keys.nextElement());
252                }
253                return set;
254            }
255 
256            public Object put(Object key, Object value) {
257                throw new UnsupportedOperationException();
258            }
259 
260            public void putAll(Map map) {
261                throw new UnsupportedOperationException();
262            }
263 
264            public Object remove(Object key) {
265                throw new UnsupportedOperationException();
266            }
267 
268            public int size() {
269                int size = 0;
270                Enumeration keys = bundle.getKeys();
271                while (keys.hasMoreElements()) {
272                    keys.nextElement();
273                    size++;
274                }
275                return size;
276            }
277 
278            public Collection values() {
279                List list = new ArrayList();
280                Enumeration keys = bundle.getKeys();
281                while (keys.hasMoreElements()) {
282                    String key = keys.nextElement().toString();
283                    list.add(bundle.getObject(key));
284                }
285                return list;
286            }
287 
288        };
289        return map;
290 
291    }
292 
293 
294     // --------------------------------------------------------- Private Methods
295 
296 
297     /***
298      * <p>Return the localized <code>ResourceBundle</code> for the specified
299      * <code>Locale</code>.</p>
300      *
301      * @param basename Base name of the resource bundle to return
302      * @param locale Locale used to select the appropriate resource bundle
303      */
304     private ResourceBundle getBundle(String basename, Locale locale) {
305 
306         assert basename != null;
307         assert locale != null;
308         ClassLoader rbcl = Thread.currentThread().getContextClassLoader();
309         if (rbcl == null) {
310             rbcl = this.getClass().getClassLoader();
311         }
312         try {
313             return ResourceBundle.getBundle(basename, locale, rbcl);
314         } catch (MissingResourceException e) {
315             return ResourceBundle.getBundle(basename, defaultLocale, rbcl);
316         }
317 
318     }
319 
320 
321 }