001: /*
002: * The contents of this file are subject to the terms
003: * of the Common Development and Distribution License
004: * (the "License"). You may not use this file except
005: * in compliance with the License.
006: *
007: * You can obtain a copy of the license at
008: * glassfish/bootstrap/legal/CDDLv1.0.txt or
009: * https://glassfish.dev.java.net/public/CDDLv1.0.html.
010: * See the License for the specific language governing
011: * permissions and limitations under the License.
012: *
013: * When distributing Covered Code, include this CDDL
014: * HEADER in each file and include the License file at
015: * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
016: * add the following below this CDDL HEADER, with the
017: * fields enclosed by brackets "[]" replaced with your
018: * own identifying information: Portions Copyright [yyyy]
019: * [name of copyright owner]
020: *
021: * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
022: */
023: package javax.el;
024:
025: import java.beans.FeatureDescriptor;
026: import java.util.ArrayList;
027: import java.util.Enumeration;
028: import java.util.Iterator;
029: import java.util.List;
030: import java.util.MissingResourceException;
031: import java.util.ResourceBundle;
032:
033: /**
034: * Defines property resolution behavior on instances of
035: * {@link java.util.ResourceBundle}.
036: *
037: * <p>
038: * This resolver handles base objects of type
039: * <code>java.util.ResourceBundle</code>. It accepts any object as a property
040: * and coerces it to a <code>java.lang.String</code> for invoking
041: * {@link java.util.ResourceBundle#getObject(java.lang.String)}.
042: * </p>
043: *
044: * <p>
045: * This resolver is read only and will throw a
046: * {@link PropertyNotWritableException} if <code>setValue</code> is called.
047: * </p>
048: *
049: * <p>
050: * <code>ELResolver</code>s are combined together using
051: * {@link CompositeELResolver}s, to define rich semantics for evaluating an
052: * expression. See the javadocs for {@link ELResolver} for details.
053: * </p>
054: *
055: * @see CompositeELResolver
056: * @see ELResolver
057: * @see java.util.ResourceBundle
058: * @since JSP 2.1
059: */
060: public class ResourceBundleELResolver extends ELResolver {
061:
062: /**
063: * If the base object is an instance of <code>ResourceBundle</code>,
064: * the provided property will first be coerced to a <code>String</code>.
065: * The <code>Object</code> returned by <code>getObject</code> on
066: * the base <code>ResourceBundle</code> will be returned.
067: * </p>
068: * If the base is <code>ResourceBundle</code>, the
069: * <code>propertyResolved</code> property of the <code>ELContext</code>
070: * object must be set to <code>true</code> by this resolver, before
071: * returning. If this property is not <code>true</code> after this method
072: * is called, the caller should ignore the return value.
073: * </p>
074: * @param context
075: * The context of this evaluation.
076: * @param base
077: * The ResourceBundle to analyze.
078: * @param property
079: * The name of the property to analyze. Will be coerced to a
080: * <code>String</code>.
081: * @return If the <code>propertyResolved</code> property of
082: * <code>ELContext</code> was set to <code>true</code>, then
083: * <code>null</code> if property is <code>null</code>;
084: * otherwise the <code>Object</code> for the given key
085: * (property coerced to <code>String</code>) from the
086: * <code>ResourceBundle</code>.
087: * If no object for the given key can be found, then the
088: * <code>String</code> "???" + key + "???".
089: * @throws NullPointerException
090: * if context is <code>null</code>
091: * @throws ELException
092: * if an exception was thrown while performing the property or
093: * variable resolution. The thrown exception must be included as
094: * the cause property of this exception, if available.
095: */
096: public Object getValue(ELContext context, Object base,
097: Object property) {
098: if (context == null) {
099: throw new NullPointerException();
100: }
101:
102: if (base instanceof ResourceBundle) {
103: context.setPropertyResolved(true);
104: if (property != null) {
105: try {
106: return ((ResourceBundle) base).getObject(property
107: .toString());
108: } catch (MissingResourceException e) {
109: return "???" + property + "???";
110: }
111: }
112: }
113: return null;
114: }
115:
116: /**
117: * If the base object is an instance of <code>ResourceBundle</code>,
118: * return <code>null</code>, since the resolver is read only.
119: *
120: * <p>
121: * If the base is <code>ResourceBundle</code>, the
122: * <code>propertyResolved</code> property of the <code>ELContext</code>
123: * object must be set to <code>true</code> by this resolver, before
124: * returning. If this property is not <code>true</code> after this method
125: * is called, the caller should ignore the return value.
126: * </p>
127: *
128: * @param context
129: * The context of this evaluation.
130: * @param base
131: * The ResourceBundle to analyze.
132: * @param property
133: * The name of the property to analyze.
134: * @return If the <code>propertyResolved</code> property of
135: * <code>ELContext</code> was set to <code>true</code>, then
136: * <code>null</code>; otherwise undefined.
137: * @throws NullPointerException
138: * if context is <code>null</code>
139: */
140: public Class<?> getType(ELContext context, Object base,
141: Object property) {
142: if (context == null) {
143: throw new NullPointerException();
144: }
145:
146: if (base instanceof ResourceBundle) {
147: context.setPropertyResolved(true);
148: }
149: return null;
150: }
151:
152: /**
153: * If the base object is a ResourceBundle, throw a
154: * {@link PropertyNotWritableException}.
155: *
156: * @param context
157: * The context of this evaluation.
158: * @param base
159: * The ResourceBundle to be modified. Only bases that are of type
160: * ResourceBundle are handled.
161: * @param property
162: * The String property to use.
163: * @param value
164: * The value to be set.
165: * @throws NullPointerException
166: * if context is <code>null</code>.
167: * @throws PropertyNotWritableException
168: * Always thrown if base is an instance of ReasourceBundle.
169: */
170: public void setValue(ELContext context, Object base,
171: Object property, Object value) {
172: if (context == null) {
173: throw new NullPointerException();
174: }
175:
176: if (base instanceof ResourceBundle) {
177: context.setPropertyResolved(true);
178: throw new PropertyNotWritableException(
179: "ResourceBundles are immutable");
180: }
181: }
182:
183: /**
184: * If the base object is not null and an instanceof {@link ResourceBundle},
185: * return <code>true</code>.
186: *
187: * @param context
188: * The context of this evaluation.
189: * @param base
190: * The ResourceBundle to be modified. Only bases that are of type
191: * ResourceBundle are handled.
192: * @param property
193: * The String property to use.
194: * @return If the <code>propertyResolved</code> property of
195: * <code>ELContext</code> was set to <code>true</code>, then
196: * <code>true</code>; otherwise undefined.
197: * @throws NullPointerException
198: * if context is <code>null</code>
199: */
200: public boolean isReadOnly(ELContext context, Object base,
201: Object property) {
202: if (context == null) {
203: throw new NullPointerException();
204: }
205: if (base instanceof ResourceBundle) {
206: context.setPropertyResolved(true);
207: return true;
208: }
209: return false;
210: }
211:
212: /**
213: * If the base object is a ResourceBundle, returns an <code>Iterator</code>
214: * containing the set of keys available in the <code>ResourceBundle</code>.
215: * Otherwise, returns <code>null</code>.
216: *
217: * <p>
218: * The <code>Iterator</code> returned must contain zero or more instances
219: * of {@link java.beans.FeatureDescriptor}. Each info object contains
220: * information about a key in the ResourceBundle, and is initialized as
221: * follows:
222: * <dl>
223: * <li>displayName - The <code>String</code> key
224: * <li>name - Same as displayName property.</li>
225: * <li>shortDescription - Empty string</li>
226: * <li>expert - <code>false</code></li>
227: * <li>hidden - <code>false</code></li>
228: * <li>preferred - <code>true</code></li>
229: * </dl>
230: * In addition, the following named attributes must be set in the returned
231: * <code>FeatureDescriptor</code>s:
232: * <dl>
233: * <li>{@link ELResolver#TYPE} - <code>String.class</code></li>
234: * <li>{@link ELResolver#RESOLVABLE_AT_DESIGN_TIME} - <code>true</code></li>
235: * </dl>
236: * </p>
237: *
238: * @param context
239: * The context of this evaluation.
240: * @param base
241: * The bundle whose keys are to be iterated over. Only bases of
242: * type <code>ResourceBundle</code> are handled by this
243: * resolver.
244: * @return An <code>Iterator</code> containing zero or more (possibly
245: * infinitely more) <code>FeatureDescriptor</code> objects, each
246: * representing a key in this bundle, or <code>null</code> if the
247: * base object is not a ResourceBundle.
248: */
249: public Iterator getFeatureDescriptors(ELContext context, Object base) {
250: if (base instanceof ResourceBundle) {
251: ResourceBundle bundle = (ResourceBundle) base;
252: List features = new ArrayList();
253: String key = null;
254: FeatureDescriptor desc = null;
255: for (Enumeration e = bundle.getKeys(); e.hasMoreElements();) {
256: key = (String) e.nextElement();
257: desc = new FeatureDescriptor();
258: desc.setDisplayName(key);
259: desc.setExpert(false);
260: desc.setHidden(false);
261: desc.setName(key);
262: desc.setPreferred(true);
263: desc.setValue(TYPE, String.class);
264: desc.setValue(RESOLVABLE_AT_DESIGN_TIME, Boolean.TRUE);
265: features.add(desc);
266: }
267: return features.iterator();
268: }
269: return null;
270: }
271:
272: /**
273: * If the base object is a ResourceBundle, returns the most general type
274: * that this resolver accepts for the <code>property</code> argument.
275: * Otherwise, returns <code>null</code>.
276: *
277: * <p>
278: * Assuming the base is a <code>ResourceBundle</code>, this method will
279: * always return <code>String.class</code>.
280: *
281: * @param context
282: * The context of this evaluation.
283: * @param base
284: * The bundle to analyze. Only bases of type
285: * <code>ResourceBundle</code> are handled by this resolver.
286: * @return <code>null</code> if base is not a <code>ResourceBundle</code>;
287: * otherwise <code>String.class</code>.
288: */
289: public Class<?> getCommonPropertyType(ELContext context, Object base) {
290: if (base instanceof ResourceBundle) {
291: return String.class;
292: }
293: return null;
294: }
295: }
|