001: /*
002: * BeanEventMgr.java --
003: *
004: * The Bean Event Manager: This class manages beans event
005: * handlers for a Tcl interpreter.
006: *
007: * Copyright (c) 1997 Sun Microsystems, Inc.
008: *
009: * See the file "license.terms" for information on usage and
010: * redistribution of this file, and for a DISCLAIMER OF ALL
011: * WARRANTIES.
012: *
013: * RCS: @(#) $Id: BeanEventMgr.java,v 1.1.1.1 1998/10/14 21:09:14 cvsadmin Exp $
014: *
015: */
016:
017: package tcl.lang;
018:
019: import java.lang.reflect.*;
020: import java.util.*;
021: import java.beans.*;
022:
023: /*
024: * This class manages beans event handlers for a Tcl interpreter:
025: * the event object stack, etc.
026: */
027:
028: class BeanEventMgr implements AssocData {
029:
030: /*
031: * Stores all of the available event adaptor classes.
032: */
033:
034: private static Hashtable adaptorClsTab = new Hashtable();
035:
036: /*
037: * The class loader for loading automatically generated event adaptor
038: * classes.
039: */
040:
041: private static AdaptorClassLoader adaptorLoader = new AdaptorClassLoader();
042:
043: /*
044: * When a event handler is invoked, it is given a set of parameters
045: * (stored in an Object array.) The eventParamSetStack variable is
046: * used to store the parameter sets in a LIFO order when nested event
047: * handlers are invoked. Event parameters can be queried by the
048: * "java::event" command.
049: */
050:
051: Stack eventParamSetStack;
052:
053: /*
054: *----------------------------------------------------------------------
055: *
056: * BeanEventMgr --
057: *
058: * Creates a new BeanEventMgr instance.
059: *
060: * Side effects:
061: * Member fields are initialized.
062: *
063: *----------------------------------------------------------------------
064: */
065:
066: private BeanEventMgr() {
067: eventParamSetStack = new Stack();
068: }
069:
070: /*
071: *----------------------------------------------------------------------
072: *
073: * getBeanEventMgr --
074: *
075: * Returns the BeanEventMgr instance for the given interp. A new
076: * BeanEventMgr is created if no such BeanEventMgr exists for
077: * the interp.
078: *
079: * Results:
080: * The BeanEventMgr instance for the given interp.
081: *
082: * Side effects:
083: * A new BeanEventMgr may be created and registered as an
084: * AssocData in the given interp.
085: *
086: *----------------------------------------------------------------------
087: */
088:
089: static BeanEventMgr getBeanEventMgr(Interp interp) // Query the BeanEventMgr of this interp.
090: {
091: BeanEventMgr mgr = (BeanEventMgr) interp
092: .getAssocData("tclBeanEvent");
093: if (mgr == null) {
094: mgr = new BeanEventMgr();
095: interp.setAssocData("tclBeanEvent", mgr);
096: }
097:
098: return mgr;
099: }
100:
101: /*
102: *----------------------------------------------------------------------
103: *
104: * pushEventParamSet --
105: *
106: * Pushes a set of event parameters to the top of the stack.
107: *
108: * Results:
109: * None.
110: *
111: * Side effects:
112: * The set of parameters are pushed to the top of the stack.
113: *
114: *----------------------------------------------------------------------
115: */
116:
117: void pushEventParamSet(BeanEventParamSet p) // The parameters to push to the top of the
118: // stack.
119: {
120: eventParamSetStack.push(p);
121: }
122:
123: /*
124: *----------------------------------------------------------------------
125: *
126: * popEventParamSet --
127: *
128: * Pops the set of event parameters from the top of the stack.
129: *
130: * Results:
131: * None.
132: *
133: * Side effects:
134: * The size of the event parameter set stack is reduced by one.
135: *
136: *----------------------------------------------------------------------
137: */
138:
139: void popEventParamSet() throws EmptyStackException // If the stack is already empty.
140: {
141: eventParamSetStack.pop();
142: }
143:
144: /*
145: *----------------------------------------------------------------------
146: *
147: * peekEventParamSet --
148: *
149: * Returns the set of event parameters at the top of the stack.
150: *
151: * Results:
152: * If the event parameter stack is not empty, returns the set of
153: * parameters at the top of the stack. Otherwise, returns null.
154: *
155: * Side effects:
156: * None.
157: *
158: *----------------------------------------------------------------------
159: */
160:
161: BeanEventParamSet peekEventParamSet() {
162: if (eventParamSetStack.size() == 0) {
163: return null;
164: } else {
165: return (BeanEventParamSet) eventParamSetStack.peek();
166: }
167: }
168:
169: /*
170: *----------------------------------------------------------------------
171: *
172: * disposeAssocData --
173: *
174: * This method is called when the interpreter is destroyed or
175: * when Interp.deleteAssocData is called on a registered
176: * AssocData instance.
177: *
178: * Results:
179: * None.
180: *
181: * Side effects:
182: * Removes any bgerror's that haven't been reported.
183: *
184: *----------------------------------------------------------------------
185: */
186:
187: public void disposeAssocData(Interp interp) // The interpreter in which this AssocData
188: // instance is registered in.
189: {
190: eventParamSetStack = null;
191: }
192:
193: /*
194: *----------------------------------------------------------------------
195: *
196: * setBinding --
197: *
198: * Sets the Tcl command to be executed when the given event fires
199: * in the reflectObj. A event adaptor is created when necessary.
200: *
201: * Results:
202: * None.
203: *
204: * Side effects:
205: * If the reflectObj doesn't yet have an EventAdaptor to handle
206: * the event, we will attempt to create it. This may cause an
207: * appropriate event adaptor class to be generated and loaded
208: * into the JVM; the EventAdaptor will be instantiated and
209: * registered as a listener of the given EventSet on the javaObj.
210: *
211: *----------------------------------------------------------------------
212: */
213:
214: void setBinding(Interp interp, // Current interpreter.
215: ReflectObject reflectObj, // The reflection object to create
216: // event binding for.
217: EventSetDescriptor eventSet, // The EventSet to bind to.
218: Method event, // Identifies a specific event in
219: // the EventSet to create a
220: // binding for.
221: TclObject command) // The command to execute when the
222: // given event fires.
223: throws TclException // If the adaptor class cannot be
224: // generated, or if the adaptor
225: // cannot be instantiated.
226: {
227: EventAdaptor adaptor = null;
228:
229: if (reflectObj.bindings == null) {
230: reflectObj.bindings = new Hashtable();
231: } else {
232: adaptor = (EventAdaptor) reflectObj.bindings.get(eventSet);
233: }
234:
235: if (adaptor == null) {
236: Class lsnType = eventSet.getListenerType();
237: Class adaptorCls = (Class) adaptorClsTab.get(lsnType);
238:
239: if (adaptorCls == null) {
240: /*
241: * We have never processed this type of EventSet yet. Generate
242: * an appropriate event adaptor class and load it
243: * into the JVM.
244: */
245:
246: adaptorCls = adaptorLoader.loadEventAdaptor(interp,
247: eventSet);
248: adaptorClsTab.put(lsnType, adaptorCls);
249: }
250:
251: try {
252: adaptor = (EventAdaptor) adaptorCls.newInstance();
253: } catch (InstantiationException e1) {
254: /*
255: * adaptor will remain null. This will trigger the
256: * exception later on.
257: */
258: } catch (IllegalAccessException e2) {
259: /*
260: * adaptor will remain null. This will trigger the
261: * exception later on.
262: */
263: }
264:
265: if (adaptor == null) {
266: throw new TclException(interp,
267: "couldn't instantiate adaptor class for eventset \""
268: + eventSet + "\"");
269: }
270:
271: adaptor.init(interp, reflectObj.javaObj, eventSet);
272:
273: /*
274: * Save the adaptor -- we only need a single adaptor for each
275: * EventSet to handle all possible events in this set.
276: */
277:
278: reflectObj.bindings.put(eventSet, adaptor);
279: }
280:
281: if (command.toString().length() > 0) {
282: adaptor.setCallback(event.getName(), command);
283: } else {
284: /*
285: * The callback command is the empty string. This means remove
286: * any existing callback scripts. If no more callback scripts
287: * are registered in the adaptor, we'll remove it from the
288: * hashtable.
289: */
290:
291: if (adaptor.deleteCallback(event.getName()) == 0) {
292: reflectObj.bindings.remove(eventSet);
293: if (reflectObj.bindings.size() == 0) {
294: reflectObj.bindings = null;
295: }
296: }
297: }
298: }
299:
300: /*
301: *----------------------------------------------------------------------
302: *
303: * getBinding --
304: *
305: * Queries the command to be executed when the given event fires
306: * in this object.
307: *
308: * Results:
309: * The command to execute when the event fires. null if no such
310: * command has be registered with the setBinding() method.
311: *
312: * Side effects:
313: * None.
314: *
315: *----------------------------------------------------------------------
316: */
317:
318: TclObject getBinding(Interp interp, // Current interpreter.
319: ReflectObject reflectObj, // The reflection object to query.
320: EventSetDescriptor eventSet, // The EventSet to bind to.
321: Method event) // Identifies a specific event in
322: // the EventSet to query the
323: // binding for.
324: {
325: EventAdaptor adaptor = null;
326:
327: if (reflectObj.bindings != null) {
328: adaptor = (EventAdaptor) reflectObj.bindings.get(eventSet);
329: }
330:
331: if (adaptor == null) {
332: return null;
333: } else {
334: return adaptor.getCallback(event.getName());
335: }
336: }
337:
338: /*
339: *----------------------------------------------------------------------
340: *
341: * getHandledEvents --
342: *
343: * Queries all the events that are currently handled by for this
344: * object.
345: *
346: * Results:
347: * A Tcl list of the events that are currently handled by for this
348: * object. The list is a valid empty Tcl list if this object
349: * handles no event.
350: *
351: * Side effects:
352: * None.
353: *
354: *----------------------------------------------------------------------
355: */
356:
357: TclObject getHandledEvents(ReflectObject reflectObj) // The reflection object to query.
358: {
359: TclObject list = TclList.newInstance();
360:
361: if (reflectObj.bindings != null) {
362: for (Enumeration e = reflectObj.bindings.elements(); e
363: .hasMoreElements();) {
364: EventAdaptor adaptor = (EventAdaptor) e.nextElement();
365: adaptor.getHandledEvents(list);
366: }
367: }
368:
369: return list;
370: }
371:
372: } // end BeanEventMgr
|