/* * BeanEventMgr.java -- * * The Bean Event Manager: This class manages beans event * handlers for a Tcl interpreter. * * Copyright (c) 1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and * redistribution of this file, and for a DISCLAIMER OF ALL * WARRANTIES. * * RCS: @(#) $Id: BeanEventMgr.java,v 1.1.1.1 1998/10/14 21:09:14 cvsadmin Exp $ * */ package tcl.lang; import java.lang.reflect.*; import java.util.*; import java.beans.*; /* * This class manages beans event handlers for a Tcl interpreter: * the event object stack, etc. */ class BeanEventMgr implements AssocData { /* * Stores all of the available event adaptor classes. */ private static Hashtable adaptorClsTab = new Hashtable(); /* * The class loader for loading automatically generated event adaptor * classes. */ private static AdaptorClassLoader adaptorLoader = new AdaptorClassLoader(); /* * When a event handler is invoked, it is given a set of parameters * (stored in an Object array.) The eventParamSetStack variable is * used to store the parameter sets in a LIFO order when nested event * handlers are invoked. Event parameters can be queried by the * "java::event" command. */ Stack eventParamSetStack; /* *---------------------------------------------------------------------- * * BeanEventMgr -- * * Creates a new BeanEventMgr instance. * * Side effects: * Member fields are initialized. * *---------------------------------------------------------------------- */ private BeanEventMgr() { eventParamSetStack = new Stack(); } /* *---------------------------------------------------------------------- * * getBeanEventMgr -- * * Returns the BeanEventMgr instance for the given interp. A new * BeanEventMgr is created if no such BeanEventMgr exists for * the interp. * * Results: * The BeanEventMgr instance for the given interp. * * Side effects: * A new BeanEventMgr may be created and registered as an * AssocData in the given interp. * *---------------------------------------------------------------------- */ static BeanEventMgr getBeanEventMgr( Interp interp) // Query the BeanEventMgr of this interp. { BeanEventMgr mgr = (BeanEventMgr)interp.getAssocData("tclBeanEvent"); if (mgr == null) { mgr = new BeanEventMgr(); interp.setAssocData("tclBeanEvent", mgr); } return mgr; } /* *---------------------------------------------------------------------- * * pushEventParamSet -- * * Pushes a set of event parameters to the top of the stack. * * Results: * None. * * Side effects: * The set of parameters are pushed to the top of the stack. * *---------------------------------------------------------------------- */ void pushEventParamSet( BeanEventParamSet p) // The parameters to push to the top of the // stack. { eventParamSetStack.push(p); } /* *---------------------------------------------------------------------- * * popEventParamSet -- * * Pops the set of event parameters from the top of the stack. * * Results: * None. * * Side effects: * The size of the event parameter set stack is reduced by one. * *---------------------------------------------------------------------- */ void popEventParamSet() throws EmptyStackException // If the stack is already empty. { eventParamSetStack.pop(); } /* *---------------------------------------------------------------------- * * peekEventParamSet -- * * Returns the set of event parameters at the top of the stack. * * Results: * If the event parameter stack is not empty, returns the set of * parameters at the top of the stack. Otherwise, returns null. * * Side effects: * None. * *---------------------------------------------------------------------- */ BeanEventParamSet peekEventParamSet() { if (eventParamSetStack.size() == 0) { return null; } else { return (BeanEventParamSet)eventParamSetStack.peek(); } } /* *---------------------------------------------------------------------- * * disposeAssocData -- * * This method is called when the interpreter is destroyed or * when Interp.deleteAssocData is called on a registered * AssocData instance. * * Results: * None. * * Side effects: * Removes any bgerror's that haven't been reported. * *---------------------------------------------------------------------- */ public void disposeAssocData( Interp interp) // The interpreter in which this AssocData // instance is registered in. { eventParamSetStack = null; } /* *---------------------------------------------------------------------- * * setBinding -- * * Sets the Tcl command to be executed when the given event fires * in the reflectObj. A event adaptor is created when necessary. * * Results: * None. * * Side effects: * If the reflectObj doesn't yet have an EventAdaptor to handle * the event, we will attempt to create it. This may cause an * appropriate event adaptor class to be generated and loaded * into the JVM; the EventAdaptor will be instantiated and * registered as a listener of the given EventSet on the javaObj. * *---------------------------------------------------------------------- */ void setBinding( Interp interp, // Current interpreter. ReflectObject reflectObj, // The reflection object to create // event binding for. EventSetDescriptor eventSet, // The EventSet to bind to. Method event, // Identifies a specific event in // the EventSet to create a // binding for. TclObject command) // The command to execute when the // given event fires. throws TclException // If the adaptor class cannot be // generated, or if the adaptor // cannot be instantiated. { EventAdaptor adaptor = null; if (reflectObj.bindings == null) { reflectObj.bindings = new Hashtable(); } else { adaptor = (EventAdaptor)reflectObj.bindings.get(eventSet); } if (adaptor == null) { Class lsnType = eventSet.getListenerType(); Class adaptorCls = (Class)adaptorClsTab.get(lsnType); if (adaptorCls == null) { /* * We have never processed this type of EventSet yet. Generate * an appropriate event adaptor class and load it * into the JVM. */ adaptorCls = adaptorLoader.loadEventAdaptor(interp, eventSet); adaptorClsTab.put(lsnType, adaptorCls); } try { adaptor = (EventAdaptor)adaptorCls.newInstance(); } catch (InstantiationException e1) { /* * adaptor will remain null. This will trigger the * exception later on. */ } catch (IllegalAccessException e2) { /* * adaptor will remain null. This will trigger the * exception later on. */ } if (adaptor == null) { throw new TclException(interp, "couldn't instantiate adaptor class for eventset \"" + eventSet + "\""); } adaptor.init(interp, reflectObj.javaObj, eventSet); /* * Save the adaptor -- we only need a single adaptor for each * EventSet to handle all possible events in this set. */ reflectObj.bindings.put(eventSet, adaptor); } if (command.toString().length() > 0) { adaptor.setCallback(event.getName(), command); } else { /* * The callback command is the empty string. This means remove * any existing callback scripts. If no more callback scripts * are registered in the adaptor, we'll remove it from the * hashtable. */ if (adaptor.deleteCallback(event.getName()) == 0) { reflectObj.bindings.remove(eventSet); if (reflectObj.bindings.size() == 0) { reflectObj.bindings = null; } } } } /* *---------------------------------------------------------------------- * * getBinding -- * * Queries the command to be executed when the given event fires * in this object. * * Results: * The command to execute when the event fires. null if no such * command has be registered with the setBinding() method. * * Side effects: * None. * *---------------------------------------------------------------------- */ TclObject getBinding( Interp interp, // Current interpreter. ReflectObject reflectObj, // The reflection object to query. EventSetDescriptor eventSet, // The EventSet to bind to. Method event) // Identifies a specific event in // the EventSet to query the // binding for. { EventAdaptor adaptor = null; if (reflectObj.bindings != null) { adaptor = (EventAdaptor)reflectObj.bindings.get(eventSet); } if (adaptor == null) { return null; } else { return adaptor.getCallback(event.getName()); } } /* *---------------------------------------------------------------------- * * getHandledEvents -- * * Queries all the events that are currently handled by for this * object. * * Results: * A Tcl list of the events that are currently handled by for this * object. The list is a valid empty Tcl list if this object * handles no event. * * Side effects: * None. * *---------------------------------------------------------------------- */ TclObject getHandledEvents( ReflectObject reflectObj) // The reflection object to query. { TclObject list = TclList.newInstance(); if (reflectObj.bindings != null) { for (Enumeration e = reflectObj.bindings.elements(); e.hasMoreElements(); ) { EventAdaptor adaptor = (EventAdaptor)e.nextElement(); adaptor.getHandledEvents(list); } } return list; } } // end BeanEventMgr