[Beanshell-dev] Report from JavaOne...

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view

[Beanshell-dev] Report from JavaOne...


It's been an exciting JavaOne for BeanShell.

- Graham Hamilton announced at the keynote that we should have  
BeanShell in Dolphin, the Java 1.7 release.

- Last night we had the BeanShell BOF.  I think it was very  
successful, though we didn't have nearly enough time to cover all of  
the material and get feedback.  We'll have to schedule more for next  

- I'm running into more and more vendors on the convention floor who  
are using BeanShell in their products.

Looking forward to hearing from those of you who attended the  
conference and got feedback on the project.


SF.Net email is sponsored by: Discover Easy Linux Migration Strategies
from IBM. Find simple to follow Roadmaps, straightforward articles,
informative Webcasts and more! Get everything you need to get up to
speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click
Beanshell-developers mailing list
[hidden email]
Reply | Threaded
Open this post in threaded view

[Beanshell-dev] Distributed BeanShell Question

Michael Pitoniak


 i have developed a test automation tool that essentially allows one BeanShell interpreter to call another remote instance and request that it run a script. i presently subclass the interpreter and use Object Serialization to send the request. on the other side i unpack the request, spawn the interpreter, buffer the response, and send it back. works nicely. i recently extended it to allow it to execute BeanShell commands on the other side, rather than scripts (after all commands are really just scripts anyway). i developed a hokey mechanism for doing this:

1) send the command name over along with a hashmap of the named arguments

2) set this variable names equal to the values in the remote interpreter

3) dynamically build the method call signature and execute it


set x = 1;
set y=2;

eval("foo(x, y););

it works, but there must be a more eleant way to accomplish this. can anyone chime in if something more intellegent comes to mind? i am an engineer in pursuit of excellence who is sometimes poorly equipt :)

best regards all,


here is my class. it has some unrelated stuff in it, so please ignore that:

 * Copyright (C) 2002 by Michael Pitoniak ([hidden email]).
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to:
 *   The Free Software Foundation, Inc.,
 *   59 Temple Place - Suite 330
 *   Boston, MA 02111-1307
 *   USA

package harness.parsers.beanShell;

import harness.common.CommonConstants;
import harness.jComponents.jPanels.interfaces.JPanelConstants;
import harness.jComponents.jPanels.interfaces.TestPanelInterface;
import harness.logging.LogManager;
import harness.parsers.beanShell.interfaces.BeanShellParserConstants;
import harness.parsers.interfaces.ParserInterface;
import harness.parsers.interfaces.RemoteParserInterface;
import harness.parsers.interfaces.ScriptManagerInterface;
import harness.utils.classServices.ClassServices;
import harness.utils.exceptionServices.ExceptionServices;
import harness.utils.threadServices.BooleanLock;
import java.awt.Component;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

 *                                 TEST FOR THIS IN:
 *                                 ExecRemoteScriptRequest.execte()
 *                                 ScriptJPanel.runScript()
 * *************************************************/

public class BeanShellCMDParser extends java.lang.Thread implements ParserInterface, ScriptManagerInterface, BeanShellParserConstants, JPanelConstants, CommonConstants{
    protected RemoteParserInterface                 m_RemoteParserInterface = null;
    protected BooleanLock                           m_BooleanLock = null;
    protected String                                m_BeanShellCMD = null;
    protected HashMap                                m_ArgsHashMap = null;
    protected String                                m_PrefsFilePath = null;
    protected long                                                         m_TimeOutMS;
    private BeanShellInterptererThread2          m_BeanShellInterptererThread2 = null;
    private HashMap                                 m_ResponseHashMap = null;
    protected String                                  m_InetAddrName = null;
    private boolean                                 m_ParserStopped = false;
    protected boolean                                                 m_ParserTimeOut = false;
    protected LogManager                         m_LogManager = null;
    //TODO is this constructor needed anymore
    //it looks like we use it just to initialize all common code to all constructors
    //note it is called by other constructors in this class
    //following statement is not true...verify
    /** Default constructor needed by SEFBeanShellScriptParser */
    public BeanShellCMDParser() throws Exception{
        m_ResponseHashMap = new HashMap();
        m_LogManager = LogManager.Instance();
    /** Creates a new instance of BeanShellParser */
    public BeanShellCMDParser(RemoteParserInterface remoteParserInterface, String bshCMD, HashMap args, String prefsFilePath, long timeOutMS) throws Exception{
        m_RemoteParserInterface = remoteParserInterface;
        m_BeanShellCMD                         = bshCMD;
        m_ArgsHashMap                         = args;
        m_PrefsFilePath                 = prefsFilePath;
        m_TimeOutMS                         = timeOutMS;  
    public void run(){
    protected void scriptStateMachine(){
        int state = INITIALIZE;
            while(state != SCRIPT_COMPLETE) {
                switch(state) {

                    case INITIALIZE:
                        state = EVAL_CMD;
                    case EVAL_CMD:
                        state = SCRIPT_COMPLETE;
                        writeError(ClassServices.getCurrentMethodName() + "Illegal State Machine State");
                        state = SCRIPT_COMPLETE;
        }catch(Error error){
            /*If any ThreadDeath Errors slip past we get them here before EventQue
            An instance of ThreadDeath is thrown in the victim thread when the stop
            method with zero arguments in class Thread is called. An application
            should catch instances of this class only if it must clean up after being
            terminated asynchronously. If ThreadDeath is caught by a method, it is
            important that it be rethrown so that the thread actually dies.
            The top-level error handler does not print out a message if ThreadDeath
            is never caught. The class ThreadDeath is specifically a subclass of
            Error rather than Exception, even though it is a "normal occurrence",
            because many applications catch all occurrences of Exception and then
            discard the exception.*/
            writeError(ClassServices.getCurrentMethodName() + error);
        }catch(Exception e){
            writeError(ClassServices.getCurrentMethodName(), e);
            //ScriptManager tracks timeout if we never get here
            if(m_BooleanLock != null){
            //set System.out and System,.err back before
            //exiting because Redicted Streams are persistent
    //If this fails we throw an Exception and stop state machine
    protected void initialize() throws Exception{
        //reset output buffers on each script execution
            m_BooleanLock = new BooleanLock();
            m_InetAddrName = InetAddress.getLocalHost().getHostName();
            if(m_InetAddrName == null){
                m_InetAddrName = "REMOTE";
            //Set name for ThreadViewer Local/Remote Identification
            if(m_RemoteParserInterface instanceof TestPanelInterface){
                this.setName("REMOTE_" + ClassServices.getClassNameNoPackage(this.getClass().getName()));
        }catch(Exception e){
            writeError(ClassServices.getCurrentMethodName(), e);
            throw e;

    /* Note: Additional local namespace variables are initialized by
     * BeanShellInterptererThread.initializeBshInterpreterNameSpace()
     * Any additional variables that need to be loaded by a script
     * can be achieved by just sourcing a file with varables
     * defined in it. That file should follow java syntax.
     * If this fails it throws an Exception and stops State Machine
    public void loadScriptArgs(Object args) throws Exception{
     * NOTE: There are multiple instances of bsh classes in the jar file mounts. Test Harness
     * BeanShell support will not work unless the latest beanshell jar is found first.
     * The order in which directories and archives appear in the Filesystems tabbed pane
     * can affect the running and debugging of sources in the IDE. For example, if you have
     * Java files with identical class and package names in different mounted filesystems,
     * the file in the first mounted filesystem is always loaded during execution and debugging.
     * This happens even if you have select the second class before calling the command.
     * To change the order of mounted filesystems:
     * In the Explorer, right-click the root Filesystems ( ) node and choose Customize.
     * Right-click the Filesystems Settings node. Choose Change Order from the contextual menu.
     * In the Change Order dialog box, select the filesystem you want to move.
     * Click the Move Up button or the Move Down button to change the position
     * of the filesystem relative to the other filesystems.
    //TODO this must be public because intrinsics call it....fix that
    public void evalCMD(String bshCmd){
                     //build the bsh cmd to evaluate
            boolean bFirst = true;
            StringBuffer bshCmdBuffer = new StringBuffer();
            bshCmdBuffer.append(bshCmd + "(");

            if(m_ArgsHashMap != null){
                Set mappings = m_ArgsHashMap.entrySet();
                for (Iterator i = mappings.iterator(); i.hasNext();) {
                    Map.Entry me = (Map.Entry)i.next();
                    Object key = me.getKey();
                        bshCmdBuffer.append(", ");
                    bFirst = false;
            writeInfo(ClassServices.getCurrentMethodName() + "Evaluating: " + bshCmdBuffer.toString());
            //TODO design change, BeanShellInterpreter should really take ParserInterface
            m_BeanShellInterptererThread2 = new BeanShellInterptererThread2(this, m_BooleanLock, bshCmdBuffer.toString(), m_ArgsHashMap, m_PrefsFilePath);

            //the BeanShellInterpreter will source the script relative the
            //the "BeanShell" CWD which was set in this.initialize()
            //note: this call is synchronous, and returns when script is complete
                m_ParserTimeOut = true;
                m_RemoteParserInterface.writeError(ClassServices.getCurrentMethodName() + m_InetAddrName + "->" + "Script TimeOut.......Exceeded: " + m_TimeOutMS + "Ms");
                m_RemoteParserInterface.writeInfo(ClassServices.getCurrentMethodName() + "BooleanLock Released......Script Complete");
            writeInfo(ClassServices.getCurrentMethodName() + "Done Evaluating: " + bshCmd);
        }catch(Exception e){
            writeError(ClassServices.getCurrentMethodName(), e);
        }catch(Error error){
            writeError(ClassServices.getCurrentMethodName() + ExceptionServices.getStackTrace(error));
            throw error;
            if(m_RemoteParserInterface instanceof TestPanelInterface){
                //insure ElapsedTimerThread in BeanShellScriptParser dies
                m_RemoteParserInterface = null;
    public Object getEvalReturnObj(){
        return m_BeanShellInterptererThread2.getEvalReturnObj();
    //callesd by ScriptJPanel.stopScript() to perform a user abort.
    public void stopParser(){
            //TODO find appropriate way to stop interpreter
            //interrupt didn't work here, and stop is depricated
            /* Thread.stop()
             * The thread represented by this thread is forced to stop whatever
             * it is doing abnormally and to throw a newly created ThreadDeath
             * object as an exception.
             * It is permitted to stop a thread that has not yet been started.
             * If the thread is eventually started, it immediately terminates.
                writeInfo(ClassServices.getCurrentMethodName() + "STOPPING INTERPRETER");
        }catch(Exception e){
        }catch(Error err){

     * By setting Interpreter's parser and interpreter variables to null
     * when the Parser completes, or times out, we insure that any script
     * spawned threads that try to access the parser's methods after the
     * script completes, or is stopped; will throw an exception and exit.
     * This prevents unwanted Script spawned Threads executing after the
     * RemoteClient session exits.
     * Called at end of  ScriptManager.scriptStateMachine()
     * */
    public void disableParser(){
            m_BeanShellInterptererThread2.setInterpreterVar("parser", null);
            m_BeanShellInterptererThread2.setInterpreterVar("interpreter", null);
        }catch(Exception e){
    /* This method is Overridden in derived subclasses to perform any parser
     * specific cleanup required by that class. This is very usefull as "any"
     * syntax error in a script will cause the beanshell interpreter to exit
     * without executing any catch or finally in the script. This method ends
     * up being the only way to implement finally() for the interpreter.
    protected void cleanUp(){
        //override for specific cleanup needs
    /* This method is used to initialize  BeanShellInterpreter local varaibles "
     * before" scriptexecution.
    public void setVariableValue(String var, Object val){
            m_BeanShellInterptererThread2.setInterpreterVar(var, val);
        }catch(Exception e){
            writeError(ClassServices.getCurrentMethodName(), e);

    //TODO can we consolidate setVariableValue and this??
    public void addResponseVar(String var, Object value){
        m_ResponseHashMap.put(var, value);
    //TODO deprecate?
    public void addResponseHashMap(HashMap hashMap){
        m_ResponseHashMap = hashMap;
    /*Scripts pass varaibles back to RemoteClient Matser via addResponseVar()
     * ExecRemoteScriptRequest constructs an ExecRemoteScriptResponse, and calls
     * getResponseHashMap() to get the HashMap to pass back
    public HashMap getResponseHashMap(){
        return m_ResponseHashMap;
    //getParserStopped() is used by scripts to determine in parser has been halted
    public boolean getParserStopped() {