001: package org.gjt.sp.jedit.bsh;
002:
003: import java.util.*;
004:
005: /**
006: A namespace which maintains an external map of values held in variables in
007: its scope. This mechanism provides a standard collections based interface
008: to the namespace as well as a convenient way to export and view values of
009: the namespace without the ordinary BeanShell wrappers.
010: </p>
011:
012: Variables are maintained internally in the normal fashion to support
013: meta-information (such as variable type and visibility modifiers), but
014: exported and imported in a synchronized way. Variables are exported each
015: time they are written by BeanShell. Imported variables from the map appear
016: in the BeanShell namespace as untyped variables with no modifiers and
017: shadow any previously defined variables in the scope.
018: <p/>
019:
020: Note: this class is inherentely dependent on Java 1.2, however it is not
021: used directly by the core as other than type NameSpace, so no dependency is
022: introduced.
023: */
024: /*
025: Implementation notes: bsh methods are not currently expored to the
026: external namespace. All that would be required to add this is to override
027: setMethod() and provide a friendlier view than vector (currently used) for
028: overloaded forms (perhaps a map by method SignatureKey).
029: */
030: public class ExternalNameSpace extends NameSpace {
031: private Map externalMap;
032:
033: public ExternalNameSpace() {
034: this (null, "External Map Namespace", null);
035: }
036:
037: /**
038: */
039: public ExternalNameSpace(NameSpace parent, String name,
040: Map externalMap) {
041: super (parent, name);
042:
043: if (externalMap == null)
044: externalMap = new HashMap();
045:
046: this .externalMap = externalMap;
047:
048: }
049:
050: /**
051: Get the map view of this namespace.
052: */
053: public Map getMap() {
054: return externalMap;
055: }
056:
057: /**
058: Set the external Map which to which this namespace synchronizes.
059: The previous external map is detached from this namespace. Previous
060: map values are retained in the external map, but are removed from the
061: BeanShell namespace.
062: */
063: public void setMap(Map map) {
064: // Detach any existing namespace to preserve it, then clear this
065: // namespace and set the new one
066: this .externalMap = null;
067: clear();
068: this .externalMap = map;
069: }
070:
071: /**
072: */
073: void setVariable(String name, Object value, boolean strictJava,
074: boolean recurse) throws UtilEvalError {
075: super .setVariable(name, value, strictJava, recurse);
076: putExternalMap(name, value);
077: }
078:
079: /**
080: */
081: public void unsetVariable(String name) {
082: super .unsetVariable(name);
083: externalMap.remove(name);
084: }
085:
086: /**
087: */
088: public String[] getVariableNames() {
089: // union of the names in the internal namespace and external map
090: Set nameSet = new HashSet();
091: String[] nsNames = super .getVariableNames();
092: nameSet.addAll(Arrays.asList(nsNames));
093: nameSet.addAll(externalMap.keySet());
094: return (String[]) nameSet.toArray(new String[0]);
095: }
096:
097: /**
098: */
099: /*
100: Notes: This implmenetation of getVariableImpl handles the following
101: cases:
102: 1) var in map not in local scope - var was added through map
103: 2) var in map and in local scope - var was added through namespace
104: 3) var not in map but in local scope - var was removed via map
105: 4) var not in map and not in local scope - non-existent var
106: */
107: protected Variable getVariableImpl(String name, boolean recurse)
108: throws UtilEvalError {
109: // check the external map for the variable name
110: Object value = externalMap.get(name);
111:
112: Variable var;
113: if (value == null) {
114: // The var is not in external map and it should therefore not be
115: // found in local scope (it may have been removed via the map).
116: // Clear it prophalactically.
117: super .unsetVariable(name);
118:
119: // Search parent for var if applicable.
120: var = super .getVariableImpl(name, recurse);
121: } else {
122: // Var in external map may be found in local scope with type and
123: // modifier info.
124: Variable localVar = super .getVariableImpl(name, false);
125:
126: // If not in local scope then it was added via the external map,
127: // we'll wrap it and pass it along. Else we'll use the local
128: // version.
129: if (localVar == null)
130: var = new Variable(name, (Class) null, value,
131: (Modifiers) null);
132: else
133: var = localVar;
134: }
135:
136: return var;
137: }
138:
139: /**
140: */
141: /*
142: Note: the meaning of getDeclaredVariables() is not entirely clear, but
143: the name (and current usage in class generation support) suggests that
144: untyped variables should not be inclueded. Therefore we do not
145: currently have to add the external names here.
146: */
147: public Variable[] getDeclaredVariables() {
148: return super .getDeclaredVariables();
149: }
150:
151: /**
152: */
153: public void setTypedVariable(String name, Class type, Object value,
154: Modifiers modifiers) throws UtilEvalError {
155: super .setTypedVariable(name, type, value, modifiers);
156: putExternalMap(name, value);
157: }
158:
159: /*
160: Note: we could override this method to allow bsh methods to appear in
161: the external map.
162: */
163: public void setMethod(String name, BshMethod method)
164: throws UtilEvalError {
165: super .setMethod(name, method);
166: }
167:
168: /*
169: Note: kind of far-fetched, but... we could override this method to
170: allow bsh methods to be inserted into this namespace via the map.
171: */
172: public BshMethod getMethod(String name, Class[] sig,
173: boolean declaredOnly) throws UtilEvalError {
174: return super .getMethod(name, sig, declaredOnly);
175: }
176:
177: /*
178: Note: this method should be overridden to add the names from the
179: external map, as is done in getVariableNames();
180: */
181: protected void getAllNamesAux(Vector vec) {
182: super .getAllNamesAux(vec);
183: }
184:
185: /**
186: Clear all variables, methods, and imports from this namespace and clear
187: all values from the external map (via Map clear()).
188: */
189: public void clear() {
190: super .clear();
191: externalMap.clear();
192: }
193:
194: /**
195: Place an unwrapped value in the external map.
196: BeanShell primitive types are represented by their object wrappers, so
197: it is not possible to differentiate between wrapper types and primitive
198: types via the external Map.
199: */
200: protected void putExternalMap(String name, Object value) {
201: if (value instanceof Variable)
202: try {
203: value = unwrapVariable((Variable) value);
204: } catch (UtilEvalError ute) {
205: // There should be no case for this. unwrapVariable throws
206: // UtilEvalError in some cases where it holds an LHS or array
207: // index.
208: throw new InterpreterError("unexpected UtilEvalError");
209: }
210:
211: if (value instanceof Primitive)
212: value = Primitive.unwrap((Primitive) value);
213:
214: externalMap.put(name, value);
215: }
216: }
|