The Bean Extender Scripting Framework allows Java developers to script Java beans. Scripted beans can be aggregated in a scripting environment such as a form or an assembly surface. The Scripting Framework provides a set of classes and interfaces. These classes and interfaces are needed to script a bean and to hook up a custom Integrated Development Environment (IDE) for script development.
The various classes and interfaces for scripting help the developer make a bean scriptable. The following sections explain how to use the scripting IDE as an end user to write a script and run or debug it; how to write a scripting client to integrate with Bean Extender scripting framework; how to implement and register a new scripting component(add a new scripting language) by using Bean Extender scripting framework. The detail sections are:
The Scripting IDE (Integrated Development Environment) works with any scripting language that is connected to the scripting environment. The information in the following sections assumes that the objects were previously registered with the scripting environment. For information on registering objects, see "Working with Registered Objects".
The topics discussed in the section are:
The graphics used in this section are from a Microsoft Windows NT 4.0 system. To close these windows, follow the standard Windows closing process.
You can start the scripting interface in one of the following ways:
When you start the scripting interface, the following window is displayed.
For scripting purposes, you need to be familiar with the following buttons on the interface:
![]() | The Browse button displays a tree of registered objects. |
![]() | The Run button runs a script. When you click on this button, your script starts running. Before a script can run, the scripting language must be able to compile your script. |
![]() | The Debug button debugs a script. When you click on this button, the debugging process starts. Before starting the debugger, the scripting language must be able to compile your script and the specific script must be debug-enabled. |
![]() | The Terminate button stops the running of a script. When you click on this button, your script stops running. |
The Compile with Debug Info check box indicates whether the script will be compiled with debugging ability enabled. When you click on the Debug Script button, this box is already checked.
To browse a registered object, click on the
Browse button. A sample screen is shown below.
Each item in the tree represents a separate object registered for scripting. This window contains the Script0, the OurButton0, and Juggler1 objects. These objects were registered for scripting by an application using the scripting environment.
You can view the object class information by clicking on the plus sign next to a particular registered object. The class information displayed in the tree is scripting-language specific. You can collapse, or close, the object class information by clicking on the minus sign next the to the object.
You can modify an existing script associated with a registered object, or you can modify a script that you import. To modify a script associated with a registered object, click on the name of the object in the tree. For example, to modify a script associated with the Juggler1 registered object, click on Juggler1. All scripts associated with the selected registered object are made available to the interface. The following view is displayed after you select a registered object.
![]() | The Import button displays a file dialog to import a script associated with a registered object into the selected text area. For additional information on this button, see "Modifying Scripts". |
To modify a particular script associated with the Juggler1 object, do the following:
The following image depicts the contents of the drop-down list of the scripts associated with the Juggler1 object.
You can import code by doing the following:
Saving a script is dependent on the application using the scripting language. You cannot save the script from the scripting interface. Therefore, you must save it from the application. You can save the script, depending on the scripting application provided, in one of the following ways:
The scripting debugger can be launched from the assembly surface, the FormBuilder application, the FormRunner application, or the scripting IDE. You can debug a script written in either Java or NetRexx. However, you must compile and run your script with the debug flag set. Refer to "FormBuilder and FormRunner" for information on how to compile and run scripts with debugging enabled.
When a debug-enabled script is running with the debug flag set, an instance of the standard Bean Extender debugger is displayed with an additional Script Source button that allows you to view your Java or NetRexx script source.
![]() | The Script Source button displays the script source in a panel on the Debugger. |
For more information on how to use the standard Debugger buttons see "The Debugger".
The script source panel consists of a drop--down list containing a choice of event handles and an associated text area that displays the script code for the currently selected event handle. You can set or unset the breakpoint on a line of the script source by double-clicking on the source line, and you can switch to another event handle in the drop-down list. The following image is an example of a Java debug script panel.
The NetRexx script source code is translated into Java code; however, the
line numbers remain the same in both versions. Therefore, the NetRexx debug
script is similar to the Java debug script. The following is an example of a
NetRexx debugging window.
Installing Bean Extender development kit is required to run scripting debugger.
This section describes how to add scripting capabilities to Java objects within a programming application using the scripting APIs. Each code example in this section can build on all previous coding segments. The FormBuilder is a sample application containing scripting capabilities. Generally, scripting applications have a menu item that starts and saves a scripting session.
The following code segments are executed when the user selects a menu item from a scripting application. From the FormBuilder application, select the Edit Script menu item from the Edit menu.
For additional information on the FormBuilder, see "FormBuilder and FormRunner". For additional information on the APIs mentioned in this section, see the Bean Extender API Reference.
The following code segment demonstrates how an application program lets you select the scripting component descriptor to be used to create the scripting environment. This code creates a pop-up menu where you can select a scripting language.
import com.ibm.beans.script.SCREnvironmentFactory; import com.ibm.beans.script.SCRComponentDescriptor; ... public class MyApp extends Applet implements SCRClient, ActionListener, Serializable { private transient PopupMenu scriptPop; private transient SCRComponentDescriptor[] descList; private transient SCREnvironmentFactory factory; public void initialize() { /* Get the list of registered scripting components. The return * queryRegisteredComponents() is an array of SCRComponentDescriptors. * * The component descriptor will provide textual information describing * the scripting language and its capabilities. */ factory = new SCREnvironmentFactory(); descList[] = factory.queryRegisteredComponents(); /* The application then builds a pop-up menu with the readable * text from the component descriptor so the user can select * the scripting component that best suites the user's needs. */ if (descList != null) { if (descList.length > 1) { scriptPop = new PopupMenu ("Scripting Components"); for (int i = 0; i < descList.length; i++) { String s = descList[0].getLanguage() + " "+ descList[0].getVersion(); MenuItem mi = new MenuItem(s); scriptPop.add(mi) mi.addActionListener(this); } } } } }
The following code segment demonstrates the continued creation of the scripting environment. The previous code displays a pop-up menu that allows you to select a scripting language. When you select a language, the following code is executed to create a scripting environment.
/* An item from the scriptPop was selected. We use * the index of the popup item to select the SCRComponentDescriptor * in descList to create the SCREnvironment. */ import com.ibm.beans.script.SCREnvironment; private SCREnvironment scrEnv; public void actionPerformed(ActionEvent event) { String cmd = event.getActionCommand(); if (cmd == null) return; Object source = event.getSource(); /* * Was the source from the scriptPop menu? */ if (source instanceof MenuItem) { if ((MenuItem) source).getParent() == scriptPop) { int s = descPopup.getItemCount(); /* * The following code iterates through the descPop * to determine which item was selected. */ for (int i = 0; i < s; i++) { if (event.getSource() == descPopup.getItem(i)) { if (descList != null && descList.length > i && descList[i] != null) { /* * The next line of code creates a SCREnvironment * using the users selected SCRComponentDescriptor. * The variable "i" is the index to the selected * SCRComponentDescriptor. */ try { scrEnv = factory.create(this, descList[i]); factory = null; descList = null; remove(scriptPop); scriptPop = null; } catch(SCRComponentNotFoundException e) { scrEnv = null; MyExceptionHandler(e); } break; } } } } } }
In the following code segment, the application calls the addScriptableObject() method. When this method is called, it adds the specified scriptable object (any Java bean) to the scripting environment. Adding this object allows the previously selected scripting language to use the introspected interfaces of the object.
public class MyApp... /* * Method call to add the specified component. */ public void addScriptObject(Object o) { add(o) scrEnv.registerObject(o.getName(), o); }
In the following code segment, the application calls the renameScriptableObject() method. This method calls the rename method on SCREnvironment. The renameObject() method returns a boolean value.
public class MyApp... /* * Method call to rename the Component. */ public void renameScriptableObject(Object o, string newName) { if (scrEnv.renameObject(o.getName(), newName) { o.setName(newName); } }
In the following code segment, the application calls the removeScriptableObject() method. This method causes the object and associated event script code to be removed. After removing the object, the object is deregistered from the scripting environment.
public class MyApp... /* * Method call to remove and deregister the Object. */ public void removeScriptableObject(Object o) { remove(o); scrEnv.deregisterObject(o); }
In the following code segment, the application calls the editScript() method to invoke the Scripting Integrated Development Environment (IDE) associated with the particular scripting language.
/* Start editing the script by binding up * the IDE for the scripting language. */ scrEnv.editScript();
In the following code segment, the application calls the getRTEnvironment() method to get the run-time enironment and calls the runScript() method of the SCRRTEnvironment to start the script.
public void executeScript(boolean) { SCRRTEnvironment rtEnv; // compileDebug is true, the rtEnv will be debugging enabled. // compileDebug is true, the rtEnv will be debugging disabled. // The debugging ability support is based on implementation of each // scripting component. Some scripting component may not support // debugging ability at all. In this case, the value of compileDebug // flag will not make any difference. Bean Extender provides Java // and NetScript component. Both of them support debugging./ rtEnv = scrEnv.getRTEnvironmenrt(compileDebug); if(rtEnv != null) { // runDebug is true, starts the debugger to debug the script. If the // script is not debugging enabled, it will run the script and print // out a message to the console. // runDebug is false, start to run the script without debugging. if (!rtEnv.runScript(runDebug, this)) { System.out.println("Script failed to run."); } else { if(!runDebug) System.out.println("Script initialized successfully."); // Because different scripting components may implement the // debugging support in different ways, some scripting components // may not be able to start the script until it successfully launches // the debugger in a separate process. } }
Edit time persistence is when the SCREnvironment and all the scripts being edited are saved to a storage medium. The SCREnvironment can be serialized and deserialized with all the information needed to edit and run scripts. The SCREnvironment is serializable, so there is no need for special processing. However, to deserialize, the initialization method must be called after the object is read but before any other methods are called on the SCREnvironment.
The following code segment illustrates edit time persistence.
public class MyApp ... implements SCRClient { private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); scrEnv.initialize(this); } }
An application using the SCREnvironment could separate run-time information from edit time information. The runtime-only information can be extracted from the SCREnvironment by calling the getRTEnvironment() method. To keep the information saved for the runtime minimal, the SCRRTEnvironment class defines only a few methods.
In the following code segment, the application calls the getRTEnvironment() method to save a runtime-only version of the scripting environment.
public class MyApp... { /* * Method call to save a run-time only version of the scripting environment. */ public void deployApplication(ObjectOutputStream out) { out.writeObject(scrEnv.getRTEnvironment()); } }
The SCRClient interface is implemented by the application using the scripting environment. Both the runRequest() method and the terminateRequest() method must be implemented by the scripting environment. These methods can be called internally by the SCRClient. These internal method calls are generally a request from the language-specific IDE. However, the SCRClient determines if the script can be run and, if so, performs the necessary preparation tasks for script execution.
The following code segment prepares the application for running.
public class MyApp ... implements SCRClient { /* * Application-specific method call to prepare for running. */ public boolean runRequest(SCREnvironment scrEnv) { saveToFile(); SCRRTEnvironment rtEnv = scrEnv.getRTEnvironment(compileDebug); return rtEnv.runScript(runDebug, this); } } public boolean terminateRequest(SCREnvironment scrEnv) { // Get the saved rtEnv associated with scrEnv. Do not call // scrEnv.getRTEnvironment to get it because it will create // another one. rtEnv.terminateScript(); }
This section describes how to write a scripting component that can connect with the Bean Extender scripting environment. The scripting component must implement all the scripting language-related methods for editing and run time. During editing, the scripting component can handle object registration, class registration, script editing, and compilation. During run time, the scripting component manages deployment of the Java object events to the script and invokes the Java object methods from the script.
The SCRComponent class is the base class of all scripting component classes. The scripting component communicates with the event processor and the scripting environment. The scripting component manages the registration of the Java object and the Java class. All scripting language-related work is managed by its subclasses.
The Scripting Component Manager manages component registry which keeps track of various scripting components installed on a system. The Scripting Component Registry is saved as BeanSystem properties. The scripting component manager can get, remove or update the registered component descriptors from BeanSystem properties. During the Bean Extender installation, the installation program(initBS) creates the default BeanSystem properties for the scripting component registry. These include all the BeanExtender supported scripting components.
Bean Extender configuration tool can be used to add, remove or update a scripting component registration entry. The user who installs the new scripting component is responsible to use this tool or directly use the SCRComponentManager to add a new scripting component. The command to run this tool is:
java com.ibm.beans.util.ConfigureAfter typing in above command the default window will show up. Clicking on the scripting tab will bring you to the following scripting window.
In this window you can define the scripting language and its version. You also can define the class name of the scripting component and scripting component properties. Clicking on the Default will reset scripting component registry to the default values.
The scripting environment calls the scripting component to do the following:
The scripting component can call the scripting environment to get all registered object handles, if the component does not maintain a registered object table. The scripting component can ask the scripting environment for an object handle by giving the name of the Java object.
Each Java object involved with scripting must be registered with the scripting component. Before registering a Java object, the scripting environment calls the SCRComponent.createObjectHandle() method to create an object handle. The scripting environment registers the object handle instead of the original Java object.
When the scripting component receives an object from the scripting environment, the scripting component calls the SCREventProcessor.register(), SCREventProcessor.deregister(), or SCREventProcessor.rename() method of the event processor and calls the SCRComponent.registerObject(), SCRComponent.deregisterObject(), or SCRComponent.renameObject() method against itself respectively. However, these methods can be overridden by a subclass of SCRObjectHandle.
The SCRObjectHandle class is the base class for all object handle classes. This class contains the Java object and its name. You can subclass it to store extra Java object-related data.
The scripting component manages class registration. If a scripting component needs to maintain an internal class registration, it should override the SCRComponent.registerClass() method. Class introspection is done during class registration. The SCRComponent subclass should implement the doIntrospection() method. The scripting component provides a class registration mechanism; however, it does not define which class will be registered. The actual registration is done by each scripting component. At a minimum, all registered objects must have a corresponding class registered.
The SCRRegisteredClass class is the base class for all registered classes. The SCRRegisteredClass class contains only the class of the Java object. You can subclass it to store extra class-related information.
The SCREventProcessor class is an object that listens to all events fired by the registered Java objects and delivers these events to the run-time scripting component. The run-time scripting component is responsible for invoking the associated event handler script.
The run-time scripting component needs to implement the handleEventFired() method that is called by the event processor for event delivery. Additionally, the event processor can call the needAddListener() method to determine whether a particular event has any defined scripts.
The event processor-related work for editing is done by the SCRComponent for subclasses. The scripting event processor requires that the scripting component register each Java object. The scripting component registers objects using the SCREventProcessor.registerObject() method and deregisters objects using the SCREventProcessor.deregisterObject() method.
The following control flows illustrate the relationship among the SCREnvironment, SCRComponent, and SCREventProcessor classes for editing and run time.
For editing:
SCREnvironment-->SCRComponent.initialize()-->SCREventProcessor.SCREventProcessor() SCREnvironment-->SCRComponent.createObjectHandle() SCREnvironment-->SCRComponent.objectRegistered()-->SCREventProcessor.objectRegistered() SCREnvironment-->SCRComponent.objectDeregistered()-->SCREventProcessor.objectDeregistered() SCREnvironment-->SCRComponent.editScript() SCREnvironment-->SCRComponent.getORCreateRTComponent() SCRComponent-->SCREnvironment.getObjectHandles()
For run time:
SCRRTEnvironment-->SCRRTComponent.initialize()-->SCREventProcessor.objectRegistered() SCRRTEnvironment-->SCRRTComponent.runScript()-->SCREventProcessor.runScript() SCRRTEnvironment-->SCRRTComponent.terminateScript()-->SCREventProcessor.terminateScript() SCREventProcessor-->SCRRTComponent.needAddListener()
The scripting component must be able to save the run time only information. The SCRRTComponent class is the base class for all run-time scripting components. It contains the run-time event processor and a run-time name manager. The scripting environment gets the run-time scripting component by calling the SCRComponent.getORCreateRTComponent() method.
The scripting environment calls the SCRRTComponent.runScript() method to start scripts. The subclass needs to implement the handleRunScript() method to start the script. The scripting run-time component starts the event processor after calling the handleRunScript() method.
The run script request can come from the scripting client. The run script request can also come from the integrated development environment (IDE) connected with scripting. Currently, the scripting component must pass the request to the scripting client by calling its runRequest() method. The scripting component can get the scripting client reference from the scripting environment during initialization.
The scripting environment calls the SCRRTComponent.terminateScript() method to stop scripts. The subclass needs to implement the handleTerminateScript() method to stop the script. The scripting run-time component stops the event processor after calling the handleTerminateScript() method.
The stop script request can come from the scripting client. The stop request can also come from the IDE connected with scripting. Currently, the scripting component must pass the request to the scripting client by calling its terminateRequest() method. The scripting component can get the scripting client reference from scripting environment during initialization.
The event processor delivers events fired by Java objects to the scripting run-time component. The event processor provides the event object and the event method name. The SCRRTComponent subclass is responsible for implementing the handleEventFired() method that delivers the event to the script. The event processor does not listen to all events fired by the registered Java object. The event processor checks with the scripting run-time component for each event listener to determine whether there is an associated script.
This check method is the needAddListener() method. The event processor passes in a Java object and an event listener type name. The needAddListener() method returns true if it can find the script for the event-object pair.
If the run time cannot perform this check, the run-time scripting component does not override the needAddListener() method. The default return for the needAddListener() method is true.
The SCRRTComponent class provides a name table to look up the Java objects for the scripting component. From this table, the scripting component can get the Java object on which to invoke a method. The SCRRTComponent class does not provide any support for invoking registered Java object methods from the script.
The developer is responsible for providing ways for writing and debugging scripts. The SCRComponent class defines only the abstract editScript() method. Developers should implement this method.
The scripting component is responsible for saving all data used to edit and run the script. When a client application saves the scripting environment, the scripting environment saves the scripting component. A scripting component developer needs to ensure that all scripting-specific data is saved when the scripting component is serialized.
During initialization, the scripting component reconnects all of the registered objects with the scripting IDE and the event processor. The SCRComponent.initialize() method calls the scripting environment to get all the registered object handles, register each of the object classes of the object handle, and register each object with the event processor.
To develop a scripting component that connects with the scripting IDE (SCRIDE), the scripting component needs to be derived from the SCRIDEComponent class. The SCRIDEComponent class manages most of the communications between the SCRIDE and the scripting component.
The IDE instance is the only data transferred between the SCRIDE and the scripting component. The scripting component provides the SCRIDE with a group of SCRIDEInstance objects. Each IDE instance contains two parts: the class information tree and the editable object.
For scripting, an IDE instance is associated with one registered Java object. The class information tree stores the class information, such as methods, properties, event sets, and the methods in each event set. Each editable object stores a portion of a script associated with one event that is fired by the associated Java object.
A SCRIDE object handle is defined to associate the IDE instance with a Java object. The SCRIDEObjectHandle class is derived from the SCRObjectHandle class. The SCRIDE object handle contains an IDE instance as a property. For best results, use the SCRIDE object handle; however, it is not required. Because the SCRIDE does not have access to the SCRIDE object handle, the SCRIDE must get the Java object name from the IDE instance. The SCRIDEInstance class defines the abstract getName() method to get the Java object name. Subclasses of SCRIDEInstance should implement this method.
Inside a script, besides each event handler, there are user-defined extra functions, global declarations, or system-defined methods. The scripting component could create special IDE instances that do not have a class information tree. Each IDE instance could have a group of editable objects that define these special methods.
A generic information tree is held in one SCRIDEClassInfo object. On each tree node is a title and a group of child nodes of type SCRIDEClassInfo. The developer can store anything in the tree.
Normally, the tree stores the class-related information generated by the class introspection. During introspection, the scripting component generates the scripting language-dependent title and decides which part of the class information is added in the tree.
The SCRIDE editable object contains the script text and a changed flag. The initial value of the changed flag is true. Each time the script is changed, the SCRIDE sets the changed flag to true. The scripting component is responsible for setting the changed flag to false after compiling the script.
The SCRIDE needs a title to identify a script. Therefore, the SCRIDEEditableObject class defines the abstract getTitle() method. Normally, the title is the script method name associated with a Java object concatenated with an event method name. Because the Java object can be renamed at any time, the title might need to be regenerated after a renameObject() method call. The getTitle() method implementation is the responsiblity of the subclass.
The class introspection is done when the class is registered. The data generated during introspection is stored with the registered class. If the class is correctly stored, the class can be reused. The SCRIDERegisteredClass class provides a way of associating the class information tree with the registered class by making the class information tree a property. It is not necessary to use the SCRIDERegisteredClass.
Each time an object registration is changed, the SCRIDE component notifies the SCRIDE. The subclass must call the superclasses associated with a register, deregister or rename method.
Before running the script, the scripting component needs to synchronize the IDE to ensure that the current script editing buffer is copied to the editable object. The SCRIDE syncEditor() method is used for synchronization.
The SCRIDE generates the request to run or terminate a script. The SCRIDE communicates with the scripting component. The SCRIDEComponent class defines two methods for passing the request to the scripting client. The request for running the script is the runRequest() method. The request for terminating the script is the terminateRequest() method.
The scripting event processor needs to generate event listener files for run-time usage; however, a component can generate extra run-time files. These event listener files and run-time files must be shipped with the other run-time files generated by the scripting client. The scripting client must get these files from the scripting environment. Use the SCREnvironment.getPackagingFiles() method for this purpose.
Because event listener class files are generated by the scripting event processor, they need to be packaged by the scripting client. Therefore, the scripting client needs to provide a package name to the scripting environment. The scripting environment can call the SCRClient.getPackageName() method to get the package name.
The scripting event processor also needs to obtain the location where the event listener class files are generated. The scripting environment can call the SCRClient.getWorkingDirectory() method to get the temporary directory. If this method returns null, the event listener class files are generated in the current directory.