001: package org.mvel.jsr223;
002:
003: import javax.script.ScriptContext;
004: import javax.script.Bindings;
005: import java.util.*;
006: import static javax.script.ScriptContext.*;
007:
008: /**
009: * This class wraps around the ScriptContext to expose the ENGINE_SCOPE values
010: * for the MVEL engine. All methods invoked on this class are delegated to the
011: * ScriptContext. All MVELScriptContextMap#put(String, Object) are stored under
012: * the SCRIPT_ENGINE scope.
013: * @author Richard L. Burton III
014: * @version 1.0
015: * @since MVEL 1.2
016: */
017: public class MVELScriptContextMap implements Map<String, Object> {
018:
019: /**
020: * The ScriptContext that was wrapped.
021: */
022: private ScriptContext context;
023:
024: /**
025: * Constructs a new MVELScriptContextMap that wraps around the provided
026: * ScriptContext object.
027: * @param context The ScriptContext that'll be wrapped around.
028: */
029: public MVELScriptContextMap(ScriptContext context) {
030: this .context = context;
031: }
032:
033: /**
034: * Returns the number of unique object bindings in all scopes.
035: * (duplicate, shadowed, bindings count as a single binging).
036: */
037: public int size() {
038: return getKeySet().size();
039: }
040:
041: /**
042: * Returns true if no bindings are present in any scope of the context.
043: */
044: public boolean isEmpty() {
045: return getKeySet().size() == 0;
046: }
047:
048: /**
049: * Returns true if the key name is bound in any scope in the context.
050: * The key must be a String.
051: * @param key key whose presence in this map is to be tested.
052: * @return <tt>true</tt> if this map contains a mapping for the specified key.
053: * @throws ClassCastException if the key is of an inappropriate type for this
054: * map (optional).
055: * @throws NullPointerException if the key is <tt>null</tt> and this map does
056: * not permit <tt>null</tt> keys (optional).
057: */
058: public boolean containsKey(Object key) {
059: return context.getAttribute((String) key) != null;
060: }
061:
062: /**
063: * Returns <tt>true</tt> if this map maps one or more keys to the specified
064: * value. More formally, returns <tt>true</tt> if and only if this map
065: * contains at least one mapping to a value <tt>v</tt> such that
066: * <tt>(value==null ? v==null : value.equals(v))</tt>. This operation will
067: * probably require time linear in the map size for most implementations of the
068: * <tt>Map</tt> interface.
069: * @param value value whose presence in this map is to be tested.
070: * @return <tt>true</tt> if this map maps one or more keys to the specified
071: * value.
072: * @throws ClassCastException if the value is of an inappropriate type for this
073: * map (optional).
074: * @throws NullPointerException if the value is <tt>null</tt> and this map does
075: * not permit <tt>null</tt> values (optional).
076: */
077: public boolean containsValue(Object value) {
078: List<Integer> scopes = context.getScopes();
079: for (int i : scopes) {
080: if (context.getBindings(i).containsValue(value)) {
081: return true;
082: }
083: }
084: return false;
085: }
086:
087: /**
088: * Returns the value bound in the most specific (lowest numbered)
089: * bindings space for this key.
090: * key must be a String.
091: * @param key key whose associated value is to be returned.
092: * @return the value to which this map maps the specified key, or <tt>null</tt>
093: * if the map contains no mapping for this key.
094: * @throws ClassCastException if the key is of an inappropriate type for this
095: * map (optional).
096: * @throws NullPointerException if the key is <tt>null</tt> and this map does
097: * not permit <tt>null</tt> keys (optional).
098: * @see #containsKey(Object)
099: */
100: public Object get(Object key) {
101: return context.getAttribute((String) key);
102: }
103:
104: /**
105: * Set the key, value binding in the ENGINE_SCOPE of the context.
106: * @param key key with which the specified value is to be associated.
107: * @param value value to be associated with the specified key.
108: * @return previous value associated with specified key, or <tt>null</tt> if
109: * there was no mapping for key. A <tt>null</tt> return can also
110: * indicate that the map previously associated <tt>null</tt> with the
111: * specified key, if the implementation supports <tt>null</tt> values.
112: * @throws UnsupportedOperationException if the <tt>put</tt> operation is not
113: * supported by this map.
114: * @throws ClassCastException if the class of the specified key or value
115: * prevents it from being stored in this map.
116: * @throws IllegalArgumentException if some aspect of this key or value
117: * prevents it from being stored in this map.
118: * @throws NullPointerException if this map does not permit <tt>null</tt> keys
119: * or values, and the specified key or value is <tt>null</tt>.
120: */
121: public Object put(String key, Object value) {
122: Object oldValue = context.getAttribute(key, ENGINE_SCOPE);
123: context.setAttribute(key, value, ENGINE_SCOPE);
124: return oldValue;
125: }
126:
127: /**
128: * All put operations are done at the ENGINE_SCOPE level.
129: * @param map Mappings to be stored in this map.
130: * @throws UnsupportedOperationException if the <tt>putAll</tt> method is not
131: * supported by this map.
132: * @throws ClassCastException if the class of a key or value in the specified
133: * map prevents it from being stored in this map.
134: * @throws IllegalArgumentException some aspect of a key or value in the
135: * specified map prevents it from being stored in this map.
136: * @throws NullPointerException if the specified map is <tt>null</tt>, or if
137: * this map does not permit <tt>null</tt> keys or values, and the specified map
138: * contains <tt>null</tt> keys or values.
139: */
140: public void putAll(Map<? extends String, ? extends Object> map) {
141: Bindings bindings = context.getBindings(ENGINE_SCOPE);
142: bindings.putAll(map);
143: }
144:
145: /**
146: * Removes the mapping from the engine scope.
147: * <p/>
148: * <p>Returns the value to which the map previously associated the key, or
149: * <tt>null</tt> if the map contained no mapping for this key. (A
150: * <tt>null</tt> return can also indicate that the map previously associated
151: * <tt>null</tt> with the specified key if the implementation supports
152: * <tt>null</tt> values.) The map will not contain a mapping for the specified
153: * key once the call returns.
154: * @param okey key whose mapping is to be removed from the map.
155: * @return previous value associated with specified key, or <tt>null</tt> if
156: * there was no mapping for key.
157: * @throws ClassCastException if the key is of an inappropriate type for this
158: * map (optional).
159: * @throws NullPointerException if the key is <tt>null</tt> and this map does
160: * not permit <tt>null</tt> keys (optional).
161: * @throws UnsupportedOperationException if the <tt>remove</tt> method is not
162: * supported by this map.
163: */
164: public Object remove(Object okey) {
165: String key = (String) okey;
166: Object oldValue = context.getAttribute(key, ENGINE_SCOPE);
167: context.removeAttribute(key, ENGINE_SCOPE);
168: return oldValue;
169: }
170:
171: /**
172: * Removes all mappings from this map (optional operation).
173: * @throws UnsupportedOperationException clear is not supported by this map.
174: */
175: public void clear() {
176: context.getBindings(ENGINE_SCOPE).clear();
177: }
178:
179: /**
180: * Returns the total key set of all scopes.
181: * This method violates the Map contract by returning an unmodifiable set.
182: * @return a set view of the keys contained in this map.
183: */
184: public Set<String> keySet() {
185: return getKeySet();
186: }
187:
188: /**
189: * Returns the total values set of all scopes.
190: * This method violates the Map contract by returning an unmodifiable set.
191: * @return a collection view of the values contained in this map.
192: */
193: public Collection<Object> values() {
194: return getValueSet();
195: }
196:
197: /**
198: * Returns a set view of the mappings contained in this map. Each element in
199: * the returned set is a {@link java.util.Map.Entry}. The set is backed by the
200: * map, so changes to the map are reflected in the set, and vice-versa. If the
201: * map is modified while an iteration over the set is in progress (except
202: * through the iterator's own <tt>remove</tt> operation, or through the
203: * <tt>setValue</tt> operation on a map entry returned by the iterator) the
204: * results of the iteration are undefined. The set supports element removal,
205: * which removes the corresponding mapping from the map, via the
206: * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>, <tt>removeAll</tt>,
207: * <tt>retainAll</tt> and <tt>clear</tt> operations. It does not support the
208: * <tt>add</tt> or <tt>addAll</tt> operations.
209: * @return a set view of the mappings contained in this map.
210: */
211: public Set<Entry<String, Object>> entrySet() {
212: throw new UnsupportedOperationException(
213: "This operation is unsupported.");
214: }
215:
216: /**
217: * Constructs a Set with all of the keys from the various
218: * scopes within the ScriptContext.
219: * @return A Set<String> for all keys within the ScriptContext.
220: */
221: private Set<String> getKeySet() {
222: Set<String> keys = new HashSet<String>();
223: List<Integer> scopes = context.getScopes();
224: for (int i : scopes) {
225: keys.addAll(context.getBindings(i).keySet());
226: }
227: return Collections.unmodifiableSet(keys);
228: }
229:
230: /**
231: * Constructs a Set with all of the values from the various
232: * scopes within the ScriptContext.
233: * @return A Set<String> for all values within the ScriptContext.
234: */
235: private Set<Object> getValueSet() {
236: Set<Object> values = new HashSet<Object>();
237: List<Integer> scopes = context.getScopes();
238: for (int i : scopes) {
239: values.addAll(context.getBindings(i).values());
240: }
241: return Collections.unmodifiableSet(values);
242: }
243:
244: }
|