1 /*
2 * The contents of this file are subject to the terms
3 * of the Common Development and Distribution License
4 * (the "License"). You may not use this file except
5 * in compliance with the License.
6 *
7 * You can obtain a copy of the license at
8 * glassfish/bootstrap/legal/CDDLv1.0.txt or
9 * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10 * See the License for the specific language governing
11 * permissions and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL
14 * HEADER in each file and include the License file at
15 * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16 * add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your
18 * own identifying information: Portions Copyright [yyyy]
19 * [name of copyright owner]
20 *
21 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
22 */
23
24 package javax.el;
25
26 import java.util.Iterator;
27 import java.beans.FeatureDescriptor;
28
29 /**
30 * Enables customization of variable and property resolution behavior for EL
31 * expression evaluation.
32 *
33 * <p>While evaluating an expression, the <code>ELResolver</code> associated
34 * with the {@link ELContext} is consulted to do the initial resolution of
35 * the first variable of an expression. It is also consulted when a
36 * <code>.</code> or <code>[]</code> operator is encountered, except for the
37 * last such operator in a method expression, in which case the resultion
38 * rules are hard coded.</p>
39 *
40 * <p>For example, in the EL expression <code>${employee.lastName}</code>,
41 * the <code>ELResolver</code> determines what object <code>employee</code>
42 * refers to, and what it means to get the <code>lastName</code> property on
43 * that object.</p>
44 *
45 * <p>Most methods in this class accept a <code>base</code>
46 * and <code>property</code> parameter. In the case of variable resolution
47 * (e.g. determining what <code>employee</code> refers to in
48 * <code>${employee.lastName}</code>), the <code>base</code> parameter will
49 * be <code>null</code> and the <code>property</code> parameter will always
50 * be of type <code>String</code>. In this case, if the <code>property</code>
51 * is not a <code>String</code>, the behavior of the <code>ELResolver</code>
52 * is undefined.</p>
53 *
54 * <p>In the case of property resolution, the <code>base</code> parameter
55 * identifies the base object and the <code>property</code> object identifies
56 * the property on that base. For example, in the expression
57 * <code>${employee.lastName}</code>, <code>base</code> is the result of the
58 * variable resolution for <code>employee</code> and <code>property</code>
59 * is the string <code>"lastName"</code>. In the expression
60 * <code>${y[x]}</code>, <code>base</code> is the result of the variable
61 * resolution for <code>y</code> and <code>property</code> is the result of
62 * the variable resolution for <code>x</code>.</p>
63 *
64 * <p>Though only a single <code>ELResolver</code> is associated with an
65 * <code>ELContext</code>, there are usually multiple resolvers considered
66 * for any given variable or property resolution. <code>ELResolver</code>s
67 * are combined together using {@link CompositeELResolver}s, to define
68 * rich semantics for evaluating an expression.</p>
69 *
70 * <p>For the {@link #getValue}, {@link #getType}, {@link #setValue} and
71 * {@link #isReadOnly} methods, an <code>ELResolver</code> is not
72 * responsible for resolving all possible (base, property) pairs. In fact,
73 * most resolvers will only handle a <code>base</code> of a single type.
74 * To indicate that a resolver has successfully resolved a particular
75 * (base, property) pair, it must set the <code>propertyResolved</code>
76 * property of the <code>ELContext</code> to <code>true</code>. If it could
77 * not handle the given pair, it must leave this property alone. The caller
78 * must ignore the return value of the method if <code>propertyResolved</code>
79 * is <code>false</code>.</p>
80 *
81 * <p>The {@link #getFeatureDescriptors} and {@link #getCommonPropertyType}
82 * methods are primarily designed for design-time tool support, but must
83 * handle invocation at runtime as well. The
84 * {@link java.beans.Beans#isDesignTime} method can be used to determine
85 * if the resolver is being consulted at design-time or runtime.</p>
86 *
87 * @see CompositeELResolver
88 * @see ELContext#getELResolver
89 * @since JSP 2.1
90 */
91 public abstract class ELResolver {
92
93 // --------------------------------------------------------- Constants
94
95 /**
96 * <p>The attribute name of the named attribute in the
97 * <code>FeatureDescriptor</code> that specifies the runtime type of
98 * the variable or property.</p>
99 */
100
101 public static final String TYPE = "type";
102
103 /**
104 * <p>The attribute name of the named attribute in the
105 * <code>FeatureDescriptor</code> that specifies whether the
106 * variable or property can be resolved at runtime.</p>
107 */
108
109 public static final String RESOLVABLE_AT_DESIGN_TIME = "resolvableAtDesignTime";
110
111 /**
112 * Attempts to resolve the given <code>property</code> object on the given
113 * <code>base</code> object.
114 *
115 * <p>If this resolver handles the given (base, property) pair,
116 * the <code>propertyResolved</code> property of the
117 * <code>ELContext</code> object must be set to <code>true</code>
118 * by the resolver, before returning. If this property is not
119 * <code>true</code> after this method is called, the caller should ignore
120 * the return value.</p>
121 *
122 * @param context The context of this evaluation.
123 * @param base The base object whose property value is to be returned,
124 * or <code>null</code> to resolve a top-level variable.
125 * @param property The property or variable to be resolved.
126 * @return If the <code>propertyResolved</code> property of
127 * <code>ELContext</code> was set to <code>true</code>, then
128 * the result of the variable or property resolution; otherwise
129 * undefined.
130 * @throws NullPointerException if context is <code>null</code>
131 * @throws PropertyNotFoundException if the given (base, property) pair
132 * is handled by this <code>ELResolver</code> but the specified
133 * variable or property does not exist or is not readable.
134 * @throws ELException if an exception was thrown while performing
135 * the property or variable resolution. The thrown exception
136 * must be included as the cause property of this exception, if
137 * available.
138 */
139 public abstract Object getValue(ELContext context,
140 Object base,
141 Object property);
142
143 /**
144 * For a given <code>base</code> and <code>property</code>, attempts to
145 * identify the most general type that is acceptable for an object to be
146 * passed as the <code>value</code> parameter in a future call
147 * to the {@link #setValue} method.
148 *
149 * <p>If this resolver handles the given (base, property) pair,
150 * the <code>propertyResolved</code> property of the
151 * <code>ELContext</code> object must be set to <code>true</code>
152 * by the resolver, before returning. If this property is not
153 * <code>true</code> after this method is called, the caller should ignore
154 * the return value.</p>
155 *
156 * <p>This is not always the same as <code>getValue().getClass()</code>.
157 * For example, in the case of an {@link ArrayELResolver}, the
158 * <code>getType</code> method will return the element type of the
159 * array, which might be a superclass of the type of the actual
160 * element that is currently in the specified array element.</p>
161 *
162 * @param context The context of this evaluation.
163 * @param base The base object whose property value is to be analyzed,
164 * or <code>null</code> to analyze a top-level variable.
165 * @param property The property or variable to return the acceptable
166 * type for.
167 * @return If the <code>propertyResolved</code> property of
168 * <code>ELContext</code> was set to <code>true</code>, then
169 * the most general acceptable type; otherwise undefined.
170 * @throws NullPointerException if context is <code>null</code>
171 * @throws PropertyNotFoundException if the given (base, property) pair
172 * is handled by this <code>ELResolver</code> but the specified
173 * variable or property does not exist or is not readable.
174 * @throws ELException if an exception was thrown while performing
175 * the property or variable resolution. The thrown exception
176 * must be included as the cause property of this exception, if
177 * available.
178 */
179 public abstract Class<?> getType(ELContext context,
180 Object base,
181 Object property);
182
183 /**
184 * Attempts to set the value of the given <code>property</code>
185 * object on the given <code>base</code> object.
186 *
187 * <p>If this resolver handles the given (base, property) pair,
188 * the <code>propertyResolved</code> property of the
189 * <code>ELContext</code> object must be set to <code>true</code>
190 * by the resolver, before returning. If this property is not
191 * <code>true</code> after this method is called, the caller can
192 * safely assume no value has been set.</p>
193 *
194 * @param context The context of this evaluation.
195 * @param base The base object whose property value is to be set,
196 * or <code>null</code> to set a top-level variable.
197 * @param property The property or variable to be set.
198 * @param value The value to set the property or variable to.
199 * @throws NullPointerException if context is <code>null</code>
200 * @throws PropertyNotFoundException if the given (base, property) pair
201 * is handled by this <code>ELResolver</code> but the specified
202 * variable or property does not exist.
203 * @throws PropertyNotWritableException if the given (base, property)
204 * pair is handled by this <code>ELResolver</code> but the specified
205 * variable or property is not writable.
206 * @throws ELException if an exception was thrown while attempting to
207 * set the property or variable. The thrown exception
208 * must be included as the cause property of this exception, if
209 * available.
210 */
211 public abstract void setValue(ELContext context,
212 Object base,
213 Object property,
214 Object value);
215
216 /**
217 * For a given <code>base</code> and <code>property</code>, attempts to
218 * determine whether a call to {@link #setValue} will always fail.
219 *
220 * <p>If this resolver handles the given (base, property) pair,
221 * the <code>propertyResolved</code> property of the
222 * <code>ELContext</code> object must be set to <code>true</code>
223 * by the resolver, before returning. If this property is not
224 * <code>true</code> after this method is called, the caller should ignore
225 * the return value.</p>
226 *
227 * @param context The context of this evaluation.
228 * @param base The base object whose property value is to be analyzed,
229 * or <code>null</code> to analyze a top-level variable.
230 * @param property The property or variable to return the read-only status
231 * for.
232 * @return If the <code>propertyResolved</code> property of
233 * <code>ELContext</code> was set to <code>true</code>, then
234 * <code>true</code> if the property is read-only or
235 * <code>false</code> if not; otherwise undefined.
236 * @throws NullPointerException if context is <code>null</code>
237 * @throws PropertyNotFoundException if the given (base, property) pair
238 * is handled by this <code>ELResolver</code> but the specified
239 * variable or property does not exist.
240 * @throws ELException if an exception was thrown while performing
241 * the property or variable resolution. The thrown exception
242 * must be included as the cause property of this exception, if
243 * available.
244 */
245 public abstract boolean isReadOnly(ELContext context,
246 Object base,
247 Object property);
248
249 /**
250 * Returns information about the set of variables or properties that
251 * can be resolved for the given <code>base</code> object. One use for
252 * this method is to assist tools in auto-completion.
253 *
254 * <p>If the <code>base</code> parameter is <code>null</code>, the
255 * resolver must enumerate the list of top-level variables it can
256 * resolve.</p>
257 *
258 * <p>The <code>Iterator</code> returned must contain zero or more
259 * instances of {@link java.beans.FeatureDescriptor}, in no guaranteed
260 * order. In the case of primitive types such as <code>int</code>, the
261 * value <code>null</code> must be returned. This is to prevent the
262 * useless iteration through all possible primitive values. A
263 * return value of <code>null</code> indicates that this resolver does
264 * not handle the given <code>base</code> object or that the results
265 * are too complex to represent with this method and the
266 * {@link #getCommonPropertyType} method should be used instead.</p>
267 *
268 * <p>Each <code>FeatureDescriptor</code> will contain information about
269 * a single variable or property. In addition to the standard
270 * properties, the <code>FeatureDescriptor</code> must have two
271 * named attributes (as set by the <code>setValue</code> method):
272 * <ul>
273 * <li>{@link #TYPE} - The value of this named attribute must be
274 * an instance of <code>java.lang.Class</code> and specify the
275 * runtime type of the variable or property.</li>
276 * <li>{@link #RESOLVABLE_AT_DESIGN_TIME} - The value of this
277 * named attribute must be an instance of
278 * <code>java.lang.Boolean</code> and indicates whether it is safe
279 * to attempt to resolve this property at design-time. For
280 * instance, it may be unsafe to attempt a resolution at design
281 * time if the <code>ELResolver</code> needs access to a resource
282 * that is only available at runtime and no acceptable simulated
283 * value can be provided.</li>
284 * </ul></p>
285 *
286 * <p>The caller should be aware that the <code>Iterator</code>
287 * returned might iterate through a very large or even infinitely large
288 * set of properties. Care should be taken by the caller to not get
289 * stuck in an infinite loop.</p>
290 *
291 * <p>This is a "best-effort" list. Not all <code>ELResolver</code>s
292 * will return completely accurate results, but all must be callable
293 * at both design-time and runtime (i.e. whether or not
294 * <code>Beans.isDesignTime()</code> returns <code>true</code>),
295 * without causing errors.</p>
296 *
297 * <p>The <code>propertyResolved</code> property of the
298 * <code>ELContext</code> is not relevant to this method.
299 * The results of all <code>ELResolver</code>s are concatenated
300 * in the case of composite resolvers.</p>
301 *
302 * @param context The context of this evaluation.
303 * @param base The base object whose set of valid properties is to
304 * be enumerated, or <code>null</code> to enumerate the set of
305 * top-level variables that this resolver can evaluate.
306 * @return An <code>Iterator</code> containing zero or more (possibly
307 * infinitely more) <code>FeatureDescriptor</code> objects, or
308 * <code>null</code> if this resolver does not handle the given
309 * <code>base</code> object or that the results are too complex to
310 * represent with this method
311 * @see java.beans.FeatureDescriptor
312 */
313 public abstract Iterator<FeatureDescriptor> getFeatureDescriptors(
314 ELContext context,
315 Object base);
316
317 /**
318 * Returns the most general type that this resolver accepts for the
319 * <code>property</code> argument, given a <code>base</code> object.
320 * One use for this method is to assist tools in auto-completion.
321 *
322 * <p>This assists tools in auto-completion and also provides a
323 * way to express that the resolver accepts a primitive value,
324 * such as an integer index into an array. For example, the
325 * {@link ArrayELResolver} will accept any <code>int</code> as a
326 * <code>property</code>, so the return value would be
327 * <code>Integer.class</code>.</p>
328 *
329 * @param context The context of this evaluation.
330 * @param base The base object to return the most general property
331 * type for, or <code>null</code> to enumerate the set of
332 * top-level variables that this resolver can evaluate.
333 * @return <code>null</code> if this <code>ELResolver</code> does not
334 * know how to handle the given <code>base</code> object; otherwise
335 * <code>Object.class</code> if any type of <code>property</code>
336 * is accepted; otherwise the most general <code>property</code>
337 * type accepted for the given <code>base</code>.
338 */
339 public abstract Class<?> getCommonPropertyType(ELContext context,
340 Object base);
341
342 }