001: package bsh.engine;
002:
003: import javax.script.ScriptContext;
004: import java.util.*;
005: import static javax.script.ScriptContext.*;
006:
007: /**
008: * This class implements an ENGINE_SCOPE centric Map view of the ScriptContext
009: * for engine implementations. This class can be used to simplify engine
010: * implementations which have the capability to bind their namespaces to Maps
011: * or other external interfaces.
012: *
013: * Get operations on this view delegate to the
014: * ScriptContext inheriting get() method that automatically traverses the
015: * binding scopes in order or precedence. Put operations on this view always
016: * store values in the ENGINE_SCOPE bindings. Other operations such as
017: * size() and contains() are implemented appropriately, but perhaps not as
018: * efficiently as possible.
019: *
020: */
021: public class ScriptContextEngineView implements Map<String, Object> {
022: ScriptContext context;
023:
024: public ScriptContextEngineView(ScriptContext context) {
025: this .context = context;
026: }
027:
028: /**
029: * Returns the number of unique object bindings in all scopes.
030: * (duplicate, shadowed, bindings count as a single binging).
031: */
032: public int size() {
033: return totalKeySet().size();
034: }
035:
036: /**
037: * Returns true if no bindings are present in any scope of the context.
038: */
039: public boolean isEmpty() {
040: return totalKeySet().size() == 0;
041: }
042:
043: /**
044: * Returns true if the key name is bound in any scope in the context.
045: * The key must be a String.
046: *
047: * @param key key whose presence in this map is to be tested.
048: *
049: * @return <tt>true</tt> if this map contains a mapping for the specified key.
050: *
051: * @throws ClassCastException if the key is of an inappropriate type for this
052: * map (optional).
053: * @throws NullPointerException if the key is <tt>null</tt> and this map does
054: * not permit <tt>null</tt> keys (optional).
055: */
056: // Why isn't the compiler allowing this?
057: //public boolean containsKey( String key )
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: *
070: * @param value value whose presence in this map is to be tested.
071: *
072: * @return <tt>true</tt> if this map maps one or more keys to the specified
073: * value.
074: *
075: * @throws ClassCastException if the value is of an inappropriate type for this
076: * map (optional).
077: * @throws NullPointerException if the value is <tt>null</tt> and this map does
078: * not permit <tt>null</tt> values (optional).
079: */
080: public boolean containsValue(Object value) {
081: Set values = totalValueSet();
082: return values.contains(value);
083: }
084:
085: /**
086: * Returns the value bound in the most specific (lowest numbered)
087: * bindings space for this key.
088: * key must be a String.
089: *
090: * @param key key whose associated value is to be returned.
091: *
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: *
095: * @throws ClassCastException if the key is of an inappropriate type for this
096: * map (optional).
097: * @throws NullPointerException if the key is <tt>null</tt> and this map does
098: * not permit <tt>null</tt> keys (optional).
099: * @see #containsKey(Object)
100: */
101: public Object get(Object key) {
102: return context.getAttribute((String) key);
103: }
104:
105: /**
106: * Set the key, value binding in the ENGINE_SCOPE of the context.
107: *
108: * @param key key with which the specified value is to be associated.
109: * @param value value to be associated with the specified key.
110: *
111: * @return previous value associated with specified key, or <tt>null</tt> if
112: * there was no mapping for key. A <tt>null</tt> return can also
113: * indicate that the map previously associated <tt>null</tt> with the
114: * specified key, if the implementation supports <tt>null</tt> values.
115: *
116: * @throws UnsupportedOperationException if the <tt>put</tt> operation is not
117: * supported by this map.
118: * @throws ClassCastException if the class of the specified key or value
119: * prevents it from being stored in this map.
120: * @throws IllegalArgumentException if some aspect of this key or value
121: * prevents it from being stored in this map.
122: * @throws NullPointerException if this map does not permit <tt>null</tt> keys
123: * or values, and the specified key or value is <tt>null</tt>.
124: */
125: public Object put(String key, Object value) {
126: Object oldValue = context.getAttribute(key, ENGINE_SCOPE);
127: context.setAttribute(key, value, ENGINE_SCOPE);
128: return oldValue;
129: }
130:
131: /**
132: * Put the bindings into the ENGINE_SCOPE of the context.
133: *
134: * @param t Mappings to be stored in this map.
135: *
136: * @throws UnsupportedOperationException if the <tt>putAll</tt> method is not
137: * supported by this map.
138: * @throws ClassCastException if the class of a key or value in the specified
139: * map prevents it from being stored in this map.
140: * @throws IllegalArgumentException some aspect of a key or value in the
141: * specified map prevents it from being stored in this map.
142: * @throws NullPointerException if the specified map is <tt>null</tt>, or if
143: * this map does not permit <tt>null</tt> keys or values, and the specified map
144: * contains <tt>null</tt> keys or values.
145: */
146: public void putAll(Map<? extends String, ? extends Object> t) {
147: context.getBindings(ENGINE_SCOPE).putAll(t);
148: }
149:
150: /**
151: * Removes the mapping from the engine scope.
152: * <p/>
153: * <p>Returns the value to which the map previously associated the key, or
154: * <tt>null</tt> if the map contained no mapping for this key. (A
155: * <tt>null</tt> return can also indicate that the map previously associated
156: * <tt>null</tt> with the specified key if the implementation supports
157: * <tt>null</tt> values.) The map will not contain a mapping for the specified
158: * key once the call returns.
159: *
160: * @param okey key whose mapping is to be removed from the map.
161: *
162: * @return previous value associated with specified key, or <tt>null</tt> if
163: * there was no mapping for key.
164: *
165: * @throws ClassCastException if the key is of an inappropriate type for this
166: * map (optional).
167: * @throws NullPointerException if the key is <tt>null</tt> and this map does
168: * not permit <tt>null</tt> keys (optional).
169: * @throws UnsupportedOperationException if the <tt>remove</tt> method is not
170: * supported by this map.
171: */
172: // Why is the compiler complaining about this?
173: //public Object remove( String key )
174: public Object remove(Object okey) {
175: // This shouldn't be necessary... we don't map Objects, Strings.
176: String key = (String) okey;
177: Object oldValue = context.getAttribute(key, ENGINE_SCOPE);
178: context.removeAttribute(key, ENGINE_SCOPE);
179: return oldValue;
180: }
181:
182: /**
183: * Removes all mappings from this map (optional operation).
184: *
185: * @throws UnsupportedOperationException clear is not supported by this map.
186: */
187: public void clear() {
188: context.getBindings(ENGINE_SCOPE).clear();
189: }
190:
191: /**
192: * Returns the total key set of all scopes.
193: * This method violates the Map contract by returning an unmodifiable set.
194: *
195: * @return a set view of the keys contained in this map.
196: */
197: public Set keySet() {
198: return totalKeySet();
199: }
200:
201: /**
202: *
203: * Returns the total values set of all scopes.
204: * This method violates the Map contract by returning an unmodifiable set.
205: *
206: * @return a collection view of the values contained in this map.
207: */
208: public Collection values() {
209: return totalValueSet();
210: }
211:
212: /**
213: * Returns a set view of the mappings contained in this map. Each element in
214: * the returned set is a {@link java.util.Map.Entry}. The set is backed by the
215: * map, so changes to the map are reflected in the set, and vice-versa. If the
216: * map is modified while an iteration over the set is in progress (except
217: * through the iterator's own <tt>remove</tt> operation, or through the
218: * <tt>setValue</tt> operation on a map entry returned by the iterator) the
219: * results of the iteration are undefined. The set supports element removal,
220: * which removes the corresponding mapping from the map, via the
221: * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>, <tt>removeAll</tt>,
222: * <tt>retainAll</tt> and <tt>clear</tt> operations. It does not support the
223: * <tt>add</tt> or <tt>addAll</tt> operations.
224: *
225: * @return a set view of the mappings contained in this map.
226: */
227: public Set<Entry<String, Object>> entrySet() {
228: throw new Error("unimplemented");
229: }
230:
231: private Set totalKeySet() {
232: Set keys = new HashSet();
233: List<Integer> scopes = context.getScopes();
234: for (int i : scopes) {
235: keys.addAll(context.getBindings(i).keySet());
236: }
237: return Collections.unmodifiableSet(keys);
238: }
239:
240: private Set totalValueSet() {
241: Set values = new HashSet();
242: List<Integer> scopes = context.getScopes();
243: for (int i : scopes) {
244: values.addAll(context.getBindings(i).values());
245: }
246: return Collections.unmodifiableSet(values);
247: }
248:
249: }
|