1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
5 *
6 * Portions Copyright Apache Software Foundation.
7 *
8 * The contents of this file are subject to the terms of either the GNU
9 * General Public License Version 2 only ("GPL") or the Common Development
10 * and Distribution License("CDDL") (collectively, the "License"). You
11 * may not use this file except in compliance with the License. You can obtain
12 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
13 * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
14 * language governing permissions and limitations under the License.
15 *
16 * When distributing the software, include this License Header Notice in each
17 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
18 * Sun designates this particular file as subject to the "Classpath" exception
19 * as provided by Sun in the GPL Version 2 section of the License file that
20 * accompanied this code. If applicable, add the following below the License
21 * Header, with the fields enclosed by brackets [] replaced by your own
22 * identifying information: "Portions Copyrighted [year]
23 * [name of copyright owner]"
24 *
25 * Contributor(s):
26 *
27 * If you wish your version of this file to be governed by only the CDDL or
28 * only the GPL Version 2, indicate your decision by adding "[Contributor]
29 * elects to include this software in this distribution under the [CDDL or GPL
30 * Version 2] license." If you don't indicate a single choice of license, a
31 * recipient has the option to distribute your version of this file under
32 * either the CDDL, the GPL Version 2 or to extend the choice of license to
33 * its licensees as provided above. However, if you add GPL Version 2 code
34 * and therefore, elected the GPL Version 2 license, then the option applies
35 * only if the new code is made subject to such option by the copyright
36 * holder.
37 */
38
39 package javax.servlet.jsp.el;
40
41 import java.beans.FeatureDescriptor;
42 import java.util.Iterator;
43 import java.util.ArrayList;
44 import java.util.Enumeration;
45
46 import javax.servlet.jsp.PageContext;
47 import javax.servlet.jsp.JspContext;
48
49 import javax.el.ELContext;
50 import javax.el.ELResolver;
51 import javax.el.ELException;
52
53 /**
54 * Defines variable resolution behavior for scoped attributes.
55 *
56 * <p>This resolver handles all variable resolutions (where <code>base</code>
57 * is <code>null</code>. It searches <code>PageContext.findAttribute()</code>
58 * for a matching attribute. If not found, it will return <code>null</code>,
59 * or in the case of <code>setValue</code> it will create a new attribute
60 * in the page scope with the given name.</p>
61 *
62 * @see javax.el.ELResolver
63 * @since JSP 2.1
64 */
65
66 public class ScopedAttributeELResolver extends ELResolver {
67
68 /**
69 * If the base object is <code>null</code>, searches the page,
70 * request, session and application scopes for an attribute with
71 * the given name and returns it, or <code>null</code> if no
72 * attribute exists with the current name.
73 *
74 * <p>The <code>propertyResolved</code> property of the
75 * <code>ELContext</code> object must be set to <code>true</code> by
76 * this resolver before returning if base is <code>null</code>. If
77 * this property is not <code>true</code> after this method is called,
78 * the caller should ignore the return value.</p>
79 *
80 * @param context The context of this evaluation.
81 * @param base Only <code>null</code> is handled by this resolver.
82 * Other values will result in an immediate return.
83 * @param property The name of the scoped attribute to resolve.
84 * @return If the <code>propertyResolved</code> property of
85 * <code>ELContext</code> was set to <code>true</code>, then
86 * the scoped attribute; otherwise undefined.
87 * @throws NullPointerException if context is <code>null</code>
88 * @throws ELException if an exception was thrown while performing
89 * the property or variable resolution. The thrown exception
90 * must be included as the cause property of this exception, if
91 * available.
92 */
93 public Object getValue(ELContext context,
94 Object base,
95 Object property) {
96
97 if (context == null) {
98 throw new NullPointerException();
99 }
100
101 if (base == null) {
102 context.setPropertyResolved(true);
103 if (property instanceof String) {
104 String attribute = (String) property;
105 PageContext ctxt = (PageContext)
106 context.getContext(JspContext.class);
107 return ctxt.findAttribute(attribute);
108 }
109 }
110 return null;
111 }
112
113 /**
114 * If the base object is <code>null</code>, returns
115 * <code>Object.class</code> to indicate that any type is valid to
116 * set for a scoped attribute.
117 *
118 * <p>The <code>propertyResolved</code> property of the
119 * <code>ELContext</code> object must be set to <code>true</code> by
120 * this resolver before returning if base is <code>null</code>. If
121 * this property is not <code>true</code> after this method is called,
122 * the caller should ignore the return value.</p>
123 *
124 * @param context The context of this evaluation.
125 * @param base Only <code>null</code> is handled by this resolver.
126 * Other values will result in an immediate return.
127 * @param property The name of the scoped attribute to resolve.
128 * @return If the <code>propertyResolved</code> property of
129 * <code>ELContext</code> was set to <code>true</code>, then
130 * <code>Object.class</code>; otherwise undefined.
131 * @throws NullPointerException if context is <code>null</code>
132 * @throws ELException if an exception was thrown while performing
133 * the property or variable resolution. The thrown exception
134 * must be included as the cause property of this exception, if
135 * available.
136 */
137 public Class<Object> getType(ELContext context,
138 Object base,
139 Object property) {
140
141 if (context == null) {
142 throw new NullPointerException();
143 }
144
145 if (base == null) {
146 context.setPropertyResolved(true);
147 return Object.class;
148 }
149 return null;
150 }
151
152
153 /**
154 * If the base object is <code>null</code>, sets an existing scoped
155 * attribute to the new value, or creates a new scoped attribute if one
156 * does not exist by this name.
157 *
158 * <p>If the provided attribute name matches the key of an attribute
159 * in page scope, request scope, session scope, or application scope, the
160 * corresponding attribute value will be replaced by the provided value.
161 * Otherwise, a new page scope attribute will be created with the
162 * given name and value.</p>
163 *
164 * <p>The <code>propertyResolved</code> property of the
165 * <code>ELContext</code> object must be set to <code>true</code> by
166 * this resolver before returning if base is <code>null</code>. If
167 * this property is not <code>true</code> after this method is called,
168 * the caller should ignore the return value.</p>
169 *
170 * @param context The context of this evaluation.
171 * @param base Only <code>null</code> is handled by this resolver.
172 * Other values will result in an immediate return.
173 * @param property The name of the scoped attribute to set.
174 * @param val The value for the scoped attribute.
175 * @throws NullPointerException if context is <code>null</code>.
176 * @throws ELException if an exception was thrown while performing
177 * the property or variable resolution. The thrown exception
178 * must be included as the cause property of this exception, if
179 * available.
180 */
181 public void setValue(ELContext context,
182 Object base,
183 Object property,
184 Object val) {
185 if (context == null) {
186 throw new NullPointerException();
187 }
188
189 if (base == null) {
190 context.setPropertyResolved(true);
191 if (property instanceof String) {
192 PageContext ctxt = (PageContext)
193 context.getContext(JspContext.class);
194 String attr = (String) property;
195 if (ctxt.getAttribute(attr, PageContext.REQUEST_SCOPE) != null)
196 ctxt.setAttribute(attr, val, PageContext.REQUEST_SCOPE);
197 else if (ctxt.getAttribute(attr, PageContext.SESSION_SCOPE) != null)
198 ctxt.setAttribute(attr, val, PageContext.SESSION_SCOPE);
199 else if (ctxt.getAttribute(attr, PageContext.APPLICATION_SCOPE) != null)
200 ctxt.setAttribute(attr, val, PageContext.APPLICATION_SCOPE);
201 else {
202 ctxt.setAttribute(attr, val, PageContext.PAGE_SCOPE);
203 }
204 }
205 }
206 }
207
208 /**
209 * If the base object is <code>null</code>, returns <code>false</code>
210 * to indicate that scoped attributes are never read-only.
211 *
212 * <p>The <code>propertyResolved</code> property of the
213 * <code>ELContext</code> object must be set to <code>true</code> by
214 * this resolver before returning if base is <code>null</code>. If
215 * this property is not <code>true</code> after this method is called,
216 * the caller should ignore the return value.</p>
217 *
218 * @param context The context of this evaluation.
219 * @param base Only <code>null</code> is handled by this resolver.
220 * Other values will result in an immediate return.
221 * @param property The name of the scoped attribute.
222 * @return If the <code>propertyResolved</code> property of
223 * <code>ELContext</code> was set to <code>true</code>, then
224 * <code>false</code>; otherwise undefined.
225 * @throws NullPointerException if context is <code>null</code>.
226 * @throws ELException if an exception was thrown while performing
227 * the property or variable resolution. The thrown exception
228 * must be included as the cause property of this exception, if
229 * available.
230 */
231 public boolean isReadOnly(ELContext context,
232 Object base,
233 Object property) {
234 if (context == null) {
235 throw new NullPointerException();
236 }
237
238 if (base == null) {
239 context.setPropertyResolved(true);
240 }
241 return false;
242 }
243
244 /**
245 * If the base object is <code>null</code>, returns an
246 * <code>Iterator</code> containing <code>FeatureDescriptor</code> objects
247 * with information about each scoped attribute resolved by this
248 * resolver. Otherwise, returns <code>null</code>.
249 *
250 * <p>The <code>Iterator</code> returned must contain one instance of
251 * {@link java.beans.FeatureDescriptor} for each scoped attribute found in
252 * any scope. Each info object contains information about
253 * a single scoped attribute, and is initialized as follows:
254 *
255 * <dl>
256 * <li>displayName - The name of the scoped attribute.</li>
257 * <li>name - Same as displayName property.</li>
258 * <li>shortDescription - A suitable description for the scoped
259 * attribute. Should include the attribute's current scope
260 * (page, request, session, application). Will vary by
261 * implementation.</li>
262 * <li>expert - <code>false</code></li>
263 * <li>hidden - <code>false</code></li>
264 * <li>preferred - <code>true</code></li>
265 * </dl>
266 * In addition, the following named attributes must be set in the
267 * returned <code>FeatureDescriptor</code>s:
268 * <dl>
269 * <li>{@link ELResolver#TYPE} - The current runtime type of the scoped attribute.</li>
270 * <li>{@link ELResolver#RESOLVABLE_AT_DESIGN_TIME} - <code>true</code>.</li>
271 * </dl></p>
272 *
273 * @param context The context of this evaluation.
274 * @param base Only <code>null</code> is handled by this resolver.
275 * Other values will result in a <code>null</code> return value.
276 * @return An <code>Iterator</code> containing one
277 * <code>FeatureDescriptor</code> object for each scoped attribute, or
278 * <code>null</code> if <code>base</code> is not <code>null</code>.
279 */
280 public Iterator<FeatureDescriptor> getFeatureDescriptors(
281 ELContext context,
282 Object base) {
283 Enumeration attrs;
284 ArrayList<FeatureDescriptor> list = new ArrayList<FeatureDescriptor>();
285 PageContext ctxt = (PageContext) context.getContext(JspContext.class);
286
287 attrs = ctxt.getAttributeNamesInScope(PageContext.PAGE_SCOPE);
288 while (attrs.hasMoreElements()) {
289 String name = (String) attrs.nextElement();
290 Object value = ctxt.getAttribute(name, PageContext.PAGE_SCOPE);
291 FeatureDescriptor descriptor = new FeatureDescriptor();
292 descriptor.setName(name);
293 descriptor.setDisplayName(name);
294 descriptor.setShortDescription("page scope attribute");
295 descriptor.setExpert(false);
296 descriptor.setHidden(false);
297 descriptor.setPreferred(true);
298 descriptor.setValue("type", value.getClass());
299 descriptor.setValue("resolvableAtDesignTime", Boolean.TRUE);
300 list.add(descriptor);
301 }
302
303 attrs = ctxt.getAttributeNamesInScope(PageContext.REQUEST_SCOPE);
304 while (attrs.hasMoreElements()) {
305 String name = (String) attrs.nextElement();
306 Object value = ctxt.getAttribute(name, PageContext.REQUEST_SCOPE);
307 FeatureDescriptor descriptor = new FeatureDescriptor();
308 descriptor.setName(name);
309 descriptor.setDisplayName(name);
310 descriptor.setShortDescription("request scope attribute");
311 descriptor.setExpert(false);
312 descriptor.setHidden(false);
313 descriptor.setPreferred(true);
314 descriptor.setValue("type", value.getClass());
315 descriptor.setValue("resolvableAtDesignTime", Boolean.TRUE);
316 list.add(descriptor);
317 }
318
319 attrs = ctxt.getAttributeNamesInScope(PageContext.SESSION_SCOPE);
320 while (attrs.hasMoreElements()) {
321 String name = (String) attrs.nextElement();
322 Object value = ctxt.getAttribute(name, PageContext.SESSION_SCOPE);
323 FeatureDescriptor descriptor = new FeatureDescriptor();
324 descriptor.setName(name);
325 descriptor.setDisplayName(name);
326 descriptor.setShortDescription("session scope attribute");
327 descriptor.setExpert(false);
328 descriptor.setHidden(false);
329 descriptor.setPreferred(true);
330 descriptor.setValue("type", value.getClass());
331 descriptor.setValue("resolvableAtDesignTime", Boolean.TRUE);
332 list.add(descriptor);
333 }
334
335 attrs = ctxt.getAttributeNamesInScope(PageContext.APPLICATION_SCOPE);
336 while (attrs.hasMoreElements()) {
337 String name = (String) attrs.nextElement();
338 Object value = ctxt.getAttribute(name, PageContext.APPLICATION_SCOPE);
339 FeatureDescriptor descriptor = new FeatureDescriptor();
340 descriptor.setName(name);
341 descriptor.setDisplayName(name);
342 descriptor.setShortDescription("application scope attribute");
343 descriptor.setExpert(false);
344 descriptor.setHidden(false);
345 descriptor.setPreferred(true);
346 descriptor.setValue("type", value.getClass());
347 descriptor.setValue("resolvableAtDesignTime", Boolean.TRUE);
348 list.add(descriptor);
349 }
350 return list.iterator();
351 }
352
353 /**
354 * If the base object is <code>null</code>, returns
355 * <code>String.class</code>. Otherwise, returns <code>null</code>.
356 *
357 * @param context The context of this evaluation.
358 * @param base Only <code>null</code> is handled by this resolver.
359 * Other values will result in a <code>null</code> return value.
360 * @return <code>null</code> if base is not <code>null</code>; otherwise
361 * <code>String.class</code>.
362 */
363 public Class<String> getCommonPropertyType(ELContext context,
364 Object base) {
365 if (base == null) {
366 return String.class;
367 }
368 return null;
369 }
370
371 }