View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.taglib.core;
20  
21  import java.util.ArrayList;
22  import java.util.Collection;
23  import java.util.Enumeration;
24  import java.util.HashSet;
25  import java.util.List;
26  import java.util.Locale;
27  import java.util.Map;
28  import java.util.MissingResourceException;
29  import java.util.ResourceBundle;
30  import java.util.Set;
31  
32  import javax.faces.component.UIViewRoot;
33  import javax.faces.context.FacesContext;
34  import javax.faces.webapp.UIComponentTag;
35  import javax.servlet.jsp.JspException;
36  import javax.servlet.jsp.tagext.Tag;
37  import javax.servlet.jsp.tagext.TagSupport;
38  
39  import org.apache.commons.logging.Log;
40  import org.apache.commons.logging.LogFactory;
41  /**
42   * Loads a resource bundle and saves it as a variable in the request scope.
43   * 
44   * Unless otherwise specified, all attributes accept static values or EL expressions.
45   * 
46   * @JSFJspTag
47   *   name="f:loadBundle"
48   *   bodyContent="empty"
49   *
50   * @author Manfred Geiler (latest modification by $Author: skitching $)
51   * @version $Revision: 673803 $ $Date: 2008-07-03 16:07:46 -0500 (Thu, 03 Jul 2008) $
52   */
53  public class LoadBundleTag
54          extends TagSupport
55  {
56   /*
57   * TODO:
58   * We should find a way to save loaded bundles in the state, because otherwise
59   * on the next request the bundle map will not be present before the render phase
60   * and value bindings that reference to the bundle will always log annoying
61   * "Variable 'xxx' could not be resolved" error messages.
62   */
63      
64      private static final long serialVersionUID = -8892145684062838928L;
65  
66      private static final Log log = LogFactory.getLog(LoadBundleTag.class);
67  
68      private String _basename;
69      private String _var;
70  
71      /**
72       * The base name of the resource bundle.
73       * 
74       * @JSFJspAttribute
75       *   required="true"
76       */
77      public void setBasename(String basename)
78      {
79          _basename = basename;
80      }
81  
82      /**
83       * The name of the variable in request scope that the resources
84       * are saved to.  This must be a static value.
85       *  
86       * @JSFJspAttribute
87       *   required="true"
88       */
89      public void setVar(String var)
90      {
91          _var = var;
92      }
93  
94      public int doStartTag() throws JspException
95      {
96          FacesContext facesContext = FacesContext.getCurrentInstance();
97          if (facesContext == null)
98          {
99              throw new JspException("No faces context?!");
100         }
101 
102         try
103         {
104             resolveBundle(getBasename(facesContext));
105         }
106         catch(IllegalStateException ex)
107         {
108             throw new JspException(ex);
109         }
110 
111         return Tag.SKIP_BODY;
112     }
113 
114     private String getBasename(FacesContext facesContext) {
115         String basename = null;
116 
117         if (_basename!=null) {
118             if (UIComponentTag.isValueReference(_basename)) {
119                 basename = (String)facesContext.getApplication().createValueBinding(_basename).getValue(facesContext);
120             } else {
121                 basename = _basename;
122             }
123         }
124         return basename;
125     }
126 
127     /**
128      * This method is copied over to org.apache.myfaces.custom.loadbundle.LoadBundle.
129      * If you change anything here, think about changing it there as well.
130      *
131      * @param resolvedBasename
132      */
133     private void resolveBundle(String resolvedBasename) {
134         //ATTENTION: read comment above before changing this!
135         FacesContext facesContext = FacesContext.getCurrentInstance();
136 
137         UIViewRoot viewRoot = facesContext.getViewRoot();
138         if (viewRoot == null)
139         {
140             throw new IllegalStateException("No view root! LoadBundle must be nested inside <f:view> action.");
141         }
142 
143         Locale locale = viewRoot.getLocale();
144         if (locale == null)
145         {
146             locale = facesContext.getApplication().getDefaultLocale();
147         }
148 
149         final ResourceBundle bundle;
150         try
151         {
152             bundle = ResourceBundle.getBundle(resolvedBasename,
153                                               locale,
154                                               Thread.currentThread().getContextClassLoader());
155 
156             facesContext.getExternalContext().getRequestMap().put(_var,
157                                                                   new BundleMap(bundle));
158 
159         }
160         catch (MissingResourceException e)
161         {
162             log.error("Resource bundle '" + resolvedBasename + "' could not be found.",e);
163         }
164         //ATTENTION: read comment above before changing this!
165     }
166 
167 
168     /**
169      * This class is copied over to org.apache.myfaces.custom.loadbundle.LoadBundle.
170      * If you change anything here, think about changing it there as well.
171      *
172      */
173     private static class BundleMap implements Map
174     {
175         //ATTENTION: read javadoc
176         private ResourceBundle _bundle;
177         private List _values;
178 
179         public BundleMap(ResourceBundle bundle)
180         {
181             _bundle = bundle;
182         }
183 
184         //Optimized methods
185 
186         public Object get(Object key)
187         {
188             try {
189                 return _bundle.getObject(key.toString());
190             } catch (Exception e) {
191                 return "MISSING: " + key + " :MISSING";
192             }
193         }
194 
195         public boolean isEmpty()
196         {
197             return !_bundle.getKeys().hasMoreElements();
198         }
199 
200         public boolean containsKey(Object key)
201         {
202             try {
203                 return _bundle.getObject(key.toString()) != null;
204             } catch (MissingResourceException e) {
205                 return false;
206             }
207         }
208 
209 
210         //Unoptimized methods
211 
212         public Collection values()
213         {
214             if (_values == null)
215             {
216                 _values = new ArrayList();
217                 for (Enumeration enumer = _bundle.getKeys(); enumer.hasMoreElements(); )
218                 {
219                     String v = _bundle.getString((String)enumer.nextElement());
220                     _values.add(v);
221                 }
222             }
223             return _values;
224         }
225 
226         public int size()
227         {
228             return values().size();
229         }
230 
231         public boolean containsValue(Object value)
232         {
233             return values().contains(value);
234         }
235 
236         public Set entrySet()
237         {
238             Set set = new HashSet();
239             for (Enumeration enumer = _bundle.getKeys(); enumer.hasMoreElements(); )
240             {
241                 final String k = (String)enumer.nextElement();
242                 set.add(new Map.Entry() {
243                     public Object getKey()
244                     {
245                         return k;
246                     }
247 
248                     public Object getValue()
249                     {
250                         return _bundle.getObject(k);
251                     }
252 
253                     public Object setValue(Object value)
254                     {
255                         throw new UnsupportedOperationException(this.getClass().getName() + " UnsupportedOperationException");
256                     }
257                 });
258             }
259             return set;
260         }
261 
262         public Set keySet()
263         {
264             Set set = new HashSet();
265             for (Enumeration enumer = _bundle.getKeys(); enumer.hasMoreElements(); )
266             {
267                 set.add(enumer.nextElement());
268             }
269             return set;
270         }
271         //ATTENTION: read javadoc
272 
273 
274         //Unsupported methods
275 
276         public Object remove(Object key)
277         {
278             throw new UnsupportedOperationException(this.getClass().getName() + " UnsupportedOperationException");
279         }
280 
281         public void putAll(Map t)
282         {
283             throw new UnsupportedOperationException(this.getClass().getName() + " UnsupportedOperationException");
284         }
285 
286         public Object put(Object key, Object value)
287         {
288             throw new UnsupportedOperationException(this.getClass().getName() + " UnsupportedOperationException");
289         }
290 
291         public void clear()
292         {
293             throw new UnsupportedOperationException(this.getClass().getName() + " UnsupportedOperationException");
294         }
295         //ATTENTION: read javadoc
296     }
297 
298 }