Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||||||
ShalePropertyResolver |
|
| 6.888888888888889;6.889 |
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 | 0 | public ShalePropertyResolver(PropertyResolver original) { |
73 | ||
74 | 0 | this.original = original; |
75 | ||
76 | 0 | } |
77 | ||
78 | ||
79 | // ------------------------------------------------------ Instance Variables |
|
80 | ||
81 | ||
82 | /** |
|
83 | * <p>The original <code>PropertyResolver</code> passed to our constructor.</p> |
|
84 | */ |
|
85 | 0 | 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 | 0 | if (base instanceof Context) { |
117 | 0 | Context context = (Context) base; |
118 | try { |
|
119 | 0 | if (property instanceof Name) { |
120 | 0 | return context.lookup((Name) property); |
121 | } else { |
|
122 | 0 | return context.lookup(property.toString()); |
123 | } |
|
124 | 0 | } catch (NameNotFoundException e) { |
125 | // Mimic standard JSF/JSP behavior when base is a Map |
|
126 | // by returning null |
|
127 | 0 | return null; |
128 | 0 | } catch (NamingException e) { |
129 | 0 | throw new EvaluationException(e); |
130 | } |
|
131 | 0 | } else if (base instanceof LoadBundle && !"basename".equals(property)) { |
132 | 0 | Map map = ((LoadBundle) base).getMap(); |
133 | 0 | if ("map".equals(property)) { |
134 | 0 | return map; |
135 | } else { |
|
136 | 0 | return map.get(property); |
137 | } |
|
138 | } else { |
|
139 | 0 | 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 | 0 | if (base instanceof Context) { |
164 | 0 | 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 | 0 | if (property instanceof Name) { |
169 | 0 | context.rebind((Name) property, value); |
170 | } else { |
|
171 | 0 | context.rebind(property.toString(), value); |
172 | } |
|
173 | 0 | } catch (NamingException e) { |
174 | 0 | throw new EvaluationException(e); |
175 | 0 | } |
176 | 0 | } else if (base instanceof LoadBundle && !"basename".equals(property)) { |
177 | 0 | throw new PropertyNotFoundException("" + value); |
178 | } else { |
|
179 | 0 | original.setValue(base, property, value); |
180 | } |
|
181 | ||
182 | 0 | } |
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 | 0 | 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 | 0 | return false; |
208 | 0 | } else if (base instanceof LoadBundle && !"basename".equals(property)) { |
209 | // All properties of this object are considered read only |
|
210 | 0 | return true; |
211 | } else { |
|
212 | 0 | 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 | 0 | if (base instanceof Context) { |
238 | 0 | Context context = (Context) base; |
239 | Object value; |
|
240 | try { |
|
241 | 0 | if (property instanceof Name) { |
242 | 0 | value = context.lookup((Name) property); |
243 | } else { |
|
244 | 0 | value = context.lookup(property.toString()); |
245 | } |
|
246 | 0 | } catch (NameNotFoundException e) { |
247 | // Mimic standard JSF/JSP behavior when base is a Map |
|
248 | // by returning null |
|
249 | 0 | return null; |
250 | 0 | } catch (NamingException e) { |
251 | 0 | throw new EvaluationException(e); |
252 | 0 | } |
253 | 0 | if (value == null) { |
254 | 0 | return null; |
255 | } else { |
|
256 | 0 | return value.getClass(); |
257 | } |
|
258 | 0 | } else if (base instanceof LoadBundle && !"basename".equals(property)) { |
259 | 0 | LoadBundle lb = (LoadBundle) base; |
260 | 0 | if ("map".equals(property)) { |
261 | 0 | return Map.class; |
262 | 0 | } else if (Beans.isDesignTime()) { |
263 | 0 | return Object.class; |
264 | } else { |
|
265 | 0 | Object value = lb.getMap().get(property); |
266 | 0 | if (value != null) { |
267 | 0 | return value.getClass(); |
268 | } else { |
|
269 | 0 | return null; |
270 | } |
|
271 | } |
|
272 | } else { |
|
273 | 0 | 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 | 0 | if (base instanceof Context) { |
293 | 0 | return getValue(base, "" + index); |
294 | 0 | } else if (base instanceof LoadBundle && !"basename".equals(base)) { |
295 | 0 | return getValue(base, "" + index); |
296 | } else { |
|
297 | 0 | 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 | 0 | if (base instanceof Context) { |
318 | 0 | setValue(base, "" + index, value); |
319 | 0 | } else if (base instanceof LoadBundle) { |
320 | 0 | setValue(base, "" + index, value); |
321 | } else { |
|
322 | 0 | original.setValue(base, index, value); |
323 | } |
|
324 | ||
325 | 0 | } |
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 | 0 | if (base instanceof Context) { |
342 | 0 | return isReadOnly(base, "" + index); |
343 | 0 | } else if (base instanceof LoadBundle) { |
344 | 0 | return isReadOnly(base, "" + index); |
345 | } else { |
|
346 | 0 | 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 | 0 | if (base instanceof Context) { |
366 | 0 | return getType(base, "" + index); |
367 | 0 | } else if (base instanceof LoadBundle) { |
368 | 0 | return getType(base, "" + index); |
369 | } else { |
|
370 | 0 | return original.getType(base, index); |
371 | } |
|
372 | ||
373 | } |
|
374 | ||
375 | ||
376 | } |