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.el.unified.resolver;
20  
21  import java.beans.FeatureDescriptor;
22  import java.util.ArrayList;
23  import java.util.Iterator;
24  import java.util.Map;
25  import java.util.ResourceBundle;
26  import javax.el.ELContext;
27  import javax.el.ELException;
28  import javax.el.ELResolver;
29  import javax.el.PropertyNotFoundException;
30  import javax.el.PropertyNotWritableException;
31  import javax.faces.application.Application;
32  import javax.faces.context.FacesContext;
33  
34  import org.apache.myfaces.config.RuntimeConfig;
35  
36  /**
37   * See JSF 1.2 spec section 5.6.1.4
38   * 
39   * @author Stan Silvert
40   */
41  public final class ResourceBundleResolver extends ELResolver
42  {
43  
44      /**
45       * RuntimeConfig is instantiated once per servlet and never changes--we can safely cache it
46       */
47      private RuntimeConfig runtimeConfig;
48  
49      /** Creates a new instance of ResourceBundleResolver */
50      public ResourceBundleResolver()
51      {
52      }
53  
54      @Override
55      public void setValue(final ELContext context, final Object base, final Object property, final Object value)
56          throws NullPointerException, PropertyNotFoundException, PropertyNotWritableException, ELException
57      {
58          // JSF 2.0 spec section 5.6.1.4
59          // "... If base is null and property is a String equal to the value of the
60          // <var> element of one of the <resource-bundle>'s in the application 
61          // configuration resources throw javax.el.PropertyNotWriteable, since
62          // ResourceBundles are read-only. ..."
63          // Since something is done only when base is null, it is better to check 
64          // for not null and return.
65          if (base != null)
66          {
67              return;
68          }
69  
70          if ((base == null) && (property == null))
71          {
72              throw new PropertyNotFoundException();
73          }
74  
75          if (!(property instanceof String))
76          {
77              return;
78          }
79  
80          // base is null and property is a String value, check for resource bundle.
81          final ResourceBundle bundle = getResourceBundle(context, (String)property);
82  
83          if (bundle != null)
84          {
85              throw new PropertyNotWritableException("ResourceBundles are read-only");
86          }
87      }
88  
89      @Override
90      public boolean isReadOnly(final ELContext context, final Object base, final Object property)
91          throws NullPointerException, PropertyNotFoundException, ELException
92      {
93  
94          if (base != null)
95          {
96              return false;
97          }
98          if (property == null)
99          {
100             throw new PropertyNotFoundException();
101         }
102         if (!(property instanceof String))
103         {
104             return false;
105         }
106 
107         final ResourceBundle bundle = getResourceBundle(context, (String)property);
108 
109         if (bundle != null)
110         {
111             context.setPropertyResolved(true);
112             return true;
113         }
114 
115         return false;
116     }
117 
118     @Override
119     public Object getValue(final ELContext context, final Object base, final Object property)
120         throws NullPointerException, PropertyNotFoundException, ELException
121     {
122 
123         if (base != null)
124         {
125             return null;
126         }
127         if (property == null)
128         {
129             throw new PropertyNotFoundException();
130         }
131         if (!(property instanceof String))
132         {
133             return null;
134         }
135 
136         final ResourceBundle bundle = getResourceBundle(context, (String)property);
137 
138         if (bundle != null)
139         {
140             context.setPropertyResolved(true);
141             return bundle;
142         }
143 
144         return null;
145     }
146 
147     @Override
148     public Class<?> getType(final ELContext context, final Object base, final Object property)
149         throws NullPointerException, PropertyNotFoundException, ELException
150     {
151 
152         if (base != null)
153         {
154             return null;
155         }
156         if (property == null)
157         {
158             throw new PropertyNotFoundException();
159         }
160         if (!(property instanceof String))
161         {
162             return null;
163         }
164 
165         final ResourceBundle bundle = getResourceBundle(context, (String)property);
166 
167         if (bundle != null)
168         {
169             context.setPropertyResolved(true);
170             return ResourceBundle.class;
171         }
172 
173         return null;
174     }
175 
176     @Override
177     public Iterator<FeatureDescriptor> getFeatureDescriptors(final ELContext context, final Object base)
178     {
179 
180         if (base != null)
181         {
182             return null;
183         }
184 
185         final ArrayList<FeatureDescriptor> descriptors = new ArrayList<FeatureDescriptor>();
186 
187         final Map<String, org.apache.myfaces.config.element.ResourceBundle> resourceBundles =
188                 runtimeConfig(context).getResourceBundles();
189 
190         for (org.apache.myfaces.config.element.ResourceBundle resourceBundle : resourceBundles.values())
191         {
192             descriptors.add(makeDescriptor(resourceBundle));
193         }
194 
195         return descriptors.iterator();
196     }
197 
198     @Override
199     public Class<?> getCommonPropertyType(final ELContext context, final Object base)
200     {
201 
202         if (base != null)
203         {
204             return null;
205         }
206 
207         return String.class;
208     }
209 
210     // get the FacesContext from the ELContext
211     private static FacesContext facesContext(final ELContext context)
212     {
213         return (FacesContext)context.getContext(FacesContext.class);
214     }
215 
216     private static ResourceBundle getResourceBundle(final ELContext context, final String property)
217     {
218         final FacesContext facesContext = facesContext(context);
219         if (facesContext != null)
220         {
221             final Application application = facesContext.getApplication();
222             return application.getResourceBundle(facesContext, property);
223         }
224 
225         return null;
226     }
227 
228     protected RuntimeConfig runtimeConfig(ELContext context)
229     {
230         final FacesContext facesContext = facesContext(context);
231 
232         // application-level singleton - we can safely cache this
233         if (this.runtimeConfig == null)
234         {
235             this.runtimeConfig = RuntimeConfig.getCurrentInstance(facesContext.getExternalContext());
236         }
237 
238         return runtimeConfig;
239     }
240 
241     private static FeatureDescriptor makeDescriptor(
242                                                     org.apache.myfaces.config.element.ResourceBundle bundle)
243     {
244         final FeatureDescriptor fd = new FeatureDescriptor();
245         fd.setValue(ELResolver.RESOLVABLE_AT_DESIGN_TIME, Boolean.TRUE);
246         fd.setName(bundle.getVar());
247         fd.setDisplayName(bundle.getDisplayName());
248         fd.setValue(ELResolver.TYPE, ResourceBundle.class);
249         fd.setShortDescription("");
250         fd.setExpert(false);
251         fd.setHidden(false);
252         fd.setPreferred(true);
253         return fd;
254     }
255 }