Scripting Within The BioCoRE Control Panel

The BioCoRE Control Panel is capable of running scripts written in a variety of scripting languages (currently Python and TCL). These scripts can do a variety of things, including manipulation of chats, communication with the BioCoRE server, and many other things. This is accomplished by embedding interpreters for these languages inside the Java Control Panel. All scripts execute on the same computer that the Control Panel is running on.

  • Python embedding is done via the Jython package. Jython (and more information on it) is available at http://www.jython.org. The version currently included in the Control Panel is 2.1. The license for this download is available.
  • TCL embedding is done via the JACL package. JACL (and more information on it) is available at http://sourceforge.net/projects/tcljava/. The version currently included in the Control Panel is 1.3.1. The licenses for this download ( 1, 2) are available.

    Getting Started

    The best way get started with scripting within the Control Panel is to look at some examples. If you aren't already in the BioCoRE Help project on the main BioCoRE server, join the project (You can access the list of Public Projects via the Project menu in the Control Panel or via the left sidebar of the web pages).

    Several scripts have been stored within the BioFS for this project. Using either WebDAV or the web pages, navigate to the the folder for this project and look at the files there. (You can also go to a summary page for the scripts.

    The hi.py script is a very simple Python script. The contents of the script:

    
    print "hi"
    
    
    It prints the word "hi". Anytime you do a print, the results go to the java console.

    You can execute this script in the Control Panel by going to 'Scripting | Execute Script From BioFS' and navigating to hi.py and choosing it. Or, since this script is so tiny, you could just go to 'Scripting | Manual Script Input' and type it in. In the Manual Input window, verify that the language is the correct type (JPython or Python both refer to the same thing, so that is what you would want to choose in this case) and then type in the script in the window. Once you choose to execute the script, the word "hi" should be printed to the java console.

    If you are going to working with scripting, we advise you to change your debug level in the Control Panel to at least LOW. You can set this by going to 'Help | Debug Level'. A level of LOW (or anything higher) will save a copy in the java console of any script that you have manually typed. This can save a lot of retyping.

    If there are any errors in a script that you have entered, a window will pop up telling you what the error is. The errors can be pretty obtuse. For instance, a script of:

    printt "hi"
    
    Gives the following error message:
    InterpreterException: underlying exception: Traceback (innermost last):
      (no code object) at line 0
    SyntaxError: ('invalid syntax', ('', 1, 8, 'printt "hi"'))
    
    The last line of the error is the useful one. It gives the script line number where the error occurred ('1' in this case) and the character where it noticed the problem (8), which means that the error probably occurred right before that. In this case, of course, print isn't spelled with two 't's.

    More Complex Scripts

    Obvious, a simply "hello world" type script isn't very interesting. For a more interesting script, let's dissect the chatlisten.py script in the same directory in the BioFS. This script watches incoming chat messages, and if someone says :) the script will automatically insert a response of: /me smiles back at you.. So, the following exchange could occur if your user name is johndoe.

    Tue 16:11:bobdoe>I thought it went well.
    Tue 16:12:johndoe>So did I.
    Tue 16:13:bobdoe>Would have been hard for it to go much better.  :)
    Tue 16:13:johndoe smiles back at you.
    

    To summarize what the script does: It sets up a listener that "listens" for any incoming chat message. When an incoming chat message is "heard", it processes the message. To process the message, it checks to see if the message contains a smiley face, and if it does, it automatically inserts a new message back into that project's chat window.

    Let's go through this script line by line. Virtually all scripts that you write are going to have some common directives.

    # we have to add 'main' explicitly, since it isn't in the default
    # java package
    import sys
    sys.add_package('main')
    
    # add the control panel class so we can get a handle on it
    from main import ControlPanel
    
    cp = ControlPanel.getInstance()
    
    If your script needs to interact with the Control Panel (and all of them probably will) you need to tell Python how to talk to the Control Panel. The above text will give you a variable named 'cp' that can be used to do this.

    from event import BChatMsgRecvListener
    
    In this script, you need to listen to all chat messages that are received from the server and possibly act upon them. For this, you need to use the BChatMsgRecvListener. Other listeners that you might be interested in include: BMsgSendListener, which can be used to work on messages that you type yourself (see quote.py or emote.py), BNotebookMsgRecvListener and BLinkLibMsgRecvListener, which are called when a message is sent from the server saying that a new notebook message or link library message has been received.

    The next few lines will be pretty common to scripts that you write:

    # set up a listener class.  
    class chatRecvSmileyPrintResponse(BChatMsgRecvListener):
       def process (self, event):
    
    The name of the class, chatRecvSmileyPrintResponse, will need to change for each one, and the type of the class, BChatMsgRecvListener, might change, depending on what you are listening for.
           cm = event.getChatMessage()
    
           # we only want to do something if the message isn't old
           # you will typically want this check on ALL Recv listeners
           # that you set up.  Otherwise, it will perform the operation on
           # all of the older messages that you see when you first
           # log in, which you probably don't want.
           if cm.isOld():
              return event
    
    We can get the actual text of the message, and other useful information and store it in a new variable that we call 'cm'. Next, we want to check and see if this is an "old" message. If so, we don't want to print another response (without this we could end up with double responses).
           # check to see if the message sent contains a smiley face
           # -1 is returned if it isn't there.  Otherwise, the character
           # position of the smiley face is returned.
           if (cm.getMessage()).find(':)') != -1:
    
              # am i the one that sent the message?  If so, I don't
              # want to respond to myself.
              if cm.getSender() != cp.getUserID():
    
    
    Now we need to see if we actually want to do anything with the message. So, we check to see if it contains :) and we also check to see if we sent it ourselves. If we pass all of these tests we are ready to respond to the smiley face.
                 # get the project chat window that this message was
                 # sent to
                 pp = event.getSource()
    
                 # send a message to this project.  This will send a basic
                 # emote that will then get processed.
                 pp.processTextMessage("/me smiles back at you.")
    
    We first need to figure out which chat window this message is sent for. 'getSource()' gives us this.

    Next, we need to send a message to the server. Note that messages sent via 'processTextMessage' are NOT processed by any listeners. The messages are only processed by the default Control Panel actions.

           # it is vitally important that the event is returned from the process
           # function
           return event
    
    # make a listener object.  This lets us do a cp.removeBListener(varName)
    # later if we choose to do so that will turn off this listener.  This
    # is a crucial step.
    chatPrint = chatRecvSmileyPrintResponse()
    
    # actually add the listener 
    cp.addBListener(chatPrint)
    
    The 'event' object MUST but returned from the process function. Next, we make an object of the new class that we've created, and actually add the listener.

    General Information About Listeners

  • Listeners are acted upon in "random" order. Technically, the way it is currently written, the last listener is checked first, then the next to last, etc. Don't count upon any particular ordering, though.
  • Listeners are done BEFORE the default Control Panel action for a given piece of data. For instance, when you send a chat message, all BMsgSendListeners are checked before the Control Panel actually sends the message.
  • A listener can choose to not let any other listeners act upon an event, or to not even let the default Control Panel action take place. You can cause this to be the last listener that actually gets the event by doing the following. (Zero means false) The default action for the event will still be processed, though.
    event.setContinueProcessingListeners(0)
    
    You can also prevent the default Control Panel action from occuring for this event.
    event.setDoDefaultAction(0)
    

    If you have any questions about Scripting within the Control Panel, let us know (the BioCoRE Help project is a great way to do that).