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.faces;
19  
20  import java.beans.Beans;
21  import java.util.Map;
22  import javax.faces.el.EvaluationException;
23  import javax.faces.el.PropertyNotFoundException;
24  import javax.faces.el.PropertyResolver;
25  import javax.naming.Context;
26  import javax.naming.Name;
27  import javax.naming.NameNotFoundException;
28  import javax.naming.NamingException;
29  import org.apache.shale.util.LoadBundle;
30  
31  /***
32   * <p>Shale-specific PropertyResolver for evaluating JavaServer Faces
33   * value binding and method binding expressions.  The following special
34   * processing is performed, based on recognizing the type of the base
35   * object:</p>
36   * <ul>
37   * <li><strong>javax.naming.Context</strong> - Treats the property "name"
38   *     as a String (or <code>javax.naming.Name</code>) suitable for passing
39   *     to the <code>lookup()</code> method of the <code>Context</code>.
40   *     The Context has no way to describe whether it is read only or not,
41   *     so <code>isReadOnly()</code> returns <code>false</code>.</li>
42   * <li><strong>org.apache.shale.util.LoadBundle</strong> - Special handling
43   *     as follows, based on the requested property name:
44   *     <ul>
45   *     <li><code>map</code> - Delegates to the original resolver's handling
46   *         of the <code>map</code> property.  This is for backwards compatibility
47   *         with applications depending on this behavior from the 1.0.0
48   *         version of the class.</li>
49   *     <li>Any other property is considered to be a resource bundle key, which
50   *         will be used to look up the corresponding value from the underlying
51   *         resource bundle, using the <code>Locale</code> from the current
52   *         view for selecting the appropriate translation.</li>
53   *     </ul></li>
54   * </ul>
55   * <p>All other evaluations are delegated to the previous implementation
56   * that was passed to our constructor.</p>
57   *
58   * $Id: ShalePropertyResolver.java 464373 2006-10-16 04:21:54Z rahul $
59   */
60  public class ShalePropertyResolver extends PropertyResolver {
61  
62  
63      // ------------------------------------------------------------- Constructor
64  
65  
66      /***
67       * <p>Construct a new {@link ShalePropertyResolver} instance.</p>
68       *
69       *
70       * @param original Original resolver to delegate to.
71       */
72      public ShalePropertyResolver(PropertyResolver original) {
73  
74          this.original = original;
75  
76      }
77  
78  
79      // ------------------------------------------------------ Instance Variables
80  
81  
82      /***
83       * <p>The original <code>PropertyResolver</code> passed to our constructor.</p>
84       */
85      private PropertyResolver original = null;
86  
87  
88      // ------------------------------------------------ PropertyResolver Methods
89  
90  
91      /***
92       * <p>For a base object of type <code>Context</code>, look up and return
93       * the named object corresponding to the specified property name from
94       * this <code>Context</code>.</p>
95       *
96       * <p>(Since 1.0.1) For a base object of type <code>LoadBundle</code>,
97       * treat the property expression as follows:</p>
98       * <ul>
99       * <li>If the property name is <code>map</code>, call the corresponding
100      *     property getter and return that value.</li>
101      * <li>Otherwise, treat the property name as a message key, and look up
102      *     and return the corresponding value from the <code>Map</code> that
103      *     is returned by the <code>getMap()</code> call.</li>
104      * </ul>
105      *
106      * @param base Base object from which to return a property
107      * @param property Property to be returned
108      *
109      * @exception EvaluationException if an evaluation error occurs
110      * @exception PropertyNotFoundException if there is no such named
111      *  object in this context
112      */
113     public Object getValue(Object base, Object property)
114       throws EvaluationException, PropertyNotFoundException {
115 
116         if (base instanceof Context) {
117             Context context = (Context) base;
118             try {
119                 if (property instanceof Name) {
120                     return context.lookup((Name) property);
121                 } else {
122                     return context.lookup(property.toString());
123                 }
124             } catch (NameNotFoundException e) {
125                 // Mimic standard JSF/JSP behavior when base is a Map
126                 // by returning null
127                 return null;
128             } catch (NamingException e) {
129                 throw new EvaluationException(e);
130             }
131         } else if (base instanceof LoadBundle && !"basename".equals(property)) {
132             Map map = ((LoadBundle) base).getMap();
133             if ("map".equals(property)) {
134                 return map;
135             } else {
136                 return map.get(property);
137             }
138         } else {
139             return original.getValue(base, property);
140         }
141 
142     }
143 
144 
145     /***
146      * <p>For a base object of type <code>Context</code>, replace any previous
147      * binding for the named object corresponding to the specified property
148      * name into this <code>Context</code>.</p>
149      *
150      * <p>(Since 1.0.1) For a base object of type <code>LoadBundle</code>,
151      * throw an exception since all properties of this object are read only.</p>
152      *
153      * @param base Base object in which to store a property
154      * @param property Property to be stored
155      * @param value Value to be stored
156      *
157      * @exception EvaluationException if an evaluation error occurs
158      * @exception PropertyNotFoundException if there is no such named
159      *  object in this context
160      */
161     public void setValue(Object base, Object property, Object value) {
162 
163         if (base instanceof Context) {
164             Context context = (Context) base;
165             try {
166                 // Mimic standard JSF/JSP behavior when base is a Map
167                 // by calling rebind() instead of bind()
168                 if (property instanceof Name) {
169                     context.rebind((Name) property, value);
170                 } else {
171                     context.rebind(property.toString(), value);
172                 }
173             } catch (NamingException e) {
174                 throw new EvaluationException(e);
175             }
176         } else if (base instanceof LoadBundle && !"basename".equals(property)) {
177             throw new PropertyNotFoundException("" + value);
178         } else {
179             original.setValue(base, property, value);
180         }
181 
182     }
183 
184 
185     /***
186      * <p>For a <code>Context</code> base object, arbitrarily return
187      * <code>false</code> because we cannot determine if a <code>Context</code>
188      * is read only or not.</p>
189      *
190      * <p>(Since 1.0.1) For a <code>LoadBundle</code> base object,
191      * return <code>true</code> because all pseudo-properties of
192      * this bundle are considered to be read only.</p>
193      *
194      * @param base Base object from which to return read only state
195      * @param property Property to be checked
196      *
197      * @exception EvaluationException if an evaluation error occurs
198      * @exception PropertyNotFoundException if there is no such named
199      *  object in this context
200      */
201     public boolean isReadOnly(Object base, Object property)
202       throws EvaluationException, PropertyNotFoundException {
203 
204         if (base instanceof Context) {
205             // Mimic standard JSF/JSP behavior when base is a Map
206             // by returning false if we cannot tell any better
207             return false;
208         } else if (base instanceof LoadBundle && !"basename".equals(property)) {
209             // All properties of this object are considered read only
210             return true;
211         } else {
212             return original.isReadOnly(base, property);
213         }
214 
215     }
216 
217 
218     /***
219      * <p>For a <code>Context</code>, look up and return the type of the
220      * named object corresponding to the specified property name from this
221      * <code>Context</code>.</p>
222      *
223      * <p>(Since 1.0.1) For a <code>LoadBundle</code>, look up and return
224      * the corresponding object type at runtime, or return <code>Object</code>
225      * for the type to be looked up at design time.</p>
226      *
227      * @param base Base object from which to return a property type
228      * @param property Property whose type is to be returned
229      *
230      * @exception EvaluationException if an evaluation error occurs
231      * @exception PropertyNotFoundException if there is no such named
232      *  object in this context
233      */
234     public Class getType(Object base, Object property)
235       throws EvaluationException, PropertyNotFoundException {
236 
237         if (base instanceof Context) {
238             Context context = (Context) base;
239             Object value;
240             try {
241                 if (property instanceof Name) {
242                     value = context.lookup((Name) property);
243                 } else {
244                     value = context.lookup(property.toString());
245                 }
246             } catch (NameNotFoundException e) {
247                 // Mimic standard JSF/JSP behavior when base is a Map
248                 // by returning null
249                 return null;
250             } catch (NamingException e) {
251                 throw new EvaluationException(e);
252             }
253             if (value == null) {
254                 return null;
255             } else {
256                 return value.getClass();
257             }
258         } else if (base instanceof LoadBundle && !"basename".equals(property)) {
259             LoadBundle lb = (LoadBundle) base;
260             if ("map".equals(property)) {
261                 return Map.class;
262             } else if (Beans.isDesignTime()) {
263                 return Object.class;
264             } else {
265                 Object value = lb.getMap().get(property);
266                 if (value != null) {
267                     return value.getClass();
268                 } else {
269                     return null;
270                 }
271             }
272         } else {
273             return original.getType(base, property);
274         }
275 
276     }
277 
278 
279     /***
280      * <p>Convert an index into a corresponding string, and delegate.</p>
281      *
282      * @param base Base object from which to return a property
283      * @param index Index to be returned
284      *
285      * @exception EvaluationException if an evaluation error occurs
286      * @exception PropertyNotFoundException if there is no such named
287      *  object in this context
288      */
289     public Object getValue(Object base, int index)
290       throws EvaluationException, PropertyNotFoundException {
291 
292         if (base instanceof Context) {
293             return getValue(base, "" + index);
294         } else if (base instanceof LoadBundle && !"basename".equals(base)) {
295             return getValue(base, "" + index);
296         } else {
297             return original.getValue(base, index);
298         }
299 
300     }
301 
302 
303     /***
304      * <p>Convert an index into a corresponding string, and delegate.</p>
305      *
306      * @param base Base object into which to store a property
307      * @param index Index to be stored
308      * @param value Value to be stored
309      *
310      * @exception EvaluationException if an evaluation error occurs
311      * @exception PropertyNotFoundException if there is no such named
312      *  object in this context
313      */
314     public void setValue(Object base, int index, Object value)
315       throws EvaluationException, PropertyNotFoundException {
316 
317         if (base instanceof Context) {
318             setValue(base, "" + index, value);
319         } else if (base instanceof LoadBundle) {
320             setValue(base, "" + index, value);
321         } else {
322             original.setValue(base, index, value);
323         }
324 
325     }
326 
327 
328     /***
329      * <p>Convert an index into a corresponding string, and delegate.</p>
330      *
331      * @param base Base object from which to check a property
332      * @param index Index to be checked
333      *
334      * @exception EvaluationException if an evaluation error occurs
335      * @exception PropertyNotFoundException if there is no such named
336      *  object in this context
337      */
338     public boolean isReadOnly(Object base, int index)
339       throws EvaluationException, PropertyNotFoundException {
340 
341         if (base instanceof Context) {
342             return isReadOnly(base, "" + index);
343         } else if (base instanceof LoadBundle) {
344             return isReadOnly(base, "" + index);
345         } else {
346             return original.isReadOnly(base, index);
347         }
348 
349     }
350 
351 
352     /***
353      * <p>Convert an index into a corresponding string, and delegate.</p>
354      *
355      * @param base Base object from which to return a property type
356      * @param index Index whose type is to be returned
357      *
358      * @exception EvaluationException if an evaluation error occurs
359      * @exception PropertyNotFoundException if there is no such named
360      *  object in this context
361      */
362     public Class getType(Object base, int index)
363       throws EvaluationException, PropertyNotFoundException {
364 
365         if (base instanceof Context) {
366             return getType(base, "" + index);
367         } else if (base instanceof LoadBundle) {
368             return getType(base, "" + index);
369         } else {
370             return original.getType(base, index);
371         }
372 
373     }
374 
375 
376 }