[kepler-dev] [kepler-code] r16356 - in trunk: . configs configs/ptolemy configs/ptolemy/configs configs/ptolemy/configs/kepler lib lib/jar module-info resources resources/system.properties src src/org src/org/kepler src/org/kepler/distributed

Chad Berkley berkley at nceas.ucsb.edu
Thu Jan 15 11:12:16 PST 2009


Hi Jianwu,

It looks like you checked these files into the trunk.  Could you move 
them to an appropriate module directory?

thanks,
chad

jianwu at ecoinformatics.org wrote:
> Author: jianwu
> Date: 2009-01-15 11:06:11 -0800 (Thu, 15 Jan 2009)
> New Revision: 16356
> 
> Added:
>    trunk/.classpath
>    trunk/.project
>    trunk/build.xml
>    trunk/configs/
>    trunk/configs/ptolemy/
>    trunk/configs/ptolemy/configs/
>    trunk/configs/ptolemy/configs/kepler/
>    trunk/configs/ptolemy/configs/kepler/uiMenuMappings_en_US.properties
>    trunk/lib/
>    trunk/lib/exe/
>    trunk/lib/jar/
>    trunk/lib/jar/jargon_v2.0.jar
>    trunk/module-info/
>    trunk/module-info/modules.txt
>    trunk/origmodel.xml
>    trunk/resources/
>    trunk/resources/system.properties/
>    trunk/resources/system.properties/DistributedKepler.config
>    trunk/resources/system.properties/DistributedKeplerSlaveACL.config
>    trunk/resources/system.properties/DistributedKeplerUser.config
>    trunk/resources/system.properties/build.properties
>    trunk/rmi-registry.bat
>    trunk/rmi-registry.sh
>    trunk/src/
>    trunk/src/org/
>    trunk/src/org/kepler/
>    trunk/src/org/kepler/distributed/
>    trunk/src/org/kepler/distributed/Credential.java
>    trunk/src/org/kepler/distributed/CredentialException.java
>    trunk/src/org/kepler/distributed/DCAEditorPane.java
>    trunk/src/org/kepler/distributed/DataToken.java
>    trunk/src/org/kepler/distributed/DistributedCompositeActor.java
>    trunk/src/org/kepler/distributed/DistributedConfigAction.java
>    trunk/src/org/kepler/distributed/DistributedConfigDialog.java
>    trunk/src/org/kepler/distributed/DistributedFileServer.java
>    trunk/src/org/kepler/distributed/DistributedIOPort.java
>    trunk/src/org/kepler/distributed/DistributedInputActor.java
>    trunk/src/org/kepler/distributed/DistributedLogger.java
>    trunk/src/org/kepler/distributed/DistributedPortParameter.java
>    trunk/src/org/kepler/distributed/DistributedSDFDirector.java
>    trunk/src/org/kepler/distributed/DistributedServer.java
>    trunk/src/org/kepler/distributed/DistributedServerAttribute.java
>    trunk/src/org/kepler/distributed/DistributionFactory.java
>    trunk/src/org/kepler/distributed/InvalidTokenException.java
>    trunk/src/org/kepler/distributed/JobController.java
>    trunk/src/org/kepler/distributed/KeplerRemoteJobMonitorServlet.java
>    trunk/src/org/kepler/distributed/MasterController.java
>    trunk/src/org/kepler/distributed/MemoryUsage.java
>    trunk/src/org/kepler/distributed/NotRestartableException.java
>    trunk/src/org/kepler/distributed/RemoteActor.java
>    trunk/src/org/kepler/distributed/Slave.java
>    trunk/src/org/kepler/distributed/SlaveAccessToken.java
>    trunk/src/org/kepler/distributed/SlaveController.java
> Log:
> Make master-slave to be a separate module
> 
> Added: trunk/.classpath
> ===================================================================
> --- trunk/.classpath	                        (rev 0)
> +++ trunk/.classpath	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,17 @@
> +<classpath>
> +  <classpathentry kind="output" path="target/classes"/>
> +  <classpathentry excluding="**/.svn/|**/CVS/" kind="src" path="src"/>
> +  <classpathentry excluding="**/.svn/|**/CVS/" kind="src" path="configs"/>
> +  <classpathentry excluding="**/.svn/|**/CVS/|images/|testdata/" kind="src" path="lib"/>
> +  <classpathentry excluding="**/.svn/|**/CVS/" kind="src" path="resources"/>
> +  <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
> +  <classpathentry exported="true" kind="lib" path="lib/jar/jargon_v2.0.jar"/>
> +  <classpathentry exported="true" kind="lib" path="lib/jargon_v2.0.jar"/>
> +  <classpathentry combineaccessrules="false" kind="src" path="/loader"/>
> +  <classpathentry combineaccessrules="false" kind="src" path="/util"/>
> +  <classpathentry combineaccessrules="false" kind="src" path="/core"/>
> +  <classpathentry combineaccessrules="false" kind="src" path="/ptolemy"/>
> +  <classpathentry combineaccessrules="false" kind="src" path="/actors"/>
> +  <classpathentry combineaccessrules="false" kind="src" path="/directors"/>
> +  <classpathentry combineaccessrules="false" kind="src" path="/common"/>
> +</classpath>
> 
> Added: trunk/.project
> ===================================================================
> --- trunk/.project	                        (rev 0)
> +++ trunk/.project	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,12 @@
> +<projectDescription>
> +  <name>master-slave</name>
> +  <projects/>
> +  <buildSpec>
> +    <buildCommand>
> +      <name>org.eclipse.jdt.core.javabuilder</name>
> +    </buildCommand>
> +  </buildSpec>
> +  <natures>
> +    <nature>org.eclipse.jdt.core.javanature</nature>
> +  </natures>
> +</projectDescription>
> 
> Added: trunk/build.xml
> ===================================================================
> --- trunk/build.xml	                        (rev 0)
> +++ trunk/build.xml	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,104 @@
> +<!--
> + *    '$RCSfile$'                                                                         
> + *
> + *     '$Author: aschultz $'
> + *       '$Date: 2008-08-21 18:37:56 -0700 (Thu, 21 Aug 2008) $'
> + *   '$Revision: 7748 $'
> + *
> + *  For Details: http://kepler.ecoinformatics.org
> + *
> + * Copyright (c) 2004 The Regents of the University of California.
> + * All rights reserved.
> + *
> + * Permission is hereby granted, without written agreement and without
> + * license or royalty fees, to use, copy, modify, and distribute this
> + * software and its documentation for any purpose, provided that the
> + * above copyright notice and the following two paragraphs appear in
> + * all copies of this software.
> + *
> + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
> + * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
> + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
> + * IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY
> + * OF SUCH DAMAGE.
> + *
> + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
> + * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY
> + * OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
> + * UPDATES, ?, OR MODIFICATIONS.
> +-->
> +<project name="kepler" default="usage" basedir="../">
> +
> +  <target name="preinit">
> +    <property file="master-slave/resources/system.properties/build.properties"/>  <!-- USER SPECIFIC PROPS -->
> +    <echo>ant is using JDK version: ${ant.java.version}</echo>
> +  </target>
> +
> +  <target name="setcommonclasspath">
> +
> +    <path id="project.class.path">
> +	  <pathelement location="."/>
> +      <pathelement location="common/configs/"/>
> +	  <pathelement location="master-slave/target/classes"/>
> +	  <pathelement location="loader/target/classes"/>
> +	  <pathelement location="util/target/classes"/>
> +	  <pathelement location="core/target/classes"/>
> +	  <pathelement location="actors/target/classes"/>
> +	  <pathelement location="directors/target/classes"/>
> +
> +	  <pathelement location="common/target/classes"/>
> +	  <pathelement location="ptolemy/target/classes"/>
> +
> +
> +      <!-- Project jars -->
> +      <fileset dir="master-slave/lib/jar">
> +        <include name="**/*.jar"/>
> +      </fileset>
> +      <fileset dir="loader/lib/jar">
> +        <include name="**/*.jar"/>
> +      </fileset>
> +      <fileset dir="core/lib/jar">
> +        <include name="**/*.jar"/>
> +      </fileset>
> +      <fileset dir="util/lib/jar">
> +        <include name="*.jar"/>
> +      </fileset>
> +      <fileset dir="actors/lib/jar">
> +        <include name="*.jar"/>
> +      </fileset>
> +      <fileset dir="directors/lib/jar">
> +        <include name="*.jar"/>
> +      </fileset>
> +      <fileset dir="common/lib/jar">
> +        <include name="*.jar"/>
> +      </fileset>
> +      <fileset dir="ptolemy/lib">
> +        <include name="*.jar"/>
> +      </fileset>
> +    </path>
> +    <property name="classpath" refid="project.class.path"/>
> +  </target>
> +
> +
> +  <!-- runs the slave controller-->
> +  <target name="runSlaveController" depends="preinit, setcommonclasspath">
> +    <echo>name=${name}</echo>
> +    <echo>Registering with the EarthGrid: ${register}</echo>
> +    <echo>Registration Config: ${registrationServer}</echo>
> +    <echo>Registering as: ${hostname}</echo>
> +    <java classname="org.kepler.distributed.SlaveController" classpath="${classpath}" fork="yes">
> +      <arg value="-register=${register}"/>
> +      <arg value="-hostName=${hostname}"/>
> +      <arg value="-registrationServer=${registrationServer}"/>
> +      <jvmarg value="-Djava.security.policy=${pwd}/configs/ptolemy/configs/wideopen.policy"/>
> +      <jvmarg value="-Djava.endorsed.dirs=./lib/jar/base-jars/apache"/>
> +      <jvmarg value="-Xmx512m"/>
> +      <jvmarg value="-Xss5m"/>
> +      <jvmarg value="-Djava.library.path=${javalibpath}"/>
> +      <env key="LD_LIBRARY_PATH" path="${javalibpath}"/>
> +    </java>
> +  </target>
> +
> +</project>
> 
> Added: trunk/configs/ptolemy/configs/kepler/uiMenuMappings_en_US.properties
> ===================================================================
> --- trunk/configs/ptolemy/configs/kepler/uiMenuMappings_en_US.properties	                        (rev 0)
> +++ trunk/configs/ptolemy/configs/kepler/uiMenuMappings_en_US.properties	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,391 @@
> +################################################################################
> +#
> +#    '$RCSfile$'
> +#
> +#     '$Author: barseghian $'
> +#       '$Date: 2008-04-14 11:31:18 -0700 (Mon, 14 Apr 2008) $'
> +#   '$Revision: 7104 $'
> +#
> +# This ResourceBundle contains the mappings used by the kepler menu framework
> +#
> +# MENUBAR MENU MAPPINGS - HOWTO:
> +# These are KEPLER menu assignments.
> +# Valid entries are in one of the following forms:
> +#
> +# 1) RE-USING PTII MENU ITEMS:
> +#             <KEPLER MENU LOCATION>=<PTII MENU LOCATION>
> +#
> +#    Each Key and its corresponding Value are a delimited String
> +#    representation of the hierarchical "path" to this menu item.
> +#    For example, the "Graph Editor" menu item
> +#    beneath the "New" item on the "File" menu would have
> +#    a menuPath of File->New->Graph Editor. Delimeter is
> +#    "->" (no quotes), and *escaped* spaces are allowed within menu
> +#    text strings, but not around the delimiters; i.e:
> +#     "New->Graph\ Editor" is OK, but "File\ ->New" is not.
> +#
> +#    EXAMPLE:
> +#             File->New->Workflow=File->New->Graph\ Editor
> +#
> +#    This would take the Action that was originally assigned to the
> +#    PTII menu location at "File->New->Graph\ Editor", and would
> +#    re-assign it to a Kepler menu that will be created at
> +#    "File->New->Workflow"
> +#
> +#    * NOTE (i): the "key" part of the key=value pair (i.e. the KEPLER MENU
> +#         LOCATION) is case-sensitive - The menu text shown in Kepler will be
> +#         exactly the same as the "key" text.
> +#
> +#    * NOTE (ii): the "value" part of the key=value pair (i.e. the PTII MENU
> +#         LOCATION) is *not* case-sensitive - so you don't need to worry about
> +#         whether the original PTII menu was File->Print or File->print - either
> +#         form will work.
> +#
> +#    * NOTE (iii): the "value" part of the key=value pair ***MUST*** contain at
> +#         least one delimiter ("->"), otherwise it will be assumed to be a
> +#         classname; see section (2):
> +#
> +# 2) INSTANTIATING NEW KEPLER ACTIONS:
> +#             <KEPLER MENU LOCATION>=fully.qualified.Classname
> +#
> +#    Again, each Key is a delimited String representation of the
> +#    hierarchical "path" to this Kepler menu item (see above).
> +#    Each value is a fully-qualified classname of a class that implements the
> +#    javax.swing.Action interface, and which will be instantiated and assigned
> +#    to the menu location specified in the key.
> +#
> +#    * NOTE (iv): the "key" part of the key=value pair (i.e. the KEPLER MENU
> +#         LOCATION) is case-sensitive - see explanation in NOTE (i), above.
> +#
> +#    * NOTE (v): the "value" part of the key=value pair is also case-sensitive
> +#         when using this fully.qualified.Classname form. it should match the
> +#         case of the actual fully.qualified.Classname exactly
> +#
> +#
> +# 3) NOTE ON ACCELERATOR KEY ASSIGNMENTS:
> +#
> +#    To add accelerator key assignments (Alt+whatever), and thus show the
> +#    relevant letter of the menu name as underlined, add a tilde (~) before
> +#    the letter that should be the accelerator, but ONLY IN THE KEY (the part
> +#    before the "="); for example, in the top-level Workflow menu, to make the
> +#    "o" an accelerator key (so the user can access it by typing Alt+o), and to
> +#    add an underline below the "o", the mapping entry would look like this:
> +#
> +#      W~orkflow->Add\ Relation=Graph->New\ Relation
> +#
> +#    NOTE: If you have more than one entry for a given menu, all entries
> +#    *should* have the same accelerator key set; however, in the event that
> +#    conflicting entries are found, only the *first* entry will be used.  For
> +#    example, if the following mappings appear in this order:
> +#
> +#    ~File->Open\ URL=File->Open\ URL
> +#    File->MENU_SEPARATOR_1=-------------------
> +#    F~ile->New\ Workflow->Blank=File->New->Graph\ Editor
> +#
> +#    ...then the first accelerator (the "F") will be the one that is assigned.
> +#    This enables the inclusion of only one accelerator tilde on the first
> +#    line, if desired, in order to enhance readability - instead of repeating
> +#    the accelerator for all entries. Consequently, if the first occurence of a
> +#    menu does *not* have an accelerator assigned, the menu will not have an
> +#    accelerator key, even if a subsequent mapping does try to introduce a key!
> +#
> +# 4) ADDING MENU SEPARATORS:
> +#
> +#    To add a menu separator, add a key=value pair of the following form:
> +#    MenuName->MENU_SEPARATOR_<UNIQUE number>=<one or more chars>.
> +#    So for example, a separator in the File menu might look like this:
> +#    ...
> +#    File->Open\ URL=File->Open\ URL
> +#    File->MENU_SEPARATOR_1=-------------------
> +#    File->New\ Workflow->Blank=File->New->Graph\ Editor
> +#    ...etc
> +#    The number after the "MENU_SEPARATOR_" MUST be unique for THIS particular
> +#    menu - if it is not, only the first separator will appear in Kepler. One
> +#    way is to assign an incrementing int to each menu separator (1, 2, 3.. etc)
> +#    (note: they are not *required* to be in order - it's just easier to track)
> +#    The choice of characters after the "=" is fairly arbitrary, provided
> +#    there is at least one character, and none of the characters belong to the
> +#    set of "special" characters (see important note below); however, you should
> +#    be consistent to avoid confusion. I have chosen "-------------------" to
> +#    mimic the appearance of a menu separator, so it is obvious at a glance.
> +#
> +# * * * * * * * * * * * * IMPORTANT NOTE FOR ALL ENTRIES * * * * * * * * * * * *
> +#
> +#   The following characters MUST be escaped with a backslash:
> +#      <whitespace>   :   #   !   \    =
> +#   (EXCEPT where ":" "=" or " " are used as a delimeter between the key and
> +#   its corresponding value). This means that any WHITESPACE characters
> +#   *MUST* be escaped with a backslash, thus  \:
> +#   for example:    WRONG - File->New->Workflow=File->New->Graph Editor
> +#                 CORRECT - File->New->Workflow=File->New->Graph\ Editor
> +#
> +# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
> +################################################################################
> +
> +#############################
> +# FILE MENU
> +#############################
> +
> +
> +
> +#############################
> +# FILE MENU
> +#############################
> +
> +~File->Open\ ~File...=File->Open\ File
> +File->Open\ ~URL...=File->Open\ URL
> +File->MENU_SEPARATOR_1=-------------------
> +File->Import\ Archive\ (KAR)=org.kepler.gui.ImportArchiveAction
> +File->Export\ Workflow\ as\ Archive\ (KAR)=org.kepler.gui.ExportArchiveAction
> +File->MENU_SEPARATOR_2=-------------------
> +File->~New\ Workflow->~Blank=File->New->Graph\ Editor
> +File->New\ Workflow->~FSM\ Model=File->New->FSM\ Editor
> +File->New\ Workflow->~Modal\ Model=File->New->Modal\ Model
> +File->~Save=File->Save
> +File->Save\ ~As...=File->SaveAs
> +File->MENU_SEPARATOR_3=-------------------
> +File->~Print...=File->Print
> +File->MENU_SEPARATOR_4=-------------------
> +File->~Close=File->Close
> +
> +# [LLD>] "Close All" just closes all the various workflows open but still leaves
> +# the one application window open with a blank canvas.
> +#
> +# File->C~lose\ All=***@TODO***
> +
> +File->E~xit=File->Exit
> +
> +File->MENU_SEPARATOR_5=-------------------
> +# Recently-opened files here...
> +# Recently-opened files here...
> +# Recently-opened files here...
> +####
> +
> +
> +#############################
> +# EDIT MENU
> +#############################
> +
> +~Edit->~Undo=Edit->Undo
> +Edit->~Redo=Edit->Redo
> +Edit->MENU_SEPARATOR_1=--------------------
> +Edit->Cu~t=Edit->Cut
> +Edit->~Copy=Edit->Copy
> +Edit->~Paste=Edit->Paste
> +Edit->~Delete=Edit->Cut
> +
> +
> +#############################
> +# VIEW MENU
> +#############################
> +
> +~View->Zoom\ ~Reset=View->Zoom\ Reset
> +View->Zoom\ ~In=View->Zoom\ In
> +View->Zoom\ ~Out=View->Zoom\ Out
> +View->Zoom\ Fi~t=View->Zoom\ Fit
> +View->~Full\ Screen=View->Full\ Screen
> +View->~Automate\ Layout=Graph->Automatic\ Layout
> +View->MENU_SEPARATOR_1=-------------------
> +
> +# [LLD>] I think some of this is existing and some new.  For instance the
> +# names of actors and ports are there but I don't remember where you can set
> +# the display.  I think it is buried in one of the dialogs somewhere but not
> +# on the menus.  What is different I believe is that the names need to be
> +# coupled with the actor and not some free flowing piece of text or something,
> +# if I'm remembering correctly.  Workflow notes exist but I don't think we
> +# have anyway to turn them on or off and again I think they are free flowing
> +# text items instead of couple logically with the workflow.  So yes there is
> +# some functionality that needs to be "fixed" or incorporated to make these
> +# things work correctly.  I presented this stuff a long time ago and people
> +# seemed to be in agreement but I don't know that we ever created a specific
> +# bug/task for this stuff.  I'd have to look at the bugs.
> +#
> +# View->~Names/Notes->Show\ All\ ~Names/Notes=***@TODO***
> +# View->Names/Notes->Show\ ~Workflow\ Notes=***@TODO***
> +# View->Names/Notes->Show\ All\ A~ctor\ Notes=***@TODO***
> +# View->Names/Notes->Show\ All\ ~Actor\ Names=***@TODO***
> +# View->Names/Notes->Show\ All\ ~Port\ Names=***@TODO***
> +
> +View->MENU_SEPARATOR_2=-------------------
> +View->Tr~ee\ View=View->Tree\ View
> +View->~XML\ View=View->XML\ View
> +
> +# NOTE - the following item shows up ONLY in the HTML viewer that
> +# displays the EML Metadata when "Get Metadata" is used on a data source
> +View->Page\ Source=View->Source
> +
> +
> +#############################
> +# WORKFLOW MENU
> +#############################
> +
> +# W~orkflow->~Run=***@TODO***
> +W~orkflow->Runtime\ ~Window...=View->Run\ Window
> +# Workflow->~Pause=***@TODO***
> +# Workflow->~Stop=***@TODO***
> +Workflow->MENU_SEPARATOR_1=-------------------
> +# Workflow->C~onfigure->~Workflow=***@TODO***
> +# Workflow->C~onfigure->~Director=***@TODO***
> +# Workflow->C~onfigure->~Actor=***@TODO***
> +Workflow->MENU_SEPARATOR_2=-------------------
> +# Workflow->~Open\ Actor=***@TODO***
> +
> +# [LLD>] this is new so that when a user is drilling down into a hierarchical
> +# model they have a way of moving back up the hierarchy.  I can't remember how
> +# they current do this navigation.
> +#
> +# Workflow->~Move\ Up\ One\ Level=***@TODO***
> +
> +Workflow->~Add\ Relation=Graph->New\ Relation
> +
> +# Note - the following appears only in the Finite State Machine (FSM) screen,
> +# instead of New Relation
> +Workflow->~New\ State=Graph->New\ State
> +
> +Workflow->Add\ Por~t->~Input\ Port=Graph->New\ Input\ Port
> +Workflow->Add\ Port->~Output\ Port=Graph->New\ Output\ Port
> +Workflow->Add\ Port->Input/Output\ ~Port=Graph->New\ Input/Output\ Port
> +Workflow->Add\ Port->I~nput\ Multiport=Graph->New\ Input\ Multiport
> +Workflow->Add\ Port->Output\ M~ultiport=Graph->New\ Output\ Multiport
> +Workflow->Add\ Port->Input/Output\ ~Multiport=Graph->New\ Input/Output\ Multiport
> +
> +
> +#############################
> +# TOOLS MENU
> +#############################
> +
> +### OK, per Laura's email of 12Jan06:
> +~Tools->~Animate\ at\ Runtime...=org.kepler.gui.RunWithFeedbackChkBoxAction
> +## ~Tools->Run\ with\ ~Feedback=Debug->Animate\ Execution
> +
> +
> +# [LLD] Listen to Director just listens to the director only
> +# but may not show everything that is happening in the workflow.  Debug would
> +# be a window that is showing the code execution for the entire workflow as
> +# it executes and Run with Feedback would be just highlighting which actor the
> +# workflow is on as it executes but with no other window open showing any code
> +# execution or messages behind the scenes.  If it turns out that "listen to
> +# director" shows the same as debug then we only need one item and I would
> +# leave it Tools->Debug if that is the case and remove Tools->Listen to
> +# Director.  Let's leave both for now until I find out the difference, if
> +# there is one.
> +#
> +# MB Note - if we use the mapping Tools->Debug=Debug->Listen\ to\ Director, the
> +# resulting menu item appears as "Listen to Director" instead of "Degbug", which
> +# gives us 2 menu items with the same name
> +# - so commenting this out for now, until this bug is fixed
> +#
> +#Tools->~Debug=Debug->Listen\ to\ Director
> +
> +Tools->Listen\ to\ Di~rector=Debug->Listen\ to\ Director
> +
> +# Tools->Listen\ to\ Act~or=***@TODO***
> +Tools->MENU_SEPARATOR_1=-------------------
> +# Tools->T~ype\ Check->~Visual=***@TODO***
> +# Tools->Type\ Check->~Summary=***@TODO***
> +# Tools->Type\ Check->~Both=***@TODO***
> +# Tools->~Set\ Checkpoints=***@TODO***
> +Tools->MENU_SEPARATOR_2=-------------------
> +
> +# [LLD>] this is new functionality, the idea is you enter an actor ID and the
> +# system highlights that actor wherever it is in the workflow.  Mark suggested
> +# this as a way to find things when one person is talking to another person
> +# and saying look at this actor in this workflow but the workflow has lots of
> +# actors and levels so it isn't easy for the other person to find the actor
> +# being specifie.
> +#
> +# Tools->~Locate\ Actor=***@TODO***
> +
> +# Removed for Beta release, per meeting in ABQ, 4May06
> +# Reactivated on 09/05/2007; seems to be working now - DFH
> +Tools->~Create\ Composite\ Actor=Graph->Create\ Hierarchy
> +
> +# [LLD>] this is new functionality also, an actor is highlighted and the user
> +# requests a list of other actors that are structurally or semantically
> +# compatible (a tool for helping people build workflows)
> +#
> +# Tools->Co~mpatible\ Components=***@TODO***
> +
> +# [LLD>] this is part of the stuff that Shawn is working on -- users will pick
> +# terms from an ontology and annotate the semantic meaning of an actor or
> +# director
> +#
> +# Tools->A~nnotate\ Component=***@TODO***
> +
> +Tools->MENU_SEPARATOR_3=-------------------
> +
> +######
> +Tools->~Expression\ Evaluator=File->New->Expression\ Evaluator
> +
> +Tools->Instantiate\ Com~ponent=Graph->Instantiate\ Entity
> +Tools->Instantiate\ Attri~bute=Graph->Instantiate\ Attribute
> +
> +# [LLD>] current functionality in one of the right click menus
> +#
> +# Tools->~Unit\ Constraints\ Solver=***@TODO***
> +
> +Tools->Chec~k\ System\ Settings=View->JVM\ Properties
> +Tools->~Distributed\ Computing\ Options=org.kepler.distributed.DistributedConfigAction
> +Tools->Ecogrid\ ~Authentication=org.kepler.gui.AuthenticateAction
> +
> +# [LLD>] this is new and related to authentication, it is an attempt to let
> +# the users know what resources they currently have access to but Matt has
> +# said there is now way to show all of them if a user has lots of access and I
> +# said well they need to at least understand in some way what they have access
> +# to -- this may be moot later on when role based access is implement, so it
> +# is a question mark for now and something we need to resolve
> +#
> +# Tools->List\ Res~ource\ Access=***@TODO***
> +
> +Tools->MENU_SEPARATOR_4=-------------------
> +
> +# see bug #2150 - "Edit Custom Icon' menu item doesn't work"
> +# [LLD>] ...take it out for now.  We are going to allow users to create new
> +# icons as long as they stay in the current color scheme but I don't know how
> +# that will be done -- I assume a developer will do this from some code or API.
> +#
> +# Tools->~Icon\ Editor=
> +
> +Tools->~Text\ Editor=File->New->Text\ Editor
> +
> +
> +#############################
> +# WINDOW MENU
> +#############################
> +
> +# NOTE - following is not correct - needs to list window
> +# name (e.g. "Run Window - MyWorkflow" etc)
> +~Window->~Runtime\ Window\ -\ =View->Run\ Window
> +Window->MENU_SEPARATOR_1=-------------------
> +# open windows here
> +# open windows here
> +# open windows here
> +
> +
> +
> +#############################
> +# SPECIAL MENU
> +# NOTE - this is shown only in plot windows
> +#############################
> +
> +Special->Clear=SPECIAL->CLEAR
> +Special->Export=Special->Export
> +Special->Fill=Special->Fill
> +Special->Reset\ Axes=Special->Reset\ Axes
> +Special->Sample\ Plot=Special->Sample\ Plot
> +
> +
> +#############################
> +# HELP MENU
> +#############################
> +
> +~Help->~About=Help->About
> +
> +# commenting out for alpha 9, since the CookbookAction
> +# currently shows only a test page
> +# Help->~Cookbook=org.kepler.gui.CookbookAction
> +
> +Help->~Documentation=Help->Help
> +
> +
> +
> 
> Added: trunk/lib/jar/jargon_v2.0.jar
> ===================================================================
> (Binary files differ)
> 
> 
> Property changes on: trunk/lib/jar/jargon_v2.0.jar
> ___________________________________________________________________
> Name: svn:mime-type
>    + application/octet-stream
> 
> Added: trunk/module-info/modules.txt
> ===================================================================
> --- trunk/module-info/modules.txt	                        (rev 0)
> +++ trunk/module-info/modules.txt	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,8 @@
> +master-slave
> +loader
> +util
> +core
> +ptolemy svn://source.eecs.berkeley.edu/chess/ptII/trunk
> +actors
> +directors
> +common
> 
> Added: trunk/origmodel.xml
> ===================================================================
> --- trunk/origmodel.xml	                        (rev 0)
> +++ trunk/origmodel.xml	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,132 @@
> +    <entity name="DistributedCompositeActor" class="org.kepler.distributed.DistributedCompositeActor">
> +        <property name="entityId" class="org.kepler.moml.NamedObjId" value="urn:lsid:kepler-project.org:actor:725:1">
> +        </property>
> +        <property name="class" class="ptolemy.kernel.util.StringAttribute" value="org.kepler.distributed.DistributedCompositeActor">
> +            <property name="id" class="ptolemy.kernel.util.StringAttribute" value="urn:lsid:kepler-project.org:class:000:1">
> +            </property>
> +        </property>
> +        <property name="semanticType00" class="org.kepler.sms.SemanticType" value="urn:lsid:localhost:onto:1:1#Actor">
> +        </property>
> +        <property name="semanticType11" class="org.kepler.sms.SemanticType" value="urn:lsid:localhost:onto:2:1#GeneralPurpose">
> +        </property>
> +        <property name="semanticType22" class="org.kepler.sms.SemanticType" value="urn:lsid:localhost:onto:2:1#Workflow">
> +        </property>
> +        <property name="_location" class="ptolemy.kernel.util.Location" value="[230.0, 285.0]">
> +        </property>
> +        <property name="SDF Director" class="ptolemy.domains.sdf.kernel.SDFDirector">
> +            <property name="iterations" class="ptolemy.data.expr.Parameter" value="1">
> +            </property>
> +            <property name="vectorizationFactor" class="ptolemy.data.expr.Parameter" value="1">
> +            </property>
> +            <property name="allowDisconnectedGraphs" class="ptolemy.data.expr.Parameter" value="true">
> +            </property>
> +            <property name="allowRateChanges" class="ptolemy.data.expr.Parameter" value="false">
> +            </property>
> +            <property name="constrainBufferSizes" class="ptolemy.data.expr.Parameter" value="true">
> +            </property>
> +            <property name="period" class="ptolemy.data.expr.Parameter" value="0.0">
> +            </property>
> +            <property name="synchronizeToRealTime" class="ptolemy.data.expr.Parameter" value="false">
> +            </property>
> +            <property name="timeResolution" class="ptolemy.actor.parameters.SharedParameter" value="1E-10">
> +            </property>
> +            <property name="Scheduler" class="ptolemy.domains.sdf.kernel.SDFScheduler">
> +                <property name="constrainBufferSizes" class="ptolemy.data.expr.Parameter" value="constrainBufferSizes">
> +                </property>
> +            </property>
> +<property name="KeplerDocumentation" class="ptolemy.vergil.basic.KeplerDocumentationAttribute">
> +<property name="description" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>null</configure></property>
> +<property name="author" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>Steve Neuendorffer</configure></property>
> +<property name="version" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>null</configure></property>
> +<property name="userLevelDocumentation" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>&#10;&lt;p&gt;The SDF Director is often used to oversee fairly simple, sequential workflows in which the director can determine the order of actor invocation from the workflow. Types of workflows that would run well under an SDF Director include processing and reformatting tabular data, converting one data type to another, and reading and plotting a series of data points. A workflow in which an image is read, processed (rotated, scaled, clipped, filtered, etc.), and then displayed, is also an example of a sequential workflow that requires a director simply to ensure that each actor fires in the proper order (i.e., that each actor executes only after it receives its required inputs).&lt;/p&gt;&#10;&#10;&lt;p&gt;The SDF Director is very efficient and will not tax system resources with overhead. However, this efficiency requires that certain conditions be met, namely that the 
da
>  ta consumption and production rate of each actor in an SDF workflow be constant and declared. If an actor reads one piece of data and calculates and outputs a single result, it must always read and output a single token of data. This data rate cannot change during workflow execution and, in general, workflows that require dynamic scheduling and/or flow control cannot use this director. Additionally, the SDF Director has no understanding of passing time (at least by default), and actors that depend on a notion of time may not work as expected. For example, a TimedPlotter actor will plot all values at time zero when used in SDF. &lt;/p&gt;&#10;&#10;&lt;p&gt;By default, the SDF Director requires that all actors in its workflow be connected. Otherwise, the director cannot account for concurrency between disconnected workflow parts. Usually, a PN Director should be used for workflows that contain disconnected actors; however, the SDF Director's allowDisconnectedGraphs parameter
 m
>  ay also be set to true. The SDF Director will then schedule each disconnected &quot;island&quot; independently. The director cannot infer the sequential relationship between disconnected actors (i.e., nothing forces the director to finish executing all actors on one island before firing actors on another). However, the order of execution within each island should be correct. Usually, disconnected graphs in an SDF model indicate an error.&lt;/p&gt;&#10; &#10;&lt;p&gt;Because SDF Directors schedule actors to fire only after they receive their inputs, workflows that require loops (feeding an actor's output back into its input port for further processing) can cause &quot;deadlock&quot; errors. The deadlock errors occur because the actor depends on its own output value as an initial input. To fix this problem, use a SampleDelay actor to generate and inject an initial input value into the workflow.&lt;/p&gt;&#10;&#10;&lt;p&gt;The SDF Director determines the order in which actors
 e
>  xecute and how many times each actor needs to be fired to complete a single iteration of the workflow. This schedule is calculated BEFORE the director begins to iterate the workflow. Because the SDF Director calculates a schedule in advance, it is quite efficient. However, SDF workflows must be static. In other words, the same number of tokens must be consumed/produced at every iteration of the workflow. Workflows that require dynamic control structures, such as a BooleanSwitch actor that sends output on one of two ports depending on the value of a 'control', cannot be used with an SDF Director because the number of tokens on each output can change for each execution.&lt;/p&gt;&#10;&#10;&lt;p&gt;Unless otherwise specified, the SDF Director assumes that each actor consumes and produces exactly one token per channel on each firing. Actors that do not follow the one-token-per-channel firing convention (e.g., Repeat or Ramp) must declare the number of tokens they produce or co
ns
>  ume via the appropriate parameters. &lt;/p&gt;&#10;&#10;&lt;p&gt;The number of times a workflow is iterated is controlled by the director's iterations parameter. By default, this parameter is set to &quot;0&quot;. Note that &quot;0&quot; does not mean &quot;no iterations.&quot; Rather, &quot;0&quot; means that the workflow will iterate forever. Values greater than zero specify the actual number of times the director should execute the entire workflow. A value of 1, meaning that the director will run the workflow once, is often the best setting when building an SDF workflow. &lt;/p&gt;&#10;&#10;&lt;p&gt;The amount of data processed by an SDF workflow is a function of both the number of times the workflow iterates and the value of the director's vectorizationFactor parameter. The vectorizationFactor is used to increase the efficiency of a workflow by increasing the number of times actors fire each time the workflow iterates. If the parameter is set to a positive integer (oth
er
>   than 1), the director will fire each actor the specified number of times more than normal. The default is 1, indicating that no vectorization should be performed. Keep in mind that changing the vectorizationFactor parameter changes the meaning of a nested SDF workflow and may cause deadlock in a workflow that uses it. &lt;/p&gt;&#10;&#10;&lt;p&gt;The SDF Director has several advanced parameters that are generally only relevant when an SDF workflow contains composite components. In most cases the period, timeResolution, synchronizeToRealTime, allowRateChanges, timeResolution, and constrainBufferSizes parameters can be left at their default values.&lt;/p&gt;&#10;&#10;&lt;p&gt;For more information about the SDF Director, see the Ptolemy documentation (http://ptolemy.eecs.berkeley.edu/papers/05/ptIIdesign3-domains/ptIIdesign3-domains.pdf).&lt;/p&gt;&#10;&#10;</configure></property>
> +<property name="prop:allowDisconnectedGraphs" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>Specify whether to allow disconnected actors in the workflow (by default, all actors are required to be connected). If disconnected actors are permitted, the SDF Director will schedule each disconnected 'island' independently. Nothing &quot;forces&quot; the director to finish executing all actors on one island before firing actors on another. However, the order of execution within each island should be correct. Usually, disconnected graphs in an SDF workflow indicate an error.</configure></property>
> +<property name="prop:allowRateChanges" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>Specify whether dynamic rate changes are permitted or not. By default, rate changes are not permitted, and the director will perform a check to disallow such workflows. If the parameter is selected, then workflows that require rate parameters to be modified during execution are valid, and the SDF Director will dynamically compute a new schedule at runtime. This is an advanced parameter that can usually be left at its default value.</configure></property>
> +<property name="prop:constrainBufferSizes" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>Specify whether buffer sizes are fixed. By default, buffers are fixed, and attempts to write to the buffer that cause the buffer to exceed its scheduled size result in an error. This is an advanced parameter that can usually be left at its default value.</configure></property>
> +<property name="prop:timeResolution" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>The time precision used by this director. All time values are rounded to the nearest multiple of this number. The value is a double that defaults to &quot;1E-10&quot; (which is 10-10). This is an advanced parameter that can usually be left at its default value.</configure></property>
> +<property name="prop:iterations" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>Specify the number of times a workflow is iterated. By default, this parameter is set to &quot;0&quot;. Note that &quot;0&quot; does not mean &quot;no iterations.&quot; Rather, &quot;0&quot; means that the workflow will iterate forever. Values greater than zero specify the actual number of times the director should execute the entire workflow. A value of 1, meaning that the director will run the workflow once, is often the best setting when building an SDF workflow. </configure></property>
> +<property name="prop:vectorizationFactor" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>The vectorizationFactor is used to increase the efficiency of a workflow by increasing the number of times actors fire each time the workflow iterates. If the parameter is set to a positive integer (other than 1), the director will fire each actor the specified number of times more than normal. The default is 1, indicating that no vectorization should be performed. Keep in mind that changing the vectorizationFactor parameter changes the meaning of a nested SDF workflow and may cause deadlock in a workflow that uses it. </configure></property>
> +<property name="prop:synchronizeToRealTime" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>Specify whether the execution should synchronize to real time or not. By default, the director does not synchronize to real time. If synchronize is selected, the director will only process the workflow when elapsed real time matches the product of the period parameter and the iteration count. Note: if the period parameter has a value of 0.0 (the default), then selecting this parameter has no effect. This is an advanced parameter that can usually be left at its default value.</configure></property>
> +<property name="prop:period" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>The time period of each iteration. The value is a double that defaults to 0.0, which means that the director does not increment workflow time. If the value greater than 0.0, the actor will increment workflow time each time it fires. This is an advanced parameter that can usually be left at its default value. </configure></property>
> +</property>            <property name="entityId" class="org.kepler.moml.NamedObjId" value="urn:lsid:kepler-project.org:director:1:1">
> +            </property>
> +            <property name="class" class="ptolemy.kernel.util.StringAttribute" value="ptolemy.domains.sdf.kernel.SDFDirector">
> +                <property name="id" class="ptolemy.kernel.util.StringAttribute" value="urn:lsid:kepler-project.org:directorclass:1:1">
> +                </property>
> +            </property>
> +            <property name="semanticType00" class="org.kepler.sms.SemanticType" value="urn:lsid:localhost:onto:1:1#Director">
> +            </property>
> +            <property name="semanticType11" class="org.kepler.sms.SemanticType" value="urn:lsid:localhost:onto:2:1#Director">
> +            </property>
> +            <property name="_location" class="ptolemy.kernel.util.Location" value="{150, 60}">
> +            </property>
> +        </property>
> +        <property name="DistributedServerAttribute0" class="org.kepler.distributed.DistributedServerAttribute" value="localhost">
> +        </property>
> +        <property name="DistributedServerAttribute1" class="org.kepler.distributed.DistributedServerAttribute" value="kepler.sdsc.edu">
> +        </property>
> +        <port name="input" class="ptolemy.actor.TypedIOPort">
> +            <property name="input"/>
> +            <property name="_location" class="ptolemy.kernel.util.Location" value="[110.0, 255.0]">
> +            </property>
> +            <property name="_type" class="ptolemy.actor.TypeAttribute" value="general">
> +            </property>
> +        </port>
> +        <port name="output" class="ptolemy.actor.TypedIOPort">
> +            <property name="output"/>
> +            <property name="_location" class="ptolemy.kernel.util.Location" value="[545.0, 385.0]">
> +            </property>
> +            <property name="_type" class="ptolemy.actor.TypeAttribute" value="general">
> +            </property>
> +        </port>
> +        <port name="input2" class="ptolemy.actor.TypedIOPort">
> +            <property name="input"/>
> +            <property name="_location" class="ptolemy.kernel.util.Location" value="[105.0, 320.0]">
> +            </property>
> +            <property name="_type" class="ptolemy.actor.TypeAttribute" value="general">
> +            </property>
> +        </port>
> +        <entity name="Add or Subtract" class="ptolemy.actor.lib.AddSubtract">
> +<property name="KeplerDocumentation" class="ptolemy.vergil.basic.KeplerDocumentationAttribute">
> +<property name="description" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>null</configure></property>
> +<property name="author" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>yuhong xiong and Edward lee</configure></property>
> +<property name="version" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>null</configure></property>
> +<property name="userLevelDocumentation" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>&lt;p&gt;The AddOrSubtract actor reads values via its two input ports (plus and minus), performs an add and/or subtract operation, and outputs the result.&lt;/p&gt;&#10;&#10;&lt;p&gt;The input ports are multiports, meaning that they can accept multiple inputs. Any values received via the plus port will be added; any values received via the minus port will be subtracted. Either port can be left unconnected. Leave the minus port unconnected to create a simple adder, for example. &lt;/p&gt;&#10;&#10;&lt;p&gt;Both of the input ports are polymorphic, accepting data of multiple types. The actor will automatically resolve the input type to the least upper bound of the presented values. For example, if the plus input port receives a Boolean value on one input channel and an integer on another, the resolved type will be a string, permitting the two inputs to be concatenated as strin
gs
>  . Note that strings cannot be subtracted. If the actor resolves an input type into a type that cannot be subtracted, it will generate an error.&lt;/p&gt;&#10;&#10;&lt;p&gt;The actor outputs the sum or difference and derives an output type based on the input values.&lt;/p&gt;</configure></property>
> +<property name="port:output" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>An output port that broadcasts the sum or difference of the inputs. The actor derives the output type based on the type of the inputs.</configure></property>
> +<property name="port:minus" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>A muliport that accepts values to be subtracted. The actor automatically infers the input type based on the type of the input values.</configure></property>
> +<property name="port:plus" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>A muliport that accepts values to be added. The actor automatically infers the input type based on the type of the input values.</configure></property>
> +</property>            <property name="entityId" class="org.kepler.moml.NamedObjId" value="urn:lsid:kepler-project.org:actor:69:1">
> +            </property>
> +            <property name="class" class="ptolemy.kernel.util.StringAttribute" value="ptolemy.actor.lib.AddSubtract">
> +                <property name="id" class="ptolemy.kernel.util.StringAttribute" value="urn:lsid:kepler-project.org:class:944:1">
> +                </property>
> +            </property>
> +            <property name="semanticType000" class="org.kepler.sms.SemanticType" value="urn:lsid:localhost:onto:1:1#ArithmeticMathOperationActor">
> +            </property>
> +            <property name="semanticType111" class="org.kepler.sms.SemanticType" value="urn:lsid:localhost:onto:2:1#ArithmeticOperation">
> +            </property>
> +            <property name="_location" class="ptolemy.kernel.util.Location" value="[315.0, 290.0]">
> +            </property>
> +        </entity>
> +        <relation name="relation2" class="ptolemy.actor.TypedIORelation">
> +            <property name="width" class="ptolemy.data.expr.Parameter" value="1">
> +            </property>
> +        </relation>
> +        <relation name="relation" class="ptolemy.actor.TypedIORelation">
> +            <property name="width" class="ptolemy.data.expr.Parameter" value="1">
> +            </property>
> +            <vertex name="vertex1" value="[235.0, 270.0]">
> +            </vertex>
> +        </relation>
> +        <relation name="relation3" class="ptolemy.actor.TypedIORelation">
> +            <property name="width" class="ptolemy.data.expr.Parameter" value="1">
> +            </property>
> +            <vertex name="vertex1" value="[210.0, 315.0]">
> +            </vertex>
> +        </relation>
> +        <link port="input" relation="relation"/>
> +        <link port="output" relation="relation2"/>
> +        <link port="input2" relation="relation3"/>
> +        <link port="Add or Subtract.plus" relation="relation"/>
> +        <link port="Add or Subtract.plus" relation="relation3"/>
> +        <link port="Add or Subtract.output" relation="relation2"/>
> +    </entity>
> 
> Added: trunk/resources/system.properties/DistributedKepler.config
> ===================================================================
> --- trunk/resources/system.properties/DistributedKepler.config	                        (rev 0)
> +++ trunk/resources/system.properties/DistributedKepler.config	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,5 @@
> +localhost
> +192.168.1.8
> +ceres.nceas.ucsb.edu
> +catbert.nceas.ucsb.edu
> +192.168.1.11
> 
> Added: trunk/resources/system.properties/DistributedKeplerSlaveACL.config
> ===================================================================
> --- trunk/resources/system.properties/DistributedKeplerSlaveACL.config	                        (rev 0)
> +++ trunk/resources/system.properties/DistributedKeplerSlaveACL.config	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,18 @@
> +#this file is the access control list for the slave controller
> +#the allowable values under "allow" or "deny" are either the keyword "all"
> +#or a '\n' separated list of ldap dn's who are allowed or denied.  ldap groups
> +#are not yet supported
> +
> +#note that this file is loaded only once when the slave starts.  if you make
> +#changes to it, you'll need to restart the slave
> +
> +<allow>
> +all
> +</allow>
> +
> +<deny>
> +</deny>
> +
> +#the order sets the order for processing the allows and denys.  The allowable
> +#entries are "allowFirst" or "denyFirst"
> +<order>allowFirst</order>
> 
> Added: trunk/resources/system.properties/DistributedKeplerUser.config
> ===================================================================
> --- trunk/resources/system.properties/DistributedKeplerUser.config	                        (rev 0)
> +++ trunk/resources/system.properties/DistributedKeplerUser.config	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1 @@
> +kepler,unaffiliated,hN�
;���,
> \ No newline at end of file
> 
> Added: trunk/resources/system.properties/build.properties
> ===================================================================
> --- trunk/resources/system.properties/build.properties	                        (rev 0)
> +++ trunk/resources/system.properties/build.properties	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,41 @@
> +#============Slave Controller Options==============
> +#if you want the slave to register itself with the EarthGrid, set register to true
> +register=true
> +#the name of your host (or an IP address) as you want it registered with the Earthgrid
> +hostname=128.54.63.38
> +#the name of the server in the repositoryBundle.properties file that you want 
> +#to use to connect to the EarthGrid.  You normally don't need to change this.
> +registrationServer=keplerRepository
> +
> +#============RemoteJobMonitorServlet Options==============
> +#where you want the servlet installed
> +servletInstallDir=D:/work/tomcat/webapps/
> +bin.includes = lib/,\
> +               bin/,\
> +               META-INF/,\
> +               configs/,\
> +               ptII/,\
> +               libexpat.dll,\
> +               licenses.txt,\
> +               loaddmg.sh,\
> +               demos/,\
> +               distributed-readme.txt,\
> +               hsql-license.txt,\
> +               hsqlTool.bat,\
> +               installer/,\
> +               kepler-console.bat,\
> +               kepler.exe,\
> +               kepler.sh,\
> +               copyright.txt,\
> +               cog/,\
> +               log4j.properties,\
> +               runSlave.sh,\
> +               src/,\
> +               tests/,\
> +               website/,\
> +               workflows/,\
> +               plugins/,\
> +               INSTALL.txt,\
> +               Kepler.app/,\
> +               README.txt,\
> +               kar/
> 
> Added: trunk/rmi-registry.bat
> ===================================================================
> --- trunk/rmi-registry.bat	                        (rev 0)
> +++ trunk/rmi-registry.bat	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1 @@
> +rmiregistry -J-classpath "-Jtarget/classes;../loader/target/classes;../loader/target/classes;../util/target/classes;../core/target/classes;../actors/target/classes;../directors/target/classes;../common/target/classes;../ptolemy/target/classes;lib/jar/jargon_v2.0.jar"
> \ No newline at end of file
> 
> Added: trunk/rmi-registry.sh
> ===================================================================
> --- trunk/rmi-registry.sh	                        (rev 0)
> +++ trunk/rmi-registry.sh	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1 @@
> +rmiregistry -J-classpath -Jtarget/classes:../loader/target/classes:../loader/target/classes:../util/target/classes:../core/target/classes:../actors/target/classes:../directors/target/classes:../common/target/classes:../ptolemy/target/classes:lib/jar/jargon_v2.0.jar
> \ No newline at end of file
> 
> Added: trunk/src/org/kepler/distributed/Credential.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/Credential.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/Credential.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,104 @@
> +//  Copyright (c) 2007, Regents of the University of California
> +//  All rights reserved.
> +//
> +//  Redistribution and use in source and binary forms, with or without
> +//  modification, are permitted provided that the following conditions are
> +//  met:
> +//
> +//    * Redistributions of source code must retain the above copyright notice,
> +//  this list of conditions and the following disclaimer.
> +//    * Redistributions in binary form must reproduce the above copyright
> +//  notice, this list of conditions and the following disclaimer in the
> +//  documentation and/or other materials provided with the distribution.
> +//    * Neither the name of the University of California, San Diego (UCSD) nor
> +//  the names of its contributors may be used to endorse or promote products
> +//  derived from this software without specific prior written permission.
> +//
> +//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
> +//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> +//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> +//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> +//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
> +//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
> +//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
> +//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
> +//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> +//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
> +//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +//
> +//  PRINCIPAL AUTHOR
> +//  Chad Berkley
> +//
> +//
> +package org.kepler.distributed;
> +
> +import java.io.Serializable;
> +
> +/**
> + * '$Author: aschultz $' '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + * '$Revision: 16353 $'
> + * 
> + * Class for holding credential information
> + */
> +public class Credential implements Serializable {
> +	private String username;
> +	private String org;
> +	private String sessionid;
> +	private long expiration;
> +
> +	/**
> +	 * builds a new credential object.
> +	 */
> +	public Credential(String username, String sessionid, long expiration) {
> +		this.username = username;
> +		this.sessionid = sessionid;
> +		this.expiration = expiration;
> +	}
> +
> +	/**
> +	 * return the username associated with this credential
> +	 */
> +	public String getUsername() {
> +		return username;
> +	}
> +
> +	/**
> +	 * return the sessionid associated with this credential
> +	 */
> +	public String getSessionId() {
> +		return sessionid;
> +	}
> +
> +	/**
> +	 * returns true if this credential is expired
> +	 */
> +	public boolean isExpired() {
> +		long currentTime = System.currentTimeMillis();
> +		if (currentTime > expiration) {
> +			return true;
> +		}
> +		return false;
> +	}
> +
> +	/**
> +	 * compares another credential to this one. returns true if both are the
> +	 * same.
> +	 */
> +	public boolean equals(Credential credential) {
> +		if (this.username.equals(credential.getUsername())
> +				&& this.sessionid.equals(credential.getSessionId())) {
> +			return true;
> +		}
> +		return false;
> +	}
> +
> +	/**
> +	 * return a string representation of this credential
> +	 */
> +	public String toString() {
> +		StringBuffer sb = new StringBuffer();
> +		sb.append("user: " + username + " sessionid: " + sessionid
> +				+ " isExpired: " + isExpired());
> +		return sb.toString();
> +	}
> +}
> 
> Added: trunk/src/org/kepler/distributed/CredentialException.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/CredentialException.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/CredentialException.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,57 @@
> +//  Copyright (c) 2007, Regents of the University of California
> +//  All rights reserved.
> +//
> +//  Redistribution and use in source and binary forms, with or without
> +//  modification, are permitted provided that the following conditions are
> +//  met:
> +//
> +//    * Redistributions of source code must retain the above copyright notice,
> +//  this list of conditions and the following disclaimer.
> +//    * Redistributions in binary form must reproduce the above copyright
> +//  notice, this list of conditions and the following disclaimer in the
> +//  documentation and/or other materials provided with the distribution.
> +//    * Neither the name of the University of California, San Diego (UCSD) nor
> +//  the names of its contributors may be used to endorse or promote products
> +//  derived from this software without specific prior written permission.
> +//
> +//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
> +//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> +//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> +//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> +//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
> +//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
> +//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
> +//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
> +//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> +//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
> +//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +//
> +//  PRINCIPAL AUTHOR
> +//  Chad Berkley
> +//
> +//
> +package org.kepler.distributed;
> +
> +/**
> + * '$Author: aschultz $' '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + * '$Revision: 16353 $'
> + * 
> + * Exception for errors related to credentials
> + */
> +public class CredentialException extends Exception {
> +	public CredentialException() {
> +		super();
> +	}
> +
> +	public CredentialException(String message) {
> +		super(message);
> +	}
> +
> +	public CredentialException(String message, Throwable cause) {
> +		super(message, cause);
> +	}
> +
> +	public CredentialException(Throwable cause) {
> +		super(cause);
> +	}
> +}
> 
> Added: trunk/src/org/kepler/distributed/DCAEditorPane.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/DCAEditorPane.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/DCAEditorPane.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,496 @@
> +/**
> + *    '$RCSfile$'
> + *
> + *     '$Author: aschultz $'
> + *       '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + *   '$Revision: 16353 $'
> + *
> + *  For Details: http://kepler.ecoinformatics.org
> + *
> + * Copyright (c) 2007 The Regents of the University of California.
> + * All rights reserved.
> + *
> + * Permission is hereby granted, without written agreement and without
> + * license or royalty fees, to use, copy, modify, and distribute this
> + * software and its documentation for any purpose, provided that the
> + * above copyright notice and the following two paragraphs appear in
> + * all copies of this software.
> + *
> + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
> + * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
> + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
> + * IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY
> + * OF SUCH DAMAGE.
> + *
> + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
> + * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY
> + * OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
> + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
> + */
> +
> +package org.kepler.distributed;
> +
> +import java.awt.Component;
> +import java.awt.Dimension;
> +import java.awt.event.ActionEvent;
> +import java.awt.event.ActionListener;
> +import java.io.File;
> +import java.io.FileInputStream;
> +import java.io.FileNotFoundException;
> +import java.io.FileReader;
> +import java.io.IOException;
> +import java.util.Iterator;
> +import java.util.Vector;
> +
> +import javax.swing.BorderFactory;
> +import javax.swing.Box;
> +import javax.swing.BoxLayout;
> +import javax.swing.JButton;
> +import javax.swing.JFrame;
> +import javax.swing.JLabel;
> +import javax.swing.JList;
> +import javax.swing.JOptionPane;
> +import javax.swing.JPanel;
> +import javax.swing.JScrollPane;
> +import javax.swing.ListModel;
> +
> +import ptolemy.actor.gui.EditorFactory;
> +import ptolemy.kernel.util.IllegalActionException;
> +import ptolemy.kernel.util.NameDuplicationException;
> +import ptolemy.kernel.util.NamedObj;
> +
> +/**
> + * This class creates the editor pane for the DistributedCompositeActor. This
> + * pane allows the user to select the slave(s) that he/she wants the DCA to
> + * execute on.
> + */
> +public class DCAEditorPane extends EditorFactory {
> +	DistributedCompositeActor actor;
> +	private JFrame controllingFrame;
> +	private JList availableList;
> +	private JList usedList;
> +	// actionListener to handle all button actions
> +	private ActionListener listener = new ActionListener() {
> +		public void actionPerformed(ActionEvent ae) { // add the item to the
> +														// usedList and remove
> +														// it from the availList
> +			if (ae.getActionCommand().equals("add")) {
> +				int[] selectedIndices = availableList.getSelectedIndices();
> +				Object[] selectedVals = availableList.getSelectedValues();
> +				Vector usedNewData = new Vector();
> +				Vector availNewData = new Vector();
> +				ListModel availableModel = availableList.getModel();
> +				for (int i = 0; i < availableModel.getSize(); i++) {
> +					boolean remove = false;
> +					String s = (String) availableModel.getElementAt(i);
> +					for (int j = 0; j < selectedVals.length; j++) {
> +						if (!s.trim().equals("")
> +								&& s.equals((String) selectedVals[j])) {
> +							remove = true;
> +						}
> +					}
> +
> +					if (!remove) {
> +						availNewData.addElement(s);
> +					} else {
> +						usedNewData.addElement(s);
> +					}
> +				}
> +
> +				// add the existing data
> +				ListModel usedModel = usedList.getModel();
> +				for (int i = 0; i < usedModel.getSize(); i++) {
> +					String s = (String) usedModel.getElementAt(i);
> +					usedNewData.addElement(s);
> +				}
> +
> +				usedList.setListData(usedNewData);
> +				availableList.setListData(availNewData);
> +			} else if (ae.getActionCommand().equals("remove")) { // remove the
> +																	// item and
> +																	// add it to
> +																	// the
> +																	// availList
> +				int[] selectedIndices = usedList.getSelectedIndices();
> +				Object[] selectedVals = usedList.getSelectedValues();
> +				Vector usedNewData = new Vector();
> +				Vector availNewData = new Vector();
> +				ListModel usedModel = usedList.getModel();
> +				for (int i = 0; i < usedModel.getSize(); i++) {
> +					boolean remove = false;
> +					String s = (String) usedModel.getElementAt(i);
> +					for (int j = 0; j < selectedVals.length; j++) {
> +						if (!s.trim().equals("")
> +								&& s.equals((String) selectedVals[j])) {
> +							remove = true;
> +						}
> +					}
> +
> +					if (!remove) {
> +						usedNewData.addElement(s);
> +					} else {
> +						availNewData.addElement(s);
> +					}
> +				}
> +
> +				// add the existing data
> +				ListModel availModel = availableList.getModel();
> +				for (int i = 0; i < availModel.getSize(); i++) {
> +					String s = (String) availModel.getElementAt(i);
> +					// make sure there isn't a duplicate
> +					boolean dupe = false;
> +					for (int j = 0; j < availNewData.size(); j++) {
> +						if (s.trim().equals((String) availNewData.elementAt(j))) {
> +							dupe = true;
> +							break;
> +						}
> +					}
> +
> +					if (!dupe) {
> +						availNewData.addElement(s);
> +					}
> +				}
> +
> +				usedList.setListData(usedNewData);
> +				availableList.setListData(availNewData);
> +			} else if (ae.getActionCommand().equals("ok")) { // ok
> +				try {
> +					Iterator itt = actor.attributeList(
> +							DistributedServerAttribute.class).iterator();
> +					while (itt.hasNext()) { // remove all of the attributes then
> +											// add the new ones
> +						DistributedServerAttribute dsa = (DistributedServerAttribute) itt
> +								.next();
> +						dsa.setContainer(null);
> +					}
> +
> +					// get the data from the form fields and write it to the DCA
> +					// as
> +					// a DistributedServerAttribute
> +					ListModel usedModel = usedList.getModel();
> +					for (int i = 0; i < usedModel.getSize(); i++) { // get the
> +																	// data from
> +																	// the
> +																	// usedList,
> +																	// make sure
> +																	// we don't
> +																	// already
> +						// have a DSA for that endpoint, the write it to the
> +						// model
> +						String s = (String) usedModel.getElementAt(i);
> +						DistributedServerAttribute dsa = new DistributedServerAttribute(
> +								actor, "DistributedServerAttribute" + i);
> +						dsa.setExpression(s);
> +					}
> +				} catch (Exception e) {
> +					String msg = "Could not write the server attributes to the actor: "
> +							+ e.getMessage();
> +					JOptionPane.showMessageDialog(controllingFrame, msg,
> +							"alert", JOptionPane.ERROR_MESSAGE);
> +				}
> +				// close the frame
> +				controllingFrame.setVisible(false);
> +				controllingFrame.dispose();
> +			} else if (ae.getActionCommand().equals("cancel")) { // cancel
> +				controllingFrame.setVisible(false);
> +				controllingFrame.dispose();
> +			}
> +		}
> +	};
> +
> +	/**
> +	 * Construct a factory with the specified container and name.
> +	 * 
> +	 * @param container
> +	 *            The container.
> +	 * @param name
> +	 *            The name of the factory.
> +	 * @exception IllegalActionException
> +	 *                If the factory is not of an acceptable attribute for the
> +	 *                container.
> +	 * @exception NameDuplicationException
> +	 *                If the name coincides with an attribute already in the
> +	 *                container.
> +	 */
> +	public DCAEditorPane(NamedObj container, String name)
> +			throws IllegalActionException, NameDuplicationException {
> +		super(container, name);
> +		actor = (DistributedCompositeActor) container;
> +	}
> +
> +	/**
> +	 * create the editor
> +	 * 
> +	 * @param object
> +	 *            the object to create the editor for
> +	 * @param parent
> +	 *            the parent frame of this dialog
> +	 */
> +	public void createEditor(NamedObj object, java.awt.Frame parent) {
> +		try {
> +			// add a DistributedServerAttribute for each host in the config,
> +			// unless
> +			// this DCA already has at least one DSA, then don't add any
> +			Iterator itt = actor.attributeList(
> +					org.kepler.distributed.DistributedServerAttribute.class)
> +					.iterator();
> +			if (!itt.hasNext()) { // no preset atts so add all hosts
> +				print("no DistributedServerAttributes found in actor...adding them.");
> +				FileInputStream fis = new FileInputStream(new File(
> +						DistributedCompositeActor.CONFIG_FILE));
> +				byte[] data = new byte[fis.available()];
> +				fis.read(data);
> +				String hostList = new String(data);
> +				String[] hosts = hostList.split("\n");
> +				for (int i = 0; i < hosts.length; i++) { // add each host to the
> +															// DCA
> +					DistributedServerAttribute dsa = new DistributedServerAttribute(
> +							actor, "DistributedServer" + i);
> +					dsa.setExpression(hosts[i]);
> +					print("host: " + hosts[i]);
> +				}
> +			}
> +		} catch (Exception e) {
> +			e.printStackTrace();
> +			// throw new IllegalActionException("Error initializing DCA: " +
> +			// e.getMessage());
> +			print("Error initializaing DSA: " + e.getMessage());
> +		}
> +
> +		controllingFrame = new JFrame("Distributed Composite Actor Options");
> +		controllingFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
> +		// get the main controls
> +		JPanel contentPanel = (JPanel) createEditorPane(object);
> +		contentPanel.setBorder(BorderFactory.createEtchedBorder());
> +
> +		// add the contentPanel controllingFrame and add the ok and cancel
> +		// button
> +		// panel to the controllingFrame
> +		JPanel mainPanel = createMainPanel(contentPanel);
> +		controllingFrame.setContentPane(mainPanel);
> +		controllingFrame.pack();
> +		controllingFrame.setLocationRelativeTo(parent); // stay in the center
> +		controllingFrame.setVisible(true);
> +	}
> +
> +	/**
> +	 * Return a new panel to configure the distributed composite actor. this
> +	 * panel will allow the user to choose the slaves that the DCA should
> +	 * execute on.
> +	 * 
> +	 * @param object
> +	 *            The object to be configured.
> +	 * @return An instance of the PtolemyQuery class that is created with styles
> +	 *         according to the type given in each visible attribute.
> +	 */
> +	public Component createEditorPane(NamedObj object) {
> +		String[] usedListData = getUsedServers();
> +		Vector availListData = new Vector();
> +		try {
> +			availListData = getAvailServers(usedListData);
> +		} catch (Exception e) {
> +			print("Could not get available servers from the config file: "
> +					+ e.getMessage());
> +		}
> +		availableList = new JList();
> +		usedList = new JList();
> +		usedList.setListData(availListData);
> +		availableList.setListData(availListData);
> +		availableList.setFixedCellWidth(200);
> +		usedList.setFixedCellWidth(200);
> +		usedList.setListData(usedListData);
> +
> +		// start the layout
> +		JPanel panel = new JPanel();
> +		BoxLayout panelLayout = new BoxLayout(panel, BoxLayout.Y_AXIS);
> +		panel.setLayout(panelLayout);
> +
> +		// description panel
> +		JPanel descriptionLabelPanel = new JPanel();
> +		BoxLayout descriptionLabelPanelLayout = new BoxLayout(
> +				descriptionLabelPanel, BoxLayout.X_AXIS);
> +		descriptionLabelPanel.setLayout(descriptionLabelPanelLayout);
> +		JLabel descriptionLabel = new JLabel(
> +				"<html><p bgcolor=\"grey\">Choose the slaves you "
> +						+ "would like this DistributedCompositeActor (DCA) to execute on.  By default "
> +						+ "this DCA will attempt to distribute its execution to all slaves. If "
> +						+ "you would like to configure the available slaves, go to the Tools "
> +						+ "menu and select 'Distributed Computing Options'.</p></html>");
> +		descriptionLabel.setOpaque(true);
> +		descriptionLabel.setPreferredSize(new Dimension(500, 75));
> +		descriptionLabelPanel.setPreferredSize(new Dimension(520, 95));
> +		descriptionLabelPanel.add(Box.createHorizontalStrut(10));
> +		descriptionLabelPanel.add(descriptionLabel);
> +		descriptionLabelPanel.add(Box.createHorizontalStrut(10));
> +		panel.add(descriptionLabelPanel);
> +
> +		// create the slave chooser panel
> +		JPanel slaveChooserPanel = new JPanel();
> +		BoxLayout slaveBox = new BoxLayout(slaveChooserPanel, BoxLayout.X_AXIS);
> +		slaveChooserPanel.setLayout(slaveBox);
> +
> +		// the available side
> +		JPanel availablePanel = new JPanel();
> +		JLabel availableLabel = new JLabel("Available Slaves");
> +		JPanel availableLabelPanel = new JPanel();
> +		BoxLayout availableLabelLayout = new BoxLayout(availableLabelPanel,
> +				BoxLayout.X_AXIS);
> +		availableLabelPanel.setLayout(availableLabelLayout);
> +		availableLabelPanel.add(availableLabel);
> +		availableLabelPanel.add(Box.createHorizontalStrut(10));
> +		BoxLayout availableBox = new BoxLayout(availablePanel, BoxLayout.Y_AXIS);
> +		availablePanel.setLayout(availableBox);
> +		availablePanel.add(availableLabelPanel);
> +		JScrollPane availableScrollPane = new JScrollPane(availableList);
> +		availablePanel.add(availableScrollPane);
> +
> +		// the middle buttons
> +		JPanel middleButtonPanel = new JPanel();
> +		BoxLayout middleButtonBox = new BoxLayout(middleButtonPanel,
> +				BoxLayout.Y_AXIS);
> +		middleButtonPanel.setLayout(middleButtonBox);
> +		JButton addButton = new JButton("==>");
> +		addButton.setActionCommand("add");
> +		addButton.addActionListener(listener);
> +		middleButtonPanel.add(addButton);
> +		middleButtonPanel.add(Box.createVerticalStrut(25));
> +		JButton removeButton = new JButton("<==");
> +		removeButton.setActionCommand("remove");
> +		removeButton.addActionListener(listener);
> +		middleButtonPanel.add(removeButton);
> +
> +		// the slaves to be used panel
> +		JPanel usedPanel = new JPanel();
> +		JLabel usedLabel = new JLabel("Used Slaves");
> +		JPanel usedLabelPanel = new JPanel();
> +		BoxLayout usedLabelLayout = new BoxLayout(usedLabelPanel,
> +				BoxLayout.X_AXIS);
> +		usedLabelPanel.setLayout(usedLabelLayout);
> +		usedLabelPanel.add(usedLabel);
> +		usedLabelPanel.add(Box.createHorizontalStrut(10));
> +		BoxLayout usedBox = new BoxLayout(usedPanel, BoxLayout.Y_AXIS);
> +		usedPanel.setLayout(usedBox);
> +		usedPanel.add(usedLabelPanel);
> +		JScrollPane usedScrollPane = new JScrollPane(usedList);
> +		usedPanel.add(usedScrollPane);
> +
> +		// add to the slave chooser panel
> +		slaveChooserPanel.add(Box.createHorizontalStrut(80));
> +		slaveChooserPanel.add(availablePanel);
> +		slaveChooserPanel.add(Box.createHorizontalStrut(40));
> +		slaveChooserPanel.add(middleButtonPanel);
> +		slaveChooserPanel.add(Box.createHorizontalStrut(40));
> +		slaveChooserPanel.add(usedPanel);
> +		slaveChooserPanel.add(Box.createHorizontalStrut(80));
> +
> +		panel.add(Box.createVerticalStrut(10));
> +		panel.add(slaveChooserPanel);
> +		panel.add(Box.createVerticalStrut(10));
> +		return panel;
> +	}
> +
> +	/**
> +	 * creates the main panel with the ok and cancel buttons
> +	 */
> +	private JPanel createMainPanel(JPanel contentPanel) {
> +		JPanel mainPanel = new JPanel();
> +		BoxLayout mainPanelLayout = new BoxLayout(mainPanel, BoxLayout.Y_AXIS);
> +		mainPanel.setLayout(mainPanelLayout);
> +
> +		// create the button panel
> +		JButton okButton = new JButton("OK");
> +		okButton.setActionCommand("ok");
> +		okButton.addActionListener(listener);
> +		JButton cancelButton = new JButton("Cancel");
> +		cancelButton.setActionCommand("cancel");
> +		cancelButton.addActionListener(listener);
> +		JPanel buttonPanel = new JPanel();
> +		BoxLayout buttonPanelLayout = new BoxLayout(buttonPanel,
> +				BoxLayout.X_AXIS);
> +		buttonPanel.add(okButton);
> +		buttonPanel.add(Box.createHorizontalStrut(20));
> +		buttonPanel.add(cancelButton);
> +
> +		mainPanel.add(Box.createVerticalStrut(10));
> +		mainPanel.add(contentPanel);
> +		mainPanel.add(Box.createVerticalStrut(10));
> +		mainPanel.add(buttonPanel);
> +		return mainPanel;
> +	}
> +
> +	/**
> +	 * Get the used servers from the actor
> +	 */
> +	private String[] getUsedServers() {
> +		try {
> +			// populate the usedList from the DistributedServerAttributes in the
> +			// DCA
> +			Iterator itt = actor
> +					.attributeList(DistributedServerAttribute.class).iterator();
> +			String serverList = "";
> +			while (itt.hasNext()) {
> +				DistributedServerAttribute dsa = (DistributedServerAttribute) itt
> +						.next();
> +				String host = dsa.getExpression();
> +				serverList += host + "\n";
> +			}
> +
> +			String[] hosts = serverList.split("\n");
> +			return hosts;
> +		} catch (Exception e) {
> +			String msg = "Error reading config file: " + e.getMessage();
> +			e.printStackTrace();
> +			// JOptionPane.showMessageDialog(controllingFrame, msg, "alert",
> +			// JOptionPane.ERROR_MESSAGE);
> +			return null;
> +		}
> +	}
> +
> +	/**
> +	 * get the available servers from the config file
> +	 * 
> +	 * @param usedListData
> +	 *            the string array from the usedList. use this to make sure
> +	 *            there are no duplicates in the availList
> +	 */
> +	private Vector getAvailServers(String[] usedListData) throws IOException,
> +			FileNotFoundException {
> +		String configFile = DistributedCompositeActor.CONFIG_FILE;
> +		FileReader fr = new FileReader(new File(configFile));
> +		char[] c = new char[1024];
> +		int numread = fr.read(c, 0, 1024);
> +		String data = "";
> +		while (numread != -1) {
> +			data += new String(c, 0, numread);
> +			numread = fr.read(c, 0, 1024);
> +		}
> +
> +		String[] availList = data.split("\n");
> +		Vector nodupeData = new Vector();
> +		for (int i = 0; i < availList.length; i++) {
> +			String item = availList[i];
> +			boolean dupe = false;
> +			for (int j = 0; j < usedListData.length; j++) {
> +				if (usedListData[j].equals(item)) {
> +					dupe = true;
> +				}
> +			}
> +
> +			if (!dupe) {
> +				nodupeData.addElement(item);
> +			}
> +		}
> +
> +		return nodupeData;
> +	}
> +
> +	/**
> +	 * print a message to standard out
> +	 */
> +	private void print(String message) {
> +		DistributedLogger.print("DCAEditorPane: " + message,
> +				DistributedLogger.LOW);
> +	}
> +}
> 
> Added: trunk/src/org/kepler/distributed/DataToken.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/DataToken.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/DataToken.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,536 @@
> +//  Copyright (c) 2007, Regents of the University of California
> +//  All rights reserved.
> +//
> +//  Redistribution and use in source and binary forms, with or without
> +//  modification, are permitted provided that the following conditions are
> +//  met:
> +//
> +//    * Redistributions of source code must retain the above copyright notice,
> +//  this list of conditions and the following disclaimer.
> +//    * Redistributions in binary form must reproduce the above copyright
> +//  notice, this list of conditions and the following disclaimer in the
> +//  documentation and/or other materials provided with the distribution.
> +//    * Neither the name of the University of California, San Diego (UCSD) nor
> +//  the names of its contributors may be used to endorse or promote products
> +//  derived from this software without specific prior written permission.
> +//
> +//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
> +//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> +//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> +//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> +//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
> +//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
> +//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
> +//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
> +//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> +//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
> +//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +//
> +//
> +//  FILE
> +//  DataToken.java -
> +//     org.kepler.distributed.DataToken
> +//
> +//  CLASS HIERARCHY
> +//  java.lang.Object
> +//  |
> +//    +-ptolemy.data.Token
> +//        |
> +//        +-org.kepler.distributed.DataToken
> +//
> +//
> +//  PRINCIPAL AUTHOR
> +//  Lucas Gilbert, SDSC/UCSD
> +//
> +//
> +package org.kepler.distributed;
> +
> +import java.io.File;
> +import java.io.IOException;
> +import java.net.InetAddress;
> +import java.net.URI;
> +import java.rmi.Naming;
> +import java.rmi.NotBoundException;
> +import java.rmi.RemoteException;
> +import java.security.GeneralSecurityException;
> +import java.security.MessageDigest;
> +
> +import ptolemy.data.StringToken;
> +import ptolemy.util.StringUtilities;
> +import edu.sdsc.grid.io.FileFactory;
> +import edu.sdsc.grid.io.GeneralFile;
> +import edu.sdsc.grid.io.GeneralFileOutputStream;
> +import edu.sdsc.grid.io.GeneralRandomAccessFile;
> +import edu.sdsc.grid.io.local.LocalFile;
> +import edu.sdsc.grid.io.local.LocalFileOutputStream;
> +
> +/**
> + * '$Author: aschultz $' '$Date: 2008-10-29 15:00:02 -0700 (Wed, 29 Oct 2008)
> + * $' '$Revision: 16353 $'
> + * 
> + * @author berkley
> + * @created September 7, 2007
> + */
> +public class DataToken extends StringToken {
> +	// TODO StringToken maybe necessary due to the legacy actors which use
> +	// StringToken for files
> +
> +	final static int BUFFER_SIZE = 65536;
> +
> +	URI path;
> +
> +	/**
> +   */
> +	protected DistributedFileServer fileServer;
> +
> +	/**
> +   */
> +	protected GeneralRandomAccessFile file;
> +
> +	/**
> +   */
> +	protected String cookie;
> +
> +	/**
> +   */
> +	protected boolean connected = false;
> +
> +	String host;
> +	String port;
> +
> +	/**
> +	 * The length of the file, at time of connection.
> +	 */
> +	long length = -1;
> +
> +	static String HOST;
> +	static String PORT;
> +	static {
> +		// read config file, instead?
> +		try {
> +			byte[] ip = InetAddress.getLocalHost().getAddress();
> +			HOST = (ip[0] & 0xff) + "." + (ip[1] & 0xff) + "." + (ip[2] & 0xff)
> +					+ "." + (ip[3] & 0xff);
> +		} catch (java.net.UnknownHostException e) {
> +			// TODO
> +			e.printStackTrace();
> +		}
> +		// TODO different ports?
> +		PORT = "1099";
> +	}
> +
> +	/**
> +	 * A token that represents a file or data source.
> +	 * 
> +	 *@param path
> +	 *            Description of the Parameter
> +	 */
> +	/*
> +	 * public DataToken( String localPath ) { this(new File(path).toURI()); }
> +	 */
> +
> +	/**
> +	 * A token that represents a file or data source.
> +	 * 
> +	 *@param path
> +	 *            Description of the Parameter
> +	 */
> +	public DataToken(URI path) {
> +		super(path.toString());
> +
> +		if (path == null) {
> +			throw new NullPointerException("Path cannot be null");
> +		}
> +		this.path = path;
> +
> +		init();
> +	}
> +
> +	/**
> +	 * Finalizes the object by explicitly letting go of each of its internally
> +	 * held values.
> +	 * 
> +	 *@exception Throwable
> +	 *                Description of the Exception
> +	 */
> +	protected void finalize() throws Throwable {
> +		super.finalize();
> +	}
> +
> +	/**
> +	 * Make sure this data is accessible non-locally
> +	 */
> +	protected void init() {
> +		// TODO figure out how the static variables work in RMI. probably need
> +		// to do this.
> +		if (host == null) {
> +			host = HOST;
> +		}
> +		if (port == null) {
> +			port = PORT;
> +		}
> +	}
> +
> +	// ------------------------------------------------------------------------
> +	// Methods
> +	// ------------------------------------------------------------------------
> +	/**
> +	 *@return Description of the Return Value
> +	 */
> +	public Object clone() {
> +		DataToken token = new DataToken(path);
> +		if (connected) {
> +			token.connected = true;
> +		}
> +		return token;
> +	}
> +
> +	/**
> +	 * Sets the cookie attribute of the DataToken object
> +	 * 
> +	 *@param cookie
> +	 *            The new cookie value
> +	 */
> +	void setCookie(String cookie) {
> +		this.cookie = cookie;
> +	}
> +
> +	/**
> +	 * Gets the cookie attribute of the DataToken object
> +	 * 
> +	 *@return The cookie value
> +	 */
> +	String getCookie() {
> +		try {
> +			// TODO er what if they rewrite it?
> +			if (cookie == null) {
> +				cookie = edu.sdsc.grid.io.Base64.toString(getMD5());
> +			}
> +			// TODO just catch the exception?
> +		} catch (IOException e) {
> +			e.printStackTrace();
> +		}
> +		return cookie;
> +	}
> +
> +	// ------------------------------------------------------------------------
> +	// File stream methods
> +	// -----------------------------------------------------------------------
> +
> +	/**
> +	 * Read the read
> +	 * 
> +	 *@param buffer
> +	 *            Description of the Parameter
> +	 *@param seek
> +	 *            Description of the Parameter
> +	 *@param length
> +	 *            Description of the Parameter
> +	 *@return Description of the Return Value
> +	 *@exception RemoteException
> +	 *                Description of the Exception
> +	 *@exception IOException
> +	 *                Description of the Exception
> +	 */
> +	int read(byte[] buffer, long seek, int length) throws RemoteException,
> +			IOException {
> +		if (fileServer != null) {
> +			byte[] b = fileServer.read(cookie, seek, length);
> +			// can't read the normal way because of the rmi
> +			System.arraycopy(b, 0, buffer, 0, length);
> +			return length;
> +		} else if (file != null) {
> +			if (file.getFilePointer() != seek) {
> +				file.seek(seek);
> +			}
> +			return file.read(buffer, 0, length);
> +		} else {
> +			file = FileFactory.newRandomAccessFile(path, "r");
> +			if (seek != 0) {
> +				file.seek(seek);
> +			}
> +			return file.read(buffer, 0, length);
> +		}
> +	}
> +
> +	/**
> +	 *@return Description of the Return Value
> +	 *@exception RemoteException
> +	 *                Description of the Exception
> +	 *@exception IOException
> +	 *                Description of the Exception
> +	 */
> +	long length() throws RemoteException, IOException {
> +		print("HOST: " + HOST + "  host: " + host);
> +		print("fileServer: " + fileServer + "  file: " + file);
> +		print("path: " + path);
> +		if (fileServer != null) {
> +			return fileServer.length(cookie);
> +		} else if (file != null) {
> +			return file.length();
> +		} else {
> +			print("length() else");
> +			file = FileFactory.newRandomAccessFile(path, "r");
> +			return file.length();
> +		}
> +	}
> +
> +	/**
> +	 *@return Description of the Return Value
> +	 *@returns true if and only if makes a new connection to this file. Returns
> +	 *          false if already connected, or cannot connect for any other
> +	 *          reason.
> +	 */
> +	protected boolean connect() {
> +		String scheme = null;
> +		try {
> +			scheme = path.getScheme();
> +			if (connected) {
> +				return false;
> +			} else if (!host.equals(HOST)) {
> +				// TODO file:/ part?
> +				if (cookie == null) {
> +					return false;
> +				}
> +
> +				// TODO connection pool so only one connection to a node gets
> +				// made?
> +				fileServer = (DistributedFileServer) Naming.lookup("rmi://"
> +						+ host + "/SlaveControllerInstance");
> +			} else if (scheme.startsWith("rmi:")) {
> +				// TODO um this won't ever
> +				if (cookie == null) {
> +					return false;
> +				}
> +
> +				// TODO connection pool so only one connection to a node gets
> +				// made?
> +				fileServer = (DistributedFileServer) Naming.lookup(scheme
> +						.toString());
> +			}
> +
> +			// if successful
> +			return true;
> +		} catch (IOException e) {
> +			// TODO catch?
> +			e.printStackTrace();
> +		} catch (NotBoundException e) {
> +			// TODO catch?
> +			e.printStackTrace();
> +		}
> +		return false;
> +	}
> +
> +	/**
> +	 *@param localPath
> +	 *            Description of the Parameter
> +	 *@param overwrite
> +	 *            Description of the Parameter
> +	 *@return Description of the Return Value
> +	 *@exception IOException
> +	 *                Description of the Exception
> +	 */
> +	boolean saveLocalCopy(LocalFile localPath, boolean overwrite)
> +			throws IOException {
> +		print("saveLocal start " + localPath + " " + overwrite);
> +		if (!overwrite) {
> +			if (localPath.exists()) {
> +				return false;
> +			}
> +		}
> +
> +		print("past it");
> +		GeneralFileOutputStream out = new LocalFileOutputStream(localPath);
> +		byte[] buffer = new byte[BUFFER_SIZE];
> +
> +		int read = 0;
> +		long totalRead = 0;
> +		length = length();
> +		print("saveLocal " + length);
> +		while (totalRead + BUFFER_SIZE <= length) {
> +			read = read(buffer, totalRead, BUFFER_SIZE);
> +			totalRead += read;
> +			out.write(buffer, 0, read);
> +		}
> +		if (totalRead < length) {
> +			read = read(buffer, totalRead, (int) (length - totalRead));
> +			totalRead += read;
> +			out.write(buffer, 0, read);
> +		}
> +		out.close();
> +		print("saveLocal true");
> +		return true;
> +	}
> +
> +	/**
> +	 * Gets the mD5 attribute of the DataToken object
> +	 * 
> +	 *@return The mD5 value
> +	 *@exception IOException
> +	 *                Description of the Exception
> +	 */
> +	public byte[] getMD5() throws IOException {
> +		try {
> +			// need a new connection
> +			DataToken file = (DataToken) this.clone();
> +
> +			MessageDigest digest = MessageDigest.getInstance("MD5");
> +			byte[] buffer = new byte[BUFFER_SIZE];
> +			int l = 0;
> +			long totalRead = 0;
> +			long length = file.length();
> +
> +			do {
> +				l = file.read(buffer, totalRead, BUFFER_SIZE);
> +				totalRead += l;
> +				digest.update(buffer, 0, l);
> +			} while (length > totalRead);
> +			return digest.digest();
> +		} catch (GeneralSecurityException e) {
> +			SecurityException se = new SecurityException();
> +			se.initCause(e);
> +			throw se;
> +		}
> +	}
> +
> +	/**
> +	 * Compares the local data's MD5 with the <code>remoteMD5</code>.
> +	 * 
> +	 *@param remoteMD5
> +	 *            Description of the Parameter
> +	 *@return Description of the Return Value
> +	 *@exception IOException
> +	 *                Description of the Exception
> +	 */
> +	public boolean compareMD5(byte[] remoteMD5) throws IOException {
> +		byte[] local = getMD5();
> +		if (remoteMD5 != null && local != null) {
> +			if (remoteMD5.length == local.length) {
> +				// should always be true...
> +				for (int i = 0; i < local.length; i++) {
> +					// is this really the best way?
> +					if (remoteMD5[i] != local[i]) {
> +						return false;
> +					}
> +				}
> +				return true;
> +			}
> +		}
> +		return false;
> +	}
> +
> +	/**
> +	 *@exception IOException
> +	 *                Description of the Exception
> +	 */
> +	public void refresh() throws IOException {
> +		connected = false;
> +		connect();
> +	}
> +
> +	/**
> +	 * Gets the randomAccessFile attribute of the DataToken object
> +	 * 
> +	 *@return The randomAccessFile value
> +	 *@exception IOException
> +	 *                Description of the Exception
> +	 */
> +	GeneralRandomAccessFile getRandomAccessFile() throws IOException {
> +		print("getRandomAccessFile " + path + "   host: " + host + " HOST: "
> +				+ HOST);
> +		// if not local then save to temp
> +		// and return temp location
> +		if (!(path.getScheme().startsWith("file:") || host.equals(HOST))) {
> +			print("does not match");
> +			connect();
> +			print("file: " + path.toString() + " will be gotten from slave: "
> +					+ host);
> +			String fileName = path.toString().substring(
> +					path.toString().lastIndexOf("/"));
> +			String filePrefix = fileName
> +					.substring(1, fileName.lastIndexOf("."));
> +			String fileSuxfix = fileName.substring(fileName.lastIndexOf("."));
> +
> +			LocalFile temp = (LocalFile) LocalFile.createTempFile(filePrefix,
> +					fileSuxfix);
> +			print("temp file saved in local: " + temp);
> +
> +			// just overwrite any file that might be there
> +			if (!saveLocalCopy(temp, true)) {
> +				throw new IOException("Temporary local file already exists.");
> +			}
> +
> +			// reset file location to local
> +			path = temp.toURI();
> +			print("path " + path);
> +			File f = new File(path);
> +			file = FileFactory.newRandomAccessFile(path, "r");
> +			// file.close();
> +
> +			fileServer = null;
> +			return file;
> +		} else {
> +			print("else " + file + "  path: " + path);
> +			if (file != null) {
> +				return file;
> +			}
> +
> +			GeneralFile f = FileFactory.newFile(path);
> +			print("file created: " + f);
> +			GeneralRandomAccessFile file1 = FileFactory.newRandomAccessFile(f,
> +					"r");
> +			// file1.close();
> +			return file1;
> +		}
> +	}
> +
> +	// ------------------------------------------------------------------------
> +	// StringToken Methods
> +	// ------------------------------------------------------------------------
> +	/**
> +	 * Returns the value of this token as a string. If the token represents a
> +	 * file, the value returned will point to a local file path.
> +	 * 
> +	 *@return Description of the Return Value
> +	 */
> +	public String stringValue() {
> +		print("get string value from datatoken.");
> +		// If the file is remote, copy it to a temporary local location.
> +		try {
> +			// Make sure to move the file to the local system
> +			if (file == null) {
> +				if (getRandomAccessFile() == null) {
> +
> +				}
> +
> +			}
> +
> +			return path.toString();
> +		} catch (IOException e) {
> +			RuntimeException x = new RuntimeException();
> +			x.initCause(e);
> +			throw x;
> +		}
> +	}
> +
> +	/**
> +	 *@return Description of the Return Value
> +	 */
> +	public String toString() {
> +		print("DataToken toString...");
> +		if (isNil()) {
> +			return super.toString();
> +		}
> +		return "\"" + StringUtilities.escapeString(stringValue()) + "\"";
> +	}
> +
> +	/**
> +	 * print a message prepended with this class's name
> +	 * 
> +	 *@param message
> +	 *            Description of the Parameter
> +	 */
> +	private static void print(String message) {
> +		DistributedLogger.print("DataToken: " + message, DistributedLogger.LOW);
> +	}
> +}
> 
> Added: trunk/src/org/kepler/distributed/DistributedCompositeActor.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/DistributedCompositeActor.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/DistributedCompositeActor.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,783 @@
> +//  Copyright (c) 2007, Regents of the University of California
> +//  All rights reserved.
> +//
> +//  Redistribution and use in source and binary forms, with or without
> +//  modification, are permitted provided that the following conditions are
> +//  met:
> +//
> +//    * Redistributions of source code must retain the above copyright notice,
> +//  this list of conditions and the following disclaimer.
> +//    * Redistributions in binary form must reproduce the above copyright
> +//  notice, this list of conditions and the following disclaimer in the
> +//  documentation and/or other materials provided with the distribution.
> +//    * Neither the name of the University of California, San Diego (UCSD) nor
> +//  the names of its contributors may be used to endorse or promote products
> +//  derived from this software without specific prior written permission.
> +//
> +//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
> +//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> +//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> +//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> +//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
> +//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
> +//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
> +//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
> +//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> +//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
> +//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +//
> +//
> +//  FILE
> +//  DistributedCompositeActor.java  -
> +//      org.ecoinformatics.seek.distrib.DistributedCompositeActor
> +//
> +//  CLASS HIERARCHY
> +//  ptolemy.actor.lib.hoc.LifeCycleManager
> +//      |
> +//      +-org.ecoinformatics.seek.distrib.DistributedCompositeActor
> +//
> +//  PRINCIPAL AUTHOR
> +//  Lucas Gilbert, SDSC/UCSD
> +//
> +//
> +
> +/*
> + *   '$Author: aschultz $'
> + *   '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + *   '$Revision: 16353 $'
> + */
> +package org.kepler.distributed;
> +
> +import java.io.ByteArrayInputStream;
> +import java.io.IOException;
> +import java.net.MalformedURLException;
> +import java.net.URISyntaxException;
> +import java.net.URL;
> +import java.rmi.Remote;
> +import java.rmi.RemoteException;
> +import java.util.HashMap;
> +import java.util.Iterator;
> +import java.util.Map;
> +import java.util.Vector;
> +
> +import ptolemy.actor.IOPort;
> +import ptolemy.actor.Receiver;
> +import ptolemy.actor.TypedCompositeActor;
> +import ptolemy.actor.TypedIOPort;
> +import ptolemy.data.IntToken;
> +import ptolemy.data.Token;
> +import ptolemy.data.expr.Variable;
> +import ptolemy.kernel.CompositeEntity;
> +import ptolemy.kernel.util.Attribute;
> +import ptolemy.kernel.util.IllegalActionException;
> +import ptolemy.kernel.util.InternalErrorException;
> +import ptolemy.kernel.util.NameDuplicationException;
> +import ptolemy.kernel.util.Settable;
> +import ptolemy.kernel.util.Workspace;
> +
> +//////////////////////////////////////////////////////////////////////////
> +//// DistributedCompositeActor
> +
> +/**
> + * '$Author: aschultz $' '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + * '$Revision: 16353 $'
> + */
> +public class DistributedCompositeActor extends TypedCompositeActor implements
> +		Remote {
> +	private Slave currentSlave;
> +	private Vector threadVector = new Vector();
> +
> +	/**
> +	 * Construct an actor in the default workspace with no container and an
> +	 * empty string as its name. Add the actor to the workspace directory. You
> +	 * should set the local director or executive director before attempting to
> +	 * send data to the actor or to execute it. Increment the version number of
> +	 * the workspace.
> +	 */
> +	public DistributedCompositeActor() {
> +		super();
> +
> +		// By default, when exporting MoML, the class name is whatever
> +		// the Java class is, which in this case is DistributedCompositeActor.
> +		// In derived classes, however, we usually do not want to identify
> +		// the class name as that of the derived class, but rather want
> +		// to identify it as DistributedCompositeActor. This way, the MoML
> +		// that is exported does not depend on the presence of the
> +		// derived class Java definition. Thus, we force the class name
> +		// here to be DistributedCompositeActor.
> +		setClassName("org.kepler.distributed.DistributedCompositeActor");
> +	}
> +
> +	/**
> +	 * Construct a DistributedCompositeActor in the specified workspace with no
> +	 * container and an empty string as a name. You can then change the name
> +	 * with setName(). If the workspace argument is null, then use the default
> +	 * workspace. You should set the local director or executive director before
> +	 * attempting to send data to the actor or to execute it. Add the actor to
> +	 * the workspace directory. Increment the version number of the workspace.
> +	 * 
> +	 *@param workspace
> +	 *            The workspace that will list the actor.
> +	 */
> +	public DistributedCompositeActor(Workspace workspace) {
> +		super(workspace);
> +
> +		// By default, when exporting MoML, the class name is whatever
> +		// the Java class is, which in this case is DistributedCompositeActor.
> +		// In derived classes, however, we usually do not want to identify
> +		// the class name as that of the derived class, but rather want
> +		// to identify it as DistributedCompositeActor. This way, the MoML
> +		// that is exported does not depend on the presence of the
> +		// derived class Java definition. Thus, we force the class name
> +		// here to be DistributedCompositeActor.
> +		setClassName("org.kepler.distributed.DistributedCompositeActor");
> +	}
> +
> +	/**
> +	 * Construct a DistributedCompositeActor with a name and a container. The
> +	 * container argument must not be null, or a NullPointerException will be
> +	 * thrown. This actor will use the workspace of the container for
> +	 * synchronization and version counts. If the name argument is null, then
> +	 * the name is set to the empty string. Increment the version of the
> +	 * workspace. This actor will have no local director initially, and its
> +	 * executive director will be simply the director of the container.
> +	 * 
> +	 *@param container
> +	 *            The container.
> +	 *@param name
> +	 *            The name of this actor.
> +	 *@exception IllegalActionException
> +	 *                If the container is incompatible with this actor.
> +	 *@exception NameDuplicationException
> +	 *                If the name coincides with an actor already in the
> +	 *                container.
> +	 */
> +	public DistributedCompositeActor(CompositeEntity container, String name)
> +			throws IllegalActionException, NameDuplicationException {
> +		super(container, name);
> +
> +		// By default, when exporting MoML, the class name is whatever
> +		// the Java class is, which in this case is DistributedCompositeActor.
> +		// In derived classes, however, we usually do not want to identify
> +		// the class name as that of the derived class, but rather want
> +		// to identify it as DistributedCompositeActor. This way, the MoML
> +		// that is exported does not depend on the presence of the
> +		// derived class Java definition. Thus, we force the class name
> +		// here to be DistributedCompositeActor.
> +		setClassName("org.kepler.distributed.DistributedCompositeActor");
> +		initConfigDialog();
> +	}
> +
> +	/**
> +	 * create the configuration dialog for the DCA. This allows us to add
> +	 * configuration options for sending the execution from this DCA to a
> +	 * specific slave or slaves.
> +	 */
> +	private void initConfigDialog() throws IllegalActionException,
> +			NameDuplicationException {
> +		// enable the custom config dialog
> +		DCAEditorPane dcapane = new DCAEditorPane(this, "Editor Pane");
> +	}
> +
> +	// /////////////////////////////////////////////////////////////////
> +	// // public methods ////
> +
> +	/**
> +	 * Run a complete execution of the contained model. A complete execution
> +	 * consists of invocation of super.initialize(), repeated invocations of
> +	 * super.prefire(), super.fire(), and super.postfire(), followed by
> +	 * super.wrapup(). The invocations of prefire(), fire(), and postfire() are
> +	 * repeated until either the model indicates it is not ready to execute
> +	 * (prefire() returns false), or it requests a stop (postfire() returns
> +	 * false or stop() is called). Before running the complete execution, this
> +	 * method calls the director's transferInputs() method to read any available
> +	 * inputs. After running the complete execution, it calls transferOutputs().
> +	 * The subclass of this can set the
> +	 * <i>_isSubclassOfDistributedCompositeActor</i> to be true to call the fire
> +	 * method of the superclass of this.
> +	 * 
> +	 *@exception IllegalActionException
> +	 *                If there is no director, or if the director's action
> +	 *                methods throw it.
> +	 */
> +	public void fire() throws IllegalActionException {
> +		try {
> +			print("%%%%%%%%%%%%DCA firing%%%%%%%%%%%%%%%%");
> +			_readInputs(masterController, currentSlave);
> +			print("%%%%%%%%%%%%DCA fired%%%%%%%%%%%%%%%%");
> +			// waiting for tokens are sent out.
> +			print("waiting for all tokens are sent out.");
> +			Iterator ports = inputPortList().iterator();
> +
> +			// doesn't run in this while
> +			while (ports.hasNext()) {
> +				IOPort port = (IOPort) ports.next();
> +				String portName = port.getName();
> +
> +				print("checking port " + port.getName());
> +				if (port.getWidth() > 0) {
> +					while (port.hasToken(0)) {
> +						print("waiting for port which has tokens: "
> +								+ port.getName());
> +						// this.getExecutiveDirector().
> +
> +						Thread.currentThread().sleep(1000);
> +					}
> +
> +				}
> +			}
> +
> +			print("%%%%%%%%%%%%DCA check token finished%%%%%%%%%%%%%%%%");
> +		} catch (Exception e) {
> +			e.printStackTrace();
> +			throw new IllegalActionException("Error executing the "
> +					+ "DistributedCompositeActor: " + e.getMessage());
> +		}
> +	}
> +
> +	/**
> +	 * Initialize this actor, which in this case, does nothing. The
> +	 * initialization of the submodel is accomplished in fire(). The subclass of
> +	 * this can set the <i>_isSubclassOfDistributedCompositeActor</i> to be true
> +	 * to call the initialize method of the superclass of this.
> +	 * 
> +	 *@exception IllegalActionException
> +	 *                Not thrown in this base class, but declared so the
> +	 *                subclasses can throw it.
> +	 */
> +	public void initialize() throws IllegalActionException {
> +		try {
> +			java.io.File configFile = new java.io.File(CONFIG_FILE);
> +			// getParameter("distributed config file")
> +			print("config file exists: " + configFile.exists());
> +			print("config file path: " + configFile.getPath());
> +			URL fileURL = configFile.toURL();
> +			// look in the DCA to see if there are DistributedServerAttributes.
> +			// If there
> +			// are, use the hosts defined in those attributes to execute. If
> +			// not,
> +			// use the default host list from the config file.
> +			String hostList = "";
> +			boolean hasAtt = false;
> +			Iterator attlistitt = this.attributeList(
> +					DistributedServerAttribute.class).iterator();
> +			while (attlistitt.hasNext()) {
> +				hasAtt = true;
> +				DistributedServerAttribute att = (DistributedServerAttribute) attlistitt
> +						.next();
> +				print("att: " + att.getName());
> +				print("attexpr: " + att.getExpression());
> +				hostList += att.getExpression() + "\n";
> +			}
> +
> +			// try the top-level attributes
> +			// List attList = this.getContainer().attributeList();
> +			Iterator attIt = this.getContainer().attributeList().iterator();
> +			Vector newAttIt = new Vector();
> +			while (attIt.hasNext()) {
> +				Attribute att = (Attribute) attIt.next();
> +				// Parameter para = (Parameter)att;
> +				// System.out.println("att:"+att.exportMoML());
> +				// print("att in print:"+att.description());
> +				newAttIt.add(att.exportMoML());
> +			}
> +
> +			// try the types of input ports
> +			Iterator inputPortList = this.inputPortList().iterator();
> +			Map inputPortMap = new HashMap();
> +			while (inputPortList.hasNext()) {
> +				TypedIOPort inputPort = (TypedIOPort) inputPortList.next();
> +				String strInputName = inputPort.getName();
> +				String strInputType = inputPort.getType().toString();
> +				// Parameter para = (Parameter)att;
> +				// System.out.println("att:"+att.exportMoML());
> +				print("input :" + strInputName + " whose type is "
> +						+ strInputType);
> +				inputPortMap.put(strInputName, strInputType);
> +			}
> +
> +			if (hasAtt) { // use the attributes
> +				print("using DSA attributes for host selection.");
> +				print("hostList: " + hostList);
> +				byte[] b = hostList.getBytes();
> +				ByteArrayInputStream bais = new ByteArrayInputStream(b);
> +
> +				masterController = new MasterController(this, newAttIt,
> +						inputPortMap, bais);
> +			} else { // use the config file
> +				print("using config file for host selection.");
> +				// try the top-level attributes
> +				// List attList = this.getContainer().attributeList();
> +				// Iterator attIt =
> +				// this.getContainer().attributeList().iterator();
> +				// Vector newAttIt = new Vector();
> +				// //Map paraMap = new HashMap();
> +				// while(attIt.hasNext()){
> +				// Attribute att = (Attribute)attIt.next();
> +				// //Parameter para = (Parameter)att;
> +				// //System.out.println("att:"+att.exportMoML());
> +				// //print("att in print:"+att.description());
> +				// newAttIt.add(att.exportMoML());
> +				//        	       	
> +				// }
> +				// Vector parentParaVec = new Vector();
> +				// Map paraMap = new HashMap();
> +				// while(attIt.hasNext()){
> +				// Attribute att = (Attribute)attIt.next();
> +				// if(att instanceof Parameter){
> +				// print("para in print: "+att.description());
> +				// String para[] = {att.getClass().getName(), ((Parameter)
> +				// att).getExpression()};
> +				// print("para " + att.getName() + " in print: "+para);
> +				// paraMap.put(att.getName(), para);
> +				// }else{
> +				// //Parameter para = (Parameter)att;
> +				// //System.out.println("att:"+att.exportMoML());
> +				// print("att in print:"+att.description());
> +				// newAttIt.add(att.exportMoML());
> +				// }
> +				//        	       	
> +				// }
> +				masterController = new MasterController(this, newAttIt,
> +						inputPortMap, fileURL.openStream());
> +			}
> +
> +			print("finished the initiation of MasterController");
> +
> +			// put the consumption rate param on each input port
> +			/*
> +			 * Iterator inputPortItt = this.inputPortList().iterator();
> +			 * while(inputPortItt.hasNext()) { IOPort iop =
> +			 * (IOPort)inputPortItt.next(); int numSlaves =
> +			 * masterController.getNumberOfSlaves(); Parameter
> +			 * tokenConsumptionRate =
> +			 * (Parameter)iop.getAttribute("tokenConsumptionRate");
> +			 * if(tokenConsumptionRate == null) { tokenConsumptionRate = new
> +			 * Parameter(iop, "tokenConsumptionRate"); }
> +			 * tokenConsumptionRate.setExpression(numSlaves + "");
> +			 * print("ConsumptionRate Set to: " + numSlaves + " on port " +
> +			 * iop.getName()); }
> +			 */
> +		} catch (MalformedURLException e) {
> +			IllegalActionException x = new IllegalActionException(
> +					"URL for distributed config file error");
> +			x.initCause(e);
> +			throw x;
> +		} catch (URISyntaxException e) {
> +			IllegalActionException x = new IllegalActionException(
> +					"URI for distributed config file error");
> +			x.initCause(e);
> +			throw x;
> +		} catch (RemoteException e) {
> +			IllegalActionException x = new IllegalActionException(
> +					"Remote connection in distributed config file error: "
> +							+ e.getMessage());
> +			x.initCause(e);
> +			e.printStackTrace();
> +			throw x;
> +		} catch (IOException e) {
> +			IllegalActionException x = new IllegalActionException(
> +					"IOException for distributed config file error");
> +			x.initCause(e);
> +			throw x;
> +		} catch (Exception e) {
> +			IllegalActionException x = new IllegalActionException(
> +					"Exception for distributed config file error: "
> +							+ e.getMessage());
> +			x.initCause(e);
> +			e.printStackTrace();
> +			throw x;
> +		}
> +
> +		if ((masterController == null) || !masterController.isConnected()) {
> +			throw new IllegalActionException(
> +					"Failed to connect to remote system for distributed execution");
> +		}
> +
> +		print("begin port processing in initialization");
> +		Iterator ports = outputPortList().iterator();
> +
> +		while (ports.hasNext()) {
> +			TypedIOPort port = (TypedIOPort) ports.next();
> +
> +			// Ensure that the production rate is one.
> +			// TODO: This may not be right if there is no
> +			// actual source of data for this port (e.g. no
> +			// SetVariable actor).
> +			Variable rate = (Variable) port.getAttribute("tokenProductionRate");
> +
> +			if (rate == null) {
> +				try {
> +					rate = new Variable(port, "tokenProductionRate");
> +				} catch (NameDuplicationException e) {
> +					throw new InternalErrorException(e);
> +				}
> +			}
> +
> +			rate.setToken(new IntToken(1));
> +
> +			String portName = port.getName();
> +		}
> +
> +		print("finished port processing in initialization");
> +	}
> +
> +	/**
> +	 * Return true, indicating that execution can continue. The subclass of this
> +	 * can set the <i>_isSubclassOfDistributedCompositeActor</i> to be true to
> +	 * call the postfire method of the superclass of this.
> +	 * 
> +	 *@return Description of the Return Value
> +	 *@exception IllegalActionException
> +	 *                Not thrown in this base class, but declared so the
> +	 *                subclasses can throw it.
> +	 */
> +	public boolean postfire() throws IllegalActionException {
> +
> +		print("calling postfire()");
> +		// tell the master we're done executing the wf
> +		try {
> +			print("Waiting for current slaves to finish execution before finishing postfire()");
> +			for (int i = 0; i < threadVector.size(); i++) {
> +				ExecuteModelThread emt = (ExecuteModelThread) threadVector
> +						.elementAt(i);
> +				while (!emt.done) {
> +					// print("$$$$$$$$$$$$$$ Waiting for threads to finish before wrapping up");
> +					Thread.currentThread().sleep(1000);
> +					// block here until all threads are done
> +					// we don't want to complete wrapup until all current
> +					// threads finish
> +				}
> +			}
> +		} catch (Exception e) {
> +			throw new IllegalActionException(
> +					"Could not release slave.  You may "
> +							+ "want to do this manually. : " + e.getMessage());
> +		}
> +		return true;
> +	}
> +
> +	/**
> +	 * Return true, indicating that this actor is always ready to fire.
> +	 * 
> +	 *@return Description of the Return Value
> +	 *@exception IllegalActionException
> +	 *                Not thrown in this base class, but declared so the
> +	 *                subclasses can throw it.
> +	 */
> +	public boolean prefire() throws IllegalActionException {
> +		print("waiting in prefire");
> +		currentSlave = masterController.getSlave(); // block here if there is no
> +													// slave available
> +		print("done waiting in prefire");
> +		return true;
> +	}
> +
> +	/**
> +	 * Override the base class to set type constraints between the output ports
> +	 * and parameters of this actor whose name matches the output port. If there
> +	 * is no such parameter, then create an instance of Variable with a matching
> +	 * name and set up the type constraints to that instance. The type of the
> +	 * output port is constrained to be at least that of the parameter or
> +	 * variable.
> +	 * 
> +	 *@exception IllegalActionException
> +	 *                If there is no director, or if the director's
> +	 *                preinitialize() method throws it, or if this actor is not
> +	 *                opaque.
> +	 */
> +	public void preinitialize() throws IllegalActionException {
> +	}
> +
> +	/**
> +	 * Override the base class to release the slaves
> +	 * 
> +	 *@exception IllegalActionException
> +	 *                Not thrown in this base class, but declared so the
> +	 *                subclasses can throw it.
> +	 */
> +	public void wrapup() throws IllegalActionException {
> +		print("calling wrapup()");
> +		// tell the master we're done executing the wf
> +		try {
> +			/*
> +			 * print("Waiting for current slaves to finish execution before finishing wrapup()"
> +			 * ); for(int i=0; i<threadVector.size(); i++) { ExecuteModelThread
> +			 * emt = (ExecuteModelThread)threadVector.elementAt(i);
> +			 * while(!emt.done) {//print(
> +			 * "$$$$$$$$$$$$$$ Waiting for threads to finish before wrapping up"
> +			 * ); Thread.currentThread().sleep(1000); //block here until all
> +			 * threads are done //we don't want to complete wrapup until all
> +			 * current threads finish } }
> +			 */
> +
> +			masterController.done();
> +		} catch (Exception e) {
> +			throw new IllegalActionException(
> +					"Could not release slave.  You may "
> +							+ "want to do this manually. : " + e.getMessage());
> +		}
> +	}
> +
> +	// /////////////////////////////////////////////////////////////////
> +	// // protected methods ////
> +
> +	/**
> +	 * Iterate over input ports and read any available values into the
> +	 * referenced model parameters.
> +	 * 
> +	 *@param master
> +	 *            The distributed connection manager.
> +	 *@exception IllegalActionException
> +	 *                If reading the ports or setting the parameters causes it.
> +	 *@exception RemoteException
> +	 *                Description of the Exception
> +	 *@exception IOException
> +	 *                Description of the Exception
> +	 */
> +	protected void _readInputs(MasterController master, Slave slave)
> +			throws IllegalActionException, RemoteException, IOException,
> +			Exception {
> +		print("Reading Inputs...");
> +		// NOTE: This is an essentially exact copy of the code in
> +		// ModelReference,
> +		// but this class and that one can't easily share a common base class.
> +
> +		Iterator ports = inputPortList().iterator();
> +
> +		while (ports.hasNext()) {
> +			IOPort port = (IOPort) ports.next();
> +
> +			if (slave == null) {
> +				print("SLAVE IS NULL");
> +			}
> +
> +			print("reading input from port: " + port + " sending to slave "
> +					+ slave.toString());
> +
> +			while ((port.getWidth() > 0) && port.hasToken(0)) {
> +				print("port " + port.getName() + " has token");
> +				try {
> +					Token token = port.get(0);
> +					// TODO be careful if file pointer token
> +					print("_readInputs getting token from port and putting token to the master: "
> +							+ token);
> +
> +					// put the token to the specific port on the specific slave
> +					master.put(slave, new Token[] { token }, port.getName());
> +				} catch (Exception e) {
> +					e.printStackTrace();
> +					print("port:" + port.getName() + " hasToken?"
> +							+ port.hasToken(0));
> +					break;
> +				}
> +			}
> +		}
> +		// tell the master we're ready to execute
> +		ExecuteModelThread emt = new ExecuteModelThread(master, slave);
> +		threadVector.addElement(emt);
> +		emt.start();
> +		// master.readyToRun(slave);
> +	}
> +
> +	/**
> +	 * Iterate over output ports and read any available values from the
> +	 * referenced model parameters and produce them on the outputs.
> +	 * 
> +	 *@exception IllegalActionException
> +	 *                If reading the parameters or writing to the ports causes
> +	 *                it.
> +	 */
> +	protected void _writeOutputs(Slave slave) throws IllegalActionException {
> +		print("_writeOutputs");
> +		Iterator ports = outputPortList().iterator();
> +
> +		// doesn't run in this while
> +		while (ports.hasNext()) {
> +			IOPort port = (IOPort) ports.next();
> +			String portName = port.getName();
> +
> +			print("writing from port " + port.getName());
> +			if (port.getWidth() > 0) {
> +				Attribute attribute = getAttribute(portName);
> +
> +				// Use the token directly rather than a string if possible.
> +				if (attribute instanceof Variable) {
> +					// TODO which? how many?
> +					try {
> +						print("_writeOutputs masterController.get variable");
> +						// get the token from the specific slave on the specific
> +						// port
> +						Token[] temp = masterController.get(slave, portName);
> +
> +						if (temp == null) {
> +							return;
> +						}
> +						// send the data on it's way
> +						port.send(0, temp, temp.length);
> +					} catch (Exception e) {
> +						e.printStackTrace();
> +						throw new IllegalActionException(
> +								"RMI error while getting data: "
> +										+ e.getMessage());
> +					}
> +				} else if (attribute instanceof Settable) {
> +					try {
> +						print("_writeOutputs masterController.get settable");
> +						// get the token from the specific slave on the specific
> +						// port
> +						Token[] temp = masterController.get(slave, portName);
> +
> +						if (temp == null) {
> +							return;
> +						}
> +						// send the data on it's way
> +						port.send(0, temp, temp.length);
> +					} catch (Exception e) {
> +						e.printStackTrace();
> +						throw new IllegalActionException(
> +								"RMI error while getting data: "
> +										+ e.getMessage());
> +					}
> +				} else {
> +					try {
> +						print("_writeOutputs masterController.get other");
> +						// get the token from the specific slave on the specific
> +						// port
> +						Token[] temp = masterController.get(slave, portName);
> +						if (temp == null) {
> +							return;
> +						}
> +						print("get token from slave: ");
> +						// Token.toString() is called when temp[i] is called. So
> +						// DataToken.toString() is called which call
> +						// DataToken.stringValue().
> +						for (int i = 0; i < temp.length; i++) {
> +							print("token " + i + ": " + temp[i]);
> +						}
> +						Receiver[][] localReceivers = port.getInsideReceivers();
> +						for (int t = 0; t < localReceivers.length; t++) {
> +							for (int j = 0; j < localReceivers[t].length; j++) {
> +								print("input port:"
> +										+ t
> +										+ "."
> +										+ j
> +										+ ":"
> +										+ localReceivers[t][j].getContainer()
> +												.getFullName());
> +
> +							}
> +						}
> +
> +						Receiver[][] localReceivers2 = port
> +								.getRemoteReceivers();
> +						for (int t = 0; t < localReceivers2.length; t++) {
> +							for (int j = 0; j < localReceivers2[t].length; j++) {
> +								print("remote input port:"
> +										+ t
> +										+ "."
> +										+ j
> +										+ ":"
> +										+ localReceivers2[t][j].getContainer()
> +												.getFullName());
> +
> +							}
> +						}
> +
> +						// send the data on it's way
> +						// port.send(0, temp, temp.length);
> +						port.broadcast(temp, temp.length);
> +
> +						print("finish token sending");
> +					} catch (Exception e) {
> +						e.printStackTrace();
> +						// throw new
> +						// IllegalActionException("RMI error while getting data: "
> +						// + e.getMessage());
> +						print("RMI error finish while getting data");
> +					}
> +				}
> +			}
> +		}
> +		print("Done writing outputs");
> +	}
> +
> +	/**
> +	 * print a message with the name of this class prepended
> +	 */
> +	private void print(String message) {
> +		DistributedLogger.print("DistributedCompositeActor: " + message,
> +				DistributedLogger.HIGH);
> +	}
> +
> +	// ///////////////////////////////////////////////////////////////////
> +	// // protected variables ////
> +
> +	/** Description of the Field */
> +	protected static MasterController masterController;
> +	public static String CONFIG_FILE = "master-slave/resources/system.properties/DistributedKepler.config";
> +	public static String USER_CONFIG_FILE = "master-slave/resources/system.properties/DistributedKeplerUser.config";
> +
> +	// ////////////////////////////////////////////////////////////////////
> +	// // private classes /////
> +	/**
> +	 * a thread to do the execution
> +	 */
> +	private class ExecuteModelThread extends Thread {
> +		MasterController master;
> +		Slave slave;
> +		public boolean done = false;
> +
> +		/**
> +		 * constructor
> +		 */
> +		public ExecuteModelThread(MasterController mc, Slave slave) {
> +			this.slave = slave;
> +			this.master = mc;
> +		}
> +
> +		/**
> +		 * run this when the thread is executed
> +		 */
> +		public void run() {
> +			try {
> +				// Make sure that change requests are not executed when
> +				// requested,
> +				// but rather only executed when executeChangeRequests() is
> +				// called.
> +				setDeferringChangeRequests(true);
> +
> +				// _readInputs(master, slave); //read inputs and execute
> +				master.readyToRun(slave); // block on execution
> +				print("begin to write output at ExecuteModelThread.");
> +				_writeOutputs(slave); // write the outputs
> +				print("write output finished at ExecuteModelThread.");
> +				master.releaseSlave(slave); // release the slave
> +				print("releaseSlave finished at ExecuteModelThread.");
> +				print("waiting for all tokens are sent out at ExecuteModelThread.");
> +				Iterator ports = inputPortList().iterator();
> +
> +				// doesn't run in this while
> +				while (ports.hasNext()) {
> +					IOPort port = (IOPort) ports.next();
> +					String portName = port.getName();
> +
> +					print("checking port " + port.getName()
> +							+ " at ExecuteModelThread.");
> +					if (port.getWidth() > 0) {
> +						while (port.hasToken(0)) {
> +							print("waiting at ExecuteModelThread for port which has tokens: "
> +									+ port.getName());
> +							Thread.currentThread().sleep(1000);
> +						}
> +
> +					}
> +				}
> +			} catch (Exception e) {
> +				print("Error running ExecuteModelThread: " + e.getMessage());
> +				e.printStackTrace();
> +			}
> +			done = true;
> +		}
> +	}
> +}
> 
> Added: trunk/src/org/kepler/distributed/DistributedConfigAction.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/DistributedConfigAction.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/DistributedConfigAction.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,116 @@
> +/**
> + *    '$RCSfile$'
> + *
> + *     '$Author: aschultz $'
> + *       '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + *   '$Revision: 16353 $'
> + *
> + *  For Details: http://kepler.ecoinformatics.org
> + *
> + * Copyright (c) 2004 The Regents of the University of California.
> + * All rights reserved.
> + *
> + * Permission is hereby granted, without written agreement and without
> + * license or royalty fees, to use, copy, modify, and distribute this
> + * software and its documentation for any purpose, provided that the
> + * above copyright notice and the following two paragraphs appear in
> + * all copies of this software.
> + *
> + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
> + * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
> + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
> + * IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY
> + * OF SUCH DAMAGE.
> + *
> + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
> + * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY
> + * OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
> + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
> + */
> +
> +package org.kepler.distributed;
> +
> +import java.awt.event.ActionEvent;
> +
> +import javax.swing.Action;
> +import javax.swing.ImageIcon;
> +import javax.swing.KeyStroke;
> +
> +import org.apache.commons.logging.Log;
> +import org.apache.commons.logging.LogFactory;
> +
> +import org.kepler.gui.TabbedDialog;
> +import org.kepler.gui.ActorDialogAction;
> +
> +import ptolemy.actor.gui.TableauFrame;
> +import ptolemy.kernel.util.StaticResources;
> +import ptolemy.vergil.toolbox.FigureAction;
> +import diva.gui.GUIUtilities;
> +
> +/**
> + * This action displays the dialog to choose options for distributed computing.
> + * 
> + *@author Chad Berkley
> + *@created 9/25/2007
> + */
> +public class DistributedConfigAction extends FigureAction {
> +
> +	// ////////////////////////////////////////////////////////////////////////////
> +	// LOCALIZABLE RESOURCES - NOTE that these default values are later
> +	// overridden by values from the uiDisplayText resourcebundle file
> +	// ////////////////////////////////////////////////////////////////////////////
> +
> +	private static String DISPLAY_NAME = StaticResources.getDisplayString(
> +			"actions.actor.displayName", "Distributed Computing Options");
> +	private static String TOOLTIP = StaticResources.getDisplayString(
> +			"actions.actor.tooltip",
> +			"Set options and choose slaves for distributed computing.");
> +	private static ImageIcon LARGE_ICON = null;
> +	private static KeyStroke ACCELERATOR_KEY = null;
> +
> +	/**
> +	 * Constructor
> +	 * 
> +	 * @param parent
> +	 *            the "frame" (derived from ptolemy.gui.Top) where the menu is
> +	 *            being added.
> +	 */
> +	public DistributedConfigAction(TableauFrame parent) {
> +		super("");
> +		if (parent == null) {
> +			IllegalArgumentException iae = new IllegalArgumentException(
> +					"ImportArchiveAction constructor received NULL argument for TableauFrame");
> +			iae.fillInStackTrace();
> +			throw iae;
> +		}
> +		this.parent = parent;
> +
> +		this.putValue(Action.NAME, DISPLAY_NAME);
> +		this.putValue(GUIUtilities.LARGE_ICON, LARGE_ICON);
> +		this.putValue("tooltip", TOOLTIP);
> +		this.putValue(GUIUtilities.ACCELERATOR_KEY, ACCELERATOR_KEY);
> +	}
> +
> +	/**
> +	 * Invoked when an action occurs.
> +	 * 
> +	 *@param e
> +	 *            ActionEvent
> +	 */
> +	public void actionPerformed(ActionEvent e) {
> +		// must call this first...
> +		super.actionPerformed(e);
> +		// ...before calling this:
> +		DistributedConfigDialog.createAndShowGUI();
> +	}
> +
> +	private TableauFrame parent;
> +	private TabbedDialog actorDialog;
> +
> +	private static final Log log = LogFactory.getLog("UI."
> +			+ ActorDialogAction.class.getName());
> +
> +	private static final boolean isDebugging = log.isDebugEnabled();
> +}
> 
> Added: trunk/src/org/kepler/distributed/DistributedConfigDialog.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/DistributedConfigDialog.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/DistributedConfigDialog.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,762 @@
> +/**
> + * For Details: http://kepler.ecoinformatics.org
> + *
> + *  '$RCSfile$'
> + *  Copyright: 2000 Regents of the University of California and the
> + *              National Center for Ecological Analysis and Synthesis
> + *    Authors: @authors@
> + *    Release: @release@
> + *
> + *   '$Author: aschultz $'
> + *     '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + * '$Revision: 16353 $'
> + *
> + * Copyright (c) 2003 The Regents of the University of California.
> + * All rights reserved.
> + *
> + * Permission is hereby granted, without written agreement and without
> + * license or royalty fees, to use, copy, modify, and distribute this
> + * software and its documentation for any purpose, provided that the
> + * above copyright notice and the following two paragraphs appear in
> + * all copies of this software.
> + *
> + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
> + * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
> + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
> + * IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY
> + * OF SUCH DAMAGE.
> + *
> + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
> + * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY
> + * OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
> + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
> + */
> +
> +package org.kepler.distributed;
> +
> +import java.awt.BorderLayout;
> +import java.awt.Dimension;
> +import java.awt.event.ActionEvent;
> +import java.awt.event.ActionListener;
> +import java.awt.event.WindowAdapter;
> +import java.awt.event.WindowEvent;
> +import java.io.ByteArrayOutputStream;
> +import java.io.File;
> +import java.io.FileInputStream;
> +import java.io.FileNotFoundException;
> +import java.io.FileOutputStream;
> +import java.io.FileReader;
> +import java.io.FileWriter;
> +import java.io.IOException;
> +import java.util.Vector;
> +
> +import javax.crypto.Cipher;
> +import javax.crypto.SecretKey;
> +import javax.crypto.SecretKeyFactory;
> +import javax.crypto.spec.PBEKeySpec;
> +import javax.crypto.spec.PBEParameterSpec;
> +import javax.swing.BorderFactory;
> +import javax.swing.Box;
> +import javax.swing.BoxLayout;
> +import javax.swing.JButton;
> +import javax.swing.JComboBox;
> +import javax.swing.JFrame;
> +import javax.swing.JLabel;
> +import javax.swing.JList;
> +import javax.swing.JOptionPane;
> +import javax.swing.JPanel;
> +import javax.swing.JPasswordField;
> +import javax.swing.JScrollPane;
> +import javax.swing.JTextField;
> +import javax.swing.ListModel;
> +import javax.swing.UIManager;
> +
> +import org.ecoinformatics.ecogrid.client.RegistryServiceClient;
> +import org.ecoinformatics.ecogrid.registry.stub.RegistryEntryType;
> +import org.kepler.gui.ProgressMonitorSwingWorker;
> +import org.kepler.objectmanager.repository.EcogridRepository;
> +import org.kepler.objectmanager.repository.Repository;
> +import org.kepler.objectmanager.repository.RepositoryManager;
> +import org.kepler.objectmanager.repository.EcogridRepository.RegistryClientContainer;
> +
> +/**
> + * A dialog used for setting the options and choosing slave controllers for
> + * distributed computing
> + */
> +public class DistributedConfigDialog extends JPanel implements ActionListener {
> +	// password encryption values
> +	private static String PASSWORD = "0asd09aoiun.35lk6nlk34234!#ax";
> +	private static byte[] SALT = { (byte) 0xc7, (byte) 0x73, (byte) 0x21,
> +			(byte) 0x8c, (byte) 0x7e, (byte) 0xc8, (byte) 0xee, (byte) 0x99 };
> +	private static int ITERATIONCOUNT = 20;
> +	private static byte fileDelim = ','; // TODO: Even reserved characters like
> +											// comma can go in attribute
> +	// values if you escape them, this isn't entirely safe.
> +
> +	private static JFrame controllingFrame; // The Frame of dialog
> +	private String configFile;
> +	private JTextField usernameField = new JTextField("", 15);
> +	private JLabel usernameLabel = new JLabel("Username");
> +	private JPasswordField passwordField = new JPasswordField("", 15);
> +	private JLabel passwordLabel = new JLabel("Password");
> +	private JComboBox domainField;
> +	private JLabel domainLabel = new JLabel("Organization");
> +	private JList availableList;
> +	private JList usedList;
> +	private ProgressMonitorSwingWorker pmworker = new ProgressMonitorSwingWorker(
> +			"Updating remote node list.");
> +
> +	public DistributedConfigDialog() {
> +		// get the file to read/write config info to
> +		configFile = DistributedCompositeActor.CONFIG_FILE;
> +
> +		// put together the dialog
> +		JPanel outerPanel = new JPanel();
> +		BoxLayout outerBox = new BoxLayout(outerPanel, BoxLayout.Y_AXIS);
> +		outerPanel.setLayout(outerBox);
> +
> +		JPanel descriptionLabelPanel = new JPanel();
> +		BoxLayout descriptionLabelPanelLayout = new BoxLayout(
> +				descriptionLabelPanel, BoxLayout.X_AXIS);
> +		descriptionLabelPanel.setLayout(descriptionLabelPanelLayout);
> +		JLabel descriptionLabel = new JLabel(
> +				"<html><p>Enter the username that "
> +						+ "you want to use to login to remote Kepler nodes then choose the "
> +						+ "nodes you want to use for your remote computation by selecting the "
> +						+ "available slaves and clicking the '==>' button to add them "
> +						+ "to the 'Used Slaves' list.  You can also click the 'Add Manually' "
> +						+ "button to add a slave manually if it is not registered on with the "
> +						+ "EarthGrid (i.e. nodes on a local network).</p></html>");
> +		descriptionLabel.setPreferredSize(new Dimension(500, 75));
> +		descriptionLabel.setOpaque(true);
> +		descriptionLabelPanel.setPreferredSize(new Dimension(520, 95));
> +		descriptionLabelPanel.add(Box.createHorizontalStrut(10));
> +		descriptionLabelPanel.add(descriptionLabel);
> +		descriptionLabelPanel.add(Box.createHorizontalStrut(10));
> +
> +		// create the login panel
> +		JPanel loginPanel = new JPanel();
> +		BoxLayout loginPanelLayout = new BoxLayout(loginPanel, BoxLayout.Y_AXIS);
> +		loginPanel.setLayout(loginPanelLayout);
> +		JPanel usernamePanel = new JPanel();
> +		BoxLayout usernamePanelLayout = new BoxLayout(usernamePanel,
> +				BoxLayout.X_AXIS);
> +		usernamePanel.setLayout(usernamePanelLayout);
> +		usernamePanel.add(usernameLabel);
> +		usernamePanel.add(Box.createHorizontalStrut(25));
> +		usernamePanel.add(usernameField);
> +		usernamePanel.add(Box.createHorizontalStrut(200));
> +		loginPanel.add(Box.createVerticalStrut(10));
> +		loginPanel.add(usernamePanel);
> +
> +		// domain panel
> +		JPanel domainPanel = new JPanel();
> +		BoxLayout domainPanelLayout = new BoxLayout(domainPanel,
> +				BoxLayout.X_AXIS);
> +		domainPanel.setLayout(domainPanelLayout);
> +		domainField = new JComboBox();
> +		domainField.addItem("NCEAS");
> +		domainField.addItem("LTER");
> +		domainField.addItem("PISCO");
> +		domainField.addItem("SDSC");
> +		domainField.addItem("SANParks");
> +		domainField.addItem("unaffiliated");
> +		domainPanel.add(domainLabel);
> +		domainPanel.add(Box.createHorizontalStrut(5));
> +		domainPanel.add(domainField);
> +		domainPanel.add(Box.createHorizontalStrut(200));
> +		loginPanel.add(Box.createVerticalStrut(5));
> +		loginPanel.add(domainPanel);
> +
> +		// password panel
> +		JPanel passwordPanel = new JPanel();
> +		BoxLayout passwordPanelLayout = new BoxLayout(passwordPanel,
> +				BoxLayout.X_AXIS);
> +		passwordPanel.setLayout(passwordPanelLayout);
> +		passwordField.setEchoChar('*');
> +		passwordPanel.add(passwordLabel);
> +		passwordPanel.add(Box.createHorizontalStrut(27));
> +		passwordPanel.add(passwordField);
> +		passwordPanel.add(Box.createHorizontalStrut(200));
> +		loginPanel.add(Box.createVerticalStrut(5));
> +		loginPanel.add(passwordPanel);
> +
> +		// create the slave chooser panel
> +		JPanel slaveChooserPanel = new JPanel();
> +		BoxLayout slaveBox = new BoxLayout(slaveChooserPanel, BoxLayout.X_AXIS);
> +		slaveChooserPanel.setLayout(slaveBox);
> +
> +		// the available side
> +		JPanel availablePanel = new JPanel();
> +		JLabel availableLabel = new JLabel("Available Slaves");
> +		JPanel availableLabelPanel = new JPanel();
> +		BoxLayout availableLabelLayout = new BoxLayout(availableLabelPanel,
> +				BoxLayout.X_AXIS);
> +		availableLabelPanel.setLayout(availableLabelLayout);
> +		availableLabelPanel.add(availableLabel);
> +		availableLabelPanel.add(Box.createHorizontalStrut(10));
> +		BoxLayout availableBox = new BoxLayout(availablePanel, BoxLayout.Y_AXIS);
> +		availablePanel.setLayout(availableBox);
> +		availablePanel.add(availableLabelPanel);
> +		availableList = new JList();
> +		availableList.setFixedCellWidth(200);
> +		JScrollPane availableScrollPane = new JScrollPane(availableList);
> +		availableList.setSelectedIndex(0);
> +		availablePanel.add(availableScrollPane);
> +		JButton refreshButton = new JButton("Refresh");
> +		refreshButton.setActionCommand("refresh");
> +		refreshButton.addActionListener(this);
> +		availablePanel.add(Box.createVerticalStrut(10));
> +		JPanel refreshButtonPanel = new JPanel();
> +		BoxLayout refreshButtonLayout = new BoxLayout(refreshButtonPanel,
> +				BoxLayout.X_AXIS);
> +		refreshButtonPanel.setLayout(refreshButtonLayout);
> +		refreshButtonPanel.add(Box.createHorizontalStrut(10));
> +		refreshButtonPanel.add(refreshButton);
> +		availablePanel.add(refreshButtonPanel);
> +
> +		// the middle buttons
> +		JPanel middleButtonPanel = new JPanel();
> +		BoxLayout middleButtonBox = new BoxLayout(middleButtonPanel,
> +				BoxLayout.Y_AXIS);
> +		middleButtonPanel.setLayout(middleButtonBox);
> +		JButton addButton = new JButton("==>");
> +		addButton.setActionCommand("add");
> +		addButton.addActionListener(this);
> +		middleButtonPanel.add(addButton);
> +		middleButtonPanel.add(Box.createVerticalStrut(25));
> +		JButton removeButton = new JButton("<==");
> +		removeButton.setActionCommand("remove");
> +		removeButton.addActionListener(this);
> +		middleButtonPanel.add(removeButton);
> +
> +		// the slaves to be used panel
> +		JPanel usedPanel = new JPanel();
> +		JLabel usedLabel = new JLabel("Used Slaves");
> +		JPanel usedLabelPanel = new JPanel();
> +		BoxLayout usedLabelLayout = new BoxLayout(usedLabelPanel,
> +				BoxLayout.X_AXIS);
> +		usedLabelPanel.setLayout(usedLabelLayout);
> +		usedLabelPanel.add(usedLabel);
> +		usedLabelPanel.add(Box.createHorizontalStrut(10));
> +		BoxLayout usedBox = new BoxLayout(usedPanel, BoxLayout.Y_AXIS);
> +		usedPanel.setLayout(usedBox);
> +		usedPanel.add(usedLabelPanel);
> +		String[] s = { "                                           " };
> +		usedList = new JList(s);
> +		usedList.setFixedCellWidth(200);
> +		JButton addManuallyButton = new JButton("Add Manually");
> +		addManuallyButton.setActionCommand("addManually");
> +		addManuallyButton.addActionListener(this);
> +		JPanel addManuallyButtonPanel = new JPanel();
> +		BoxLayout addManuallyButtonPanelLayout = new BoxLayout(
> +				addManuallyButtonPanel, BoxLayout.X_AXIS);
> +		addManuallyButtonPanel.setLayout(addManuallyButtonPanelLayout);
> +		addManuallyButtonPanel.add(addManuallyButton);
> +		JScrollPane usedScrollPane = new JScrollPane(usedList);
> +		usedPanel.add(usedScrollPane);
> +		usedPanel.add(Box.createVerticalStrut(10));
> +		usedPanel.add(addManuallyButtonPanel);
> +
> +		// add to the slave chooser panel
> +		slaveChooserPanel.add(Box.createHorizontalStrut(30));
> +		slaveChooserPanel.add(availablePanel);
> +		slaveChooserPanel.add(Box.createHorizontalStrut(40));
> +		slaveChooserPanel.add(middleButtonPanel);
> +		slaveChooserPanel.add(Box.createHorizontalStrut(40));
> +		slaveChooserPanel.add(usedPanel);
> +		slaveChooserPanel.add(Box.createHorizontalStrut(30));
> +
> +		// alignment panel for the login info
> +		JPanel loginPanelPanel = new JPanel();
> +		BoxLayout loginPanelPanelLayout = new BoxLayout(loginPanelPanel,
> +				BoxLayout.X_AXIS);
> +		loginPanelPanel.setLayout(loginPanelPanelLayout);
> +		loginPanelPanel.add(Box.createHorizontalStrut(120));
> +		loginPanelPanel.add(loginPanel);
> +
> +		JPanel okCancelPanel = new JPanel();
> +		BoxLayout okCancelPanelLayout = new BoxLayout(okCancelPanel,
> +				BoxLayout.X_AXIS);
> +		okCancelPanel.setLayout(okCancelPanelLayout);
> +		JButton okButton = new JButton("OK");
> +		okButton.setActionCommand("ok");
> +		okButton.addActionListener(this);
> +		JButton cancelButton = new JButton("Cancel");
> +		cancelButton.setActionCommand("cancel");
> +		cancelButton.addActionListener(this);
> +		okCancelPanel.add(Box.createHorizontalStrut(380));
> +		okCancelPanel.add(okButton);
> +		okCancelPanel.add(Box.createHorizontalStrut(10));
> +		okCancelPanel.add(cancelButton);
> +
> +		JPanel loginChooserPanel = new JPanel();
> +		BoxLayout loginChooserPanelLayout = new BoxLayout(loginChooserPanel,
> +				BoxLayout.Y_AXIS);
> +		loginChooserPanel.setLayout(loginChooserPanelLayout);
> +		loginChooserPanel.add(Box.createVerticalStrut(10));
> +		loginChooserPanel.add(descriptionLabelPanel);
> +		loginChooserPanel.add(Box.createVerticalStrut(20));
> +		loginChooserPanel.add(loginPanelPanel);
> +		loginChooserPanel.add(Box.createVerticalStrut(20));
> +		loginChooserPanel.add(slaveChooserPanel);
> +		loginChooserPanel.add(Box.createVerticalStrut(10));
> +		loginChooserPanel.setBorder(BorderFactory.createEtchedBorder());
> +
> +		// add all panels to the main panel
> +		outerPanel.add(Box.createVerticalStrut(10));
> +		outerPanel.add(loginChooserPanel);
> +		outerPanel.add(Box.createVerticalStrut(10));
> +		outerPanel.add(okCancelPanel);
> +		outerPanel.add(Box.createVerticalStrut(5));
> +
> +		// center everything in the outerPanel
> +		setLayout(new BorderLayout());
> +		add(outerPanel, BorderLayout.CENTER);
> +
> +		// start the thread to populate the node list
> +		populateList();
> +	}
> +
> +	/**
> +	 * handle the actions
> +	 */
> +	public void actionPerformed(ActionEvent e) {
> +		String action = e.getActionCommand();
> +
> +		if (action.equals("add")) { // add the selected node to the use list
> +			int[] selectedIndices = availableList.getSelectedIndices();
> +			Object[] selectedVals = availableList.getSelectedValues();
> +			Vector usedNewData = new Vector();
> +			Vector availNewData = new Vector();
> +			ListModel availableModel = availableList.getModel();
> +			for (int i = 0; i < availableModel.getSize(); i++) {
> +				boolean remove = false;
> +				String s = (String) availableModel.getElementAt(i);
> +				for (int j = 0; j < selectedVals.length; j++) {
> +					if (!s.trim().equals("")
> +							&& s.equals((String) selectedVals[j])) {
> +						remove = true;
> +					}
> +				}
> +
> +				if (!remove) {
> +					availNewData.addElement(s);
> +				} else {
> +					usedNewData.addElement(s);
> +				}
> +			}
> +
> +			// add the existing data
> +			ListModel usedModel = usedList.getModel();
> +			for (int i = 0; i < usedModel.getSize(); i++) {
> +				String s = (String) usedModel.getElementAt(i);
> +				usedNewData.addElement(s);
> +			}
> +
> +			// check for duplicates
> +			Vector nodupes = new Vector();
> +			for (int i = 0; i < usedNewData.size(); i++) {
> +				boolean dupe = false;
> +				for (int j = i + 1; j < usedNewData.size(); j++) {
> +					if (((String) usedNewData.elementAt(i))
> +							.equals((String) usedNewData.elementAt(j))) {
> +						dupe = true;
> +					}
> +				}
> +
> +				if (!dupe) {
> +					if (!((String) usedNewData.elementAt(i)).trim().equals("")) {
> +						nodupes.addElement((String) usedNewData.elementAt(i));
> +					}
> +				}
> +			}
> +
> +			usedList.setListData(nodupes);
> +			availableList.setListData(availNewData);
> +		} else if (action.equals("remove")) { // remove the selected node from
> +												// the use list
> +			int[] selectedIndices = usedList.getSelectedIndices();
> +			Object[] selectedVals = usedList.getSelectedValues();
> +			Vector usedNewData = new Vector();
> +			Vector availNewData = new Vector();
> +			ListModel usedModel = usedList.getModel();
> +			for (int i = 0; i < usedModel.getSize(); i++) {
> +				boolean remove = false;
> +				String s = (String) usedModel.getElementAt(i);
> +				for (int j = 0; j < selectedVals.length; j++) {
> +					if (!s.trim().equals("")
> +							&& s.equals((String) selectedVals[j])) {
> +						remove = true;
> +					}
> +				}
> +
> +				if (!remove) {
> +					usedNewData.addElement(s);
> +				} else {
> +					availNewData.addElement(s);
> +				}
> +			}
> +
> +			// add the existing data
> +			ListModel availModel = availableList.getModel();
> +			for (int i = 0; i < availModel.getSize(); i++) {
> +				String s = (String) availModel.getElementAt(i);
> +				availNewData.addElement(s);
> +			}
> +
> +			// check for duplicates
> +			Vector nodupes = new Vector();
> +			for (int i = 0; i < availNewData.size(); i++) {
> +				boolean dupe = false;
> +				for (int j = i + 1; j < availNewData.size(); j++) {
> +					if (((String) availNewData.elementAt(i))
> +							.equals((String) availNewData.elementAt(j))) {
> +						dupe = true;
> +					}
> +				}
> +
> +				if (!dupe) {
> +					if (!((String) availNewData.elementAt(i)).trim().equals("")) {
> +						nodupes.addElement((String) availNewData.elementAt(i));
> +					}
> +				}
> +			}
> +
> +			usedList.setListData(usedNewData);
> +			availableList.setListData(nodupes);
> +		} else if (action.equals("addManually")) { // enter a host manually
> +			// show a dialog to let the user input an endPoint, then add the
> +			// result
> +			// to the usedList
> +			String endPoint = JOptionPane
> +					.showInputDialog("Please enter the "
> +							+ "network name or IP address of the slave you wish to add.");
> +			ListModel usedModel = usedList.getModel();
> +			Vector newData = new Vector();
> +			for (int i = 0; i < usedModel.getSize(); i++) { // copy the old
> +															// values
> +				String s = (String) usedModel.getElementAt(i);
> +				if (s != null && !s.trim().equals("")) {
> +					newData.addElement(s);
> +				}
> +			}
> +			newData.addElement(endPoint);
> +			usedList.setListData(newData);
> +		} else if (action.equals("refresh")) { // refresh the list
> +			populateList();
> +		} else if (action.equals("ok")) {
> +			try {
> +				// write the hosts
> +				File f = new File(configFile);
> +				FileWriter fw = new FileWriter(f, false);
> +				ListModel usedModel = usedList.getModel();
> +				String data = "";
> +				for (int i = 0; i < usedModel.getSize(); i++) { // create a
> +																// string to
> +																// write to the
> +																// file
> +					String s = (String) usedModel.getElementAt(i);
> +					data += s;
> +					data += "\n";
> +				}
> +
> +				fw.write(data, 0, data.length());
> +				fw.flush();
> +				fw.close();
> +
> +				// write the user info
> +				String password = new String(passwordField.getPassword());
> +				String username = usernameField.getText();
> +				String org = (String) domainField.getSelectedItem();
> +				// store these with bytes because the password needs to be
> +				// stored
> +				// as bytes so it's easier just to do all of them that way
> +				byte[] encryptedPass = encryptPassword(password);
> +				byte[] usernameBytes = username.getBytes();
> +				byte[] orgBytes = org.getBytes();
> +				FileOutputStream fos = new FileOutputStream(new File(
> +						DistributedCompositeActor.USER_CONFIG_FILE));
> +				fos.write(usernameBytes);
> +				fos.write(fileDelim);
> +				fos.write(orgBytes);
> +				fos.write(fileDelim);
> +				fos.write(encryptedPass);
> +				fos.write(fileDelim);
> +				fos.flush();
> +				fos.close();
> +			} catch (Exception ee) {
> +				String msg = "Error writing config file: " + ee.getMessage();
> +				JOptionPane.showMessageDialog(controllingFrame, msg, "alert",
> +						JOptionPane.ERROR_MESSAGE);
> +			}
> +
> +			// close the dialog
> +			controllingFrame.setVisible(false);
> +			controllingFrame.dispose();
> +		} else if (action.equals("cancel")) {
> +			controllingFrame.setVisible(false);
> +			controllingFrame.dispose();
> +		}
> +	}
> +
> +	/**
> +	 * create and show this GUI element
> +	 */
> +	public static void createAndShowGUI() {
> +		// Make sure we have nice window decorations.
> +		try {
> +			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
> +		} catch (Exception e) {
> +			e.printStackTrace();
> +		}
> +		// Create and set up the window.
> +		controllingFrame = new JFrame("Distributed Computing Options");
> +		controllingFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
> +
> +		// Create and set up the content pane.
> +		final DistributedConfigDialog contentPane = new DistributedConfigDialog();
> +		contentPane.setOpaque(true); // content panes must be opaque
> +		controllingFrame.setContentPane(contentPane);
> +
> +		// Make sure the focus goes to the right component
> +		// whenever the frame is initially given the focus.
> +		controllingFrame.addWindowListener(new WindowAdapter() {
> +			public void windowActivated(WindowEvent e) {
> +				// contentPane.resetFocus();
> +			}
> +		});
> +
> +		// Display the window.
> +		controllingFrame.pack();
> +		controllingFrame.setLocationRelativeTo(null); // stay in the center
> +		controllingFrame.setVisible(true);
> +	}
> +
> +	/**
> +	 * returnst the username, domain (org) and password in a string array. if
> +	 * this information is not in the config file, it will return empty strings
> +	 * for each. The string array will always have 3 elements and will be in the
> +	 * following form: s[0] = username s[1] = org s[3] = password
> +	 */
> +	public static String[] getUserInfo() throws FileNotFoundException,
> +			IOException {
> +		String[] s = new String[3];
> +		// populate the user info
> +		FileInputStream fis = new FileInputStream(new File(
> +				DistributedCompositeActor.USER_CONFIG_FILE));
> +		ByteArrayOutputStream baos = new ByteArrayOutputStream();
> +		byte[] b = new byte[1024];
> +		int numread = fis.read(b, 0, 1024);
> +		while (numread != -1) {
> +			baos.write(b, 0, numread);
> +			numread = fis.read(b, 0, 1024);
> +		}
> +
> +		// now we have the data in one array, process it
> +		byte[] filedata = baos.toByteArray();
> +		int c1 = 0;
> +		baos = new ByteArrayOutputStream();
> +		if (filedata.length == 0) { // the config file is empty. just return
> +									// blanks
> +			return s;
> +		}
> +
> +		while (filedata[c1] != fileDelim) { // get username
> +			baos.write(filedata[c1]);
> +			c1++;
> +		}
> +		String username = baos.toString();
> +
> +		c1++;
> +		baos = new ByteArrayOutputStream();
> +		while (filedata[c1] != fileDelim) { // get the org
> +			baos.write(filedata[c1]);
> +			c1++;
> +		}
> +		String org = baos.toString();
> +
> +		c1++;
> +		baos = new ByteArrayOutputStream();
> +
> +		// ciphertext byte array may contain fileDelim character as a byte
> +		// while(filedata[c1] != fileDelim)
> +		while (c1 < filedata.length - 1) { // get the password
> +			baos.write(filedata[c1]);
> +			c1++;
> +		}
> +		baos.flush();
> +		byte[] passwordBytes = baos.toByteArray();
> +		String password = new String(decryptPassword(passwordBytes));
> +
> +		s[0] = username;
> +		s[1] = org;
> +		s[2] = password;
> +		return s;
> +	}
> +
> +	/**
> +	 * encrypts the password and returns the ciphertext
> +	 */
> +	private static byte[] encryptPassword(String password) {
> +		try {
> +			PBEKeySpec pbeKeySpec;
> +			PBEParameterSpec pbeParamSpec;
> +			SecretKeyFactory keyFac;
> +			pbeParamSpec = new PBEParameterSpec(SALT, ITERATIONCOUNT);
> +			pbeKeySpec = new PBEKeySpec(PASSWORD.toCharArray());
> +			keyFac = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
> +			SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);
> +			Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
> +			pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);
> +			byte[] b = password.getBytes();
> +			byte[] ciphertext = pbeCipher.doFinal(b);
> +			return ciphertext;
> +		} catch (Exception e) {
> +			System.out
> +					.println("Could not encrypt password.  storing in clear text.");
> +			e.printStackTrace();
> +			return password.getBytes();
> +		}
> +	}
> +
> +	/**
> +	 * decrypt the password and return cleartext
> +	 */
> +	private static byte[] decryptPassword(byte[] ciphertext) {
> +		try {
> +			PBEKeySpec pbeKeySpec;
> +			PBEParameterSpec pbeParamSpec;
> +			SecretKeyFactory keyFac;
> +			pbeParamSpec = new PBEParameterSpec(SALT, ITERATIONCOUNT);
> +			pbeKeySpec = new PBEKeySpec(PASSWORD.toCharArray());
> +			keyFac = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
> +			SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);
> +			Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
> +			pbeCipher.init(Cipher.DECRYPT_MODE, pbeKey, pbeParamSpec);
> +			byte[] password = pbeCipher.doFinal(ciphertext);
> +			return password;
> +		} catch (Exception e) {
> +			System.out.println("Could not decrypt password: " + e.getMessage());
> +			e.printStackTrace();
> +			return null;
> +		}
> +	}
> +
> +	/**
> +	 * populate the list of available slaves
> +	 */
> +	private void populateList() {
> +		// start a thread to populate the available list
> +		NodeListThread nlt = new NodeListThread();
> +		nlt.start();
> +
> +		try { // populate the usedList with the config file info
> +			FileReader fr = new FileReader(new File(configFile));
> +			char[] c = new char[1024];
> +			int numread = fr.read(c, 0, 1024);
> +			String data = "";
> +			while (numread != -1) {
> +				data += new String(c, 0, numread);
> +				numread = fr.read(c, 0, 1024);
> +			}
> +
> +			String[] hosts = data.split("\n");
> +			usedList.setListData(hosts);
> +		} catch (Exception e) {
> +			String msg = "Error reading config file: " + e.getMessage();
> +			e.printStackTrace();
> +			JOptionPane.showMessageDialog(controllingFrame, msg, "alert",
> +					JOptionPane.ERROR_MESSAGE);
> +		}
> +
> +		UserInfoThread uit = new UserInfoThread();
> +		uit.start();
> +	}
> +
> +	/**
> +	 * a thread to update the node list
> +	 */
> +	private class NodeListThread extends Thread {
> +		public NodeListThread() {
> +			// empty
> +		}
> +
> +		public void run() { // do this in a thread so that the dialog will
> +							// display then the
> +			// list will get updated instead of the user just seeing the menu
> +			// sit there while the dialog builds.
> +			try {
> +				// start the status dialog
> +				pmworker.start();
> +				String[] data;
> +
> +				// get the registry and find all of the registered nodes
> +				RepositoryManager repMan = RepositoryManager.getInstance();
> +				Repository rep = repMan.getRepository("keplerRepository");
> +				EcogridRepository ecorep = (EcogridRepository) rep;
> +				RegistryClientContainer ecoclientcont = ecorep
> +						.getRegistryClient();
> +				RegistryServiceClient ecoclient = ecoclientcont.client;
> +				String sessionid = ecoclientcont.sessionid;
> +				RegistryEntryType[] regentries = ecoclient.list(sessionid);
> +				if (regentries == null || regentries.length == 0) {
> +					pmworker.destroy();
> +					JOptionPane.showMessageDialog(null,
> +							"There are no slaves registered.", "alert",
> +							JOptionPane.ERROR_MESSAGE);
> +					return;
> +				}
> +				data = new String[regentries.length];
> +				for (int i = 0; i < regentries.length; i++) {
> +					data[i] = regentries[i].getEndPoint();
> +				}
> +
> +				// add the data to the list
> +				availableList.setListData(data);
> +			} catch (Exception e) {
> +				String msg = "Error discovering nodes: " + e.getMessage();
> +				e.printStackTrace();
> +				JOptionPane.showMessageDialog(null, msg, "alert",
> +						JOptionPane.ERROR_MESSAGE);
> +			}
> +			// close the status dialog
> +			pmworker.destroy();
> +		}
> +	}
> +
> +	/**
> +	 * a thread to update the user info
> +	 */
> +	private class UserInfoThread extends Thread {
> +		public UserInfoThread() {
> +			// empty
> +		}
> +
> +		public void run() {
> +			try {
> +				String[] s = getUserInfo();
> +				String username = s[0];
> +				String org = s[1];
> +				String password = s[2];
> +
> +				// write to the fields
> +				usernameField.setText(username);
> +				passwordField.setText(password);
> +				for (int i = 0; i < domainField.getItemCount(); i++) {
> +					String item = (String) domainField.getItemAt(i);
> +					if (item.equals(org)) {
> +						domainField.setSelectedIndex(i);
> +						break;
> +					}
> +				}
> +
> +			} catch (Exception e) {
> +				e.printStackTrace();
> +				// don't do anything here, just don't put the user data in
> +			}
> +		}
> +	}
> +}
> 
> Added: trunk/src/org/kepler/distributed/DistributedFileServer.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/DistributedFileServer.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/DistributedFileServer.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,76 @@
> +//  Copyright (c) 2007, Regents of the University of California
> +//  All rights reserved.
> +//
> +//  Redistribution and use in source and binary forms, with or without
> +//  modification, are permitted provided that the following conditions are
> +//  met:
> +//
> +//    * Redistributions of source code must retain the above copyright notice,
> +//  this list of conditions and the following disclaimer.
> +//    * Redistributions in binary form must reproduce the above copyright
> +//  notice, this list of conditions and the following disclaimer in the
> +//  documentation and/or other materials provided with the distribution.
> +//    * Neither the name of the University of California, San Diego (UCSD) nor
> +//  the names of its contributors may be used to endorse or promote products
> +//  derived from this software without specific prior written permission.
> +//
> +//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
> +//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> +//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> +//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> +//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
> +//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
> +//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
> +//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
> +//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> +//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
> +//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +//
> +//
> +//  FILE
> +//  DistributedFileServer.java  -
> +//      org.ecoinformatics.seek.distrib.DistributedFileServer
> +//
> +//  CLASS HIERARCHY
> +//
> +//      |
> +//      +-org.ecoinformatics.seek.distrib.DistributedFileServer
> +//
> +//  PRINCIPAL AUTHOR
> +//  Lucas Gilbert, SDSC/UCSD
> +//
> +//
> +package org.kepler.distributed;
> +
> +import java.io.IOException;
> +import java.rmi.Remote;
> +import java.rmi.RemoteException;
> +
> +//////////////////////////////////////////////////////////////////////////
> +//// DistributedFileServer
> +
> +/**
> + * '$Author: aschultz $' '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + * '$Revision: 16353 $'
> + * 
> + * A file server to transfer files during a distributed workflow execution.
> + */
> +public interface DistributedFileServer extends Remote {
> +	/**
> +	 * Register a file with this <code>cookie</code> to be read remotely, the
> +	 * location according to <code>token</code>.
> +	 */
> +	public void registerFile(DataToken token, String cookie)
> +			throws RemoteException, IOException;
> +
> +	/**
> +	 * Remote system reads the file registered as <code>cookie</code>
> +	 */
> +	public byte[] read(String cookie, long seek, int length)
> +			throws RemoteException, IOException;
> +
> +	/**
> +	 * Remote system reads the file registered as <code>cookie</code>
> +	 */
> +	public long length(String cookie) throws RemoteException, IOException;
> +}
> 
> Added: trunk/src/org/kepler/distributed/DistributedIOPort.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/DistributedIOPort.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/DistributedIOPort.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,464 @@
> +//  Copyright (c) 2007, Regents of the University of California
> +//  All rights reserved.
> +//
> +//  Redistribution and use in source and binary forms, with or without
> +//  modification, are permitted provided that the following conditions are
> +//  met:
> +//
> +//    * Redistributions of source code must retain the above copyright notice,
> +//  this list of conditions and the following disclaimer.
> +//    * Redistributions in binary form must reproduce the above copyright
> +//  notice, this list of conditions and the following disclaimer in the
> +//  documentation and/or other materials provided with the distribution.
> +//    * Neither the name of the University of California, San Diego (UCSD) nor
> +//  the names of its contributors may be used to endorse or promote products
> +//  derived from this software without specific prior written permission.
> +//
> +//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
> +//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> +//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> +//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> +//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
> +//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
> +//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
> +//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
> +//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> +//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
> +//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +//
> +//
> +//  FILE
> +//  SlaveController.java -
> +//     org.ecoinformatics.seek.distrib.SlaveController
> +//
> +//  CLASS HIERARCHY
> +//
> +//      |
> +//      +-org.kepler.distributed.SlaveController
> +//
> +//
> +//  PRINCIPAL AUTHOR
> +//  Lucas Gilbert, SDSC/UCSD
> +//
> +//
> +package org.kepler.distributed;
> +
> +import java.util.Iterator;
> +import java.util.Vector;
> +
> +import ptolemy.actor.NoTokenException;
> +import ptolemy.actor.Receiver;
> +import ptolemy.actor.TypedIOPort;
> +import ptolemy.data.Token;
> +import ptolemy.kernel.ComponentEntity;
> +import ptolemy.kernel.util.IllegalActionException;
> +import ptolemy.kernel.util.NameDuplicationException;
> +import ptolemy.kernel.util.NamedObj;
> +import ptolemy.kernel.util.Workspace;
> +
> +/**
> + * '$Author: aschultz $' '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + * '$Revision: 16353 $'
> + */
> +public class DistributedIOPort extends TypedIOPort {
> +	/**
> +	 * Constructor for the DistributedIOPort object
> +	 */
> +	public DistributedIOPort() {
> +		super();
> +
> +		init();
> +	}
> +
> +	/**
> +	 * Constructor for the DistributedIOPort object
> +	 * 
> +	 *@param workspace
> +	 *            Description of the Parameter
> +	 */
> +	public DistributedIOPort(Workspace workspace) {
> +		super(workspace);
> +
> +		init();
> +		print("new dip");
> +	}
> +
> +	/**
> +	 * Constructor for the DistributedIOPort object
> +	 * 
> +	 *@param container
> +	 *            Description of the Parameter
> +	 *@param name
> +	 *            Description of the Parameter
> +	 *@exception IllegalActionException
> +	 *                Description of the Exception
> +	 *@exception NameDuplicationException
> +	 *                Description of the Exception
> +	 */
> +	public DistributedIOPort(ComponentEntity container, String name)
> +			throws IllegalActionException, NameDuplicationException {
> +		super(container, name);
> +
> +		init();
> +		print("new dip");
> +	}
> +
> +	/**
> +	 * Constructor for the DistributedIOPort object
> +	 * 
> +	 *@param container
> +	 *            Description of the Parameter
> +	 *@param name
> +	 *            Description of the Parameter
> +	 *@param isInput
> +	 *            Description of the Parameter
> +	 *@param isOutput
> +	 *            Description of the Parameter
> +	 *@exception IllegalActionException
> +	 *                Description of the Exception
> +	 *@exception NameDuplicationException
> +	 *                Description of the Exception
> +	 */
> +	public DistributedIOPort(ComponentEntity container, String name,
> +			boolean isInput, boolean isOutput) throws IllegalActionException,
> +			NameDuplicationException {
> +		this(container, name);
> +		setInput(isInput);
> +		setOutput(isOutput);
> +
> +		init();
> +		print("new dip");
> +	}
> +
> +	/**
> +	 * Clones all of the properties of an IOPort
> +	 */
> +	/*
> +	 * public void cloneIOPort(CompositeEntity container, IOPort port, Iterator
> +	 * insidePortIterator) throws IllegalActionException,
> +	 * NameDuplicationException { //need: //name, type (if TypedIOPort), all
> +	 * attributes, input/output String name = port.getName(); Type type =
> +	 * BaseType.GENERAL; if(port instanceof TypedIOPort) { type =
> +	 * ((TypedIOPort)port).getType(); } boolean isInput = port.isInput();
> +	 * boolean isOutput = port.isOutput(); boolean isMultiport =
> +	 * port.isMultiport();
> +	 * 
> +	 * print("setting base attributes");
> +	 * 
> +	 * //set the base properties this.setName(name); this.setTypeEquals(type);
> +	 * this.setInput(isInput); this.setOutput(isOutput);
> +	 * this.setMultiport(isMultiport);
> +	 * 
> +	 * print("setting all attributes"); //add all of the attributes Iterator
> +	 * attributeItt = port.attributeList().iterator();
> +	 * while(attributeItt.hasNext()) { Attribute a =
> +	 * (Attribute)attributeItt.next(); print("processing attribute " +
> +	 * a.getName()); try { Attribute a1 = (Attribute)a.clone(port.workspace());
> +	 * print("setting container on clone"); a1.setContainer(this);
> +	 * print("container set"); } catch(CloneNotSupportedException cnse) { //do
> +	 * nothing. we just don't get this attribute } }
> +	 * 
> +	 * print("cloning connections"); //add all of the connections //Iterator
> +	 * insidePortIterator = port.insidePortList().iterator(); int
> +	 * insidePortIndex = 0; while(insidePortIterator.hasNext()) { IOPort
> +	 * insidePort = (IOPort)insidePortIterator.next();
> +	 * print("cloning connection with " + insidePort.getName()); TypedIORelation
> +	 * r = new TypedIORelation(container, container.getName() + "Relation" +
> +	 * insidePortIndex); print("Created new relation " + r.getName());
> +	 * insidePort.unlink(0); print("Relinking..."); this.link(r);
> +	 * insidePort.link(r); print("changing connections");
> +	 * container.connectionsChanged(insidePort);
> +	 * container.connectionsChanged(this); insidePortIndex++; }
> +	 * 
> +	 * print("done cloning"); }
> +	 */
> +
> +	/**
> +	 * Description of the Method
> +	 */
> +	private void init() {
> +		tokens = new Vector();
> +	}
> +
> +	/**
> +	 * Description of the Method
> +	 * 
> +	 *@param token
> +	 *            Description of the Parameter
> +	 *@exception IllegalActionException
> +	 *                Description of the Exception
> +	 */
> +	protected void loadRemoteData(Token token) throws IllegalActionException {
> +		print("loadRemoteData 1");
> +		tokens.add(token);
> +		sendInside(0, token);
> +	}
> +
> +	/**
> +	 * Description of the Method
> +	 * 
> +	 *@param tokenArray
> +	 *            Description of the Parameter
> +	 *@exception IllegalActionException
> +	 *                Description of the Exception
> +	 */
> +	protected void loadRemoteData(Token[] tokenArray)
> +			throws IllegalActionException {
> +		print("loadRemoteData 2");
> +		for (int i = 0; i < tokenArray.length; i++) {
> +			tokens.add(tokenArray[i]);
> +			print("sending " + tokenArray[i].toString() + " inside");
> +			this.sendInside(0, tokenArray[i]);
> +		}
> +		print("tokens.size: " + tokens.size());
> +	}
> +
> +	/**
> +	 * Description of the Method
> +	 * 
> +	 *@param channelIndex
> +	 *            Description of the Parameter
> +	 *@return Description of the Return Value
> +	 *@exception NoTokenException
> +	 *                Description of the Exception
> +	 *@exception IllegalActionException
> +	 *                Description of the Exception
> +	 */
> +	public Token get(int channelIndex) throws NoTokenException,
> +			IllegalActionException {
> +		int i = 0;
> +		while ((tokens.size() < 1) && (i < 10)) {
> +			synchronized (this) {
> +				try {
> +					print("blocking...");
> +					this.wait(1000);
> +					i++;
> +				} catch (InterruptedException e) {
> +					e.printStackTrace();
> +				}
> +			}
> +		}
> +
> +		if (i == 10) {
> +			print("give up getting token from " + this.getName());
> +			Token emptyToken = new Token();
> +			return emptyToken;
> +		}
> +
> +		Object temp = tokens.get(0);
> +		if (temp instanceof Token[]) {
> +			temp = ((Token[]) temp)[0];
> +		}
> +		tokens.remove(0);
> +		print("rmi call: getting token: " + ((Token) temp).toString());
> +		return (Token) temp;
> +	}
> +
> +	/**
> +	 * Description of the Method
> +	 * 
> +	 *@param channelIndex
> +	 *            Description of the Parameter
> +	 *@param vectorLength
> +	 *            Description of the Parameter
> +	 *@return Description of the Return Value
> +	 *@exception NoTokenException
> +	 *                Description of the Exception
> +	 *@exception IllegalActionException
> +	 *                Description of the Exception
> +	 */
> +	public Token[] get(int channelIndex, int vectorLength)
> +			throws NoTokenException, IllegalActionException {
> +		print("get2");
> +		while (tokens.size() < 1) {
> +			synchronized (this) {
> +				try {
> +					this.wait(1000);
> +				} catch (InterruptedException e) {
> +					e.printStackTrace();
> +				}
> +			}
> +		}
> +		Object temp = tokens.get(0);
> +		if (temp instanceof Token) {
> +			temp = new Token[] { (Token) temp };
> +		}
> +		tokens.remove(0);
> +
> +		// TODO vectorLength
> +		return (Token[]) temp;
> +	}
> +
> +	/**
> +   *
> +   */
> +	public Token getInside(int channelIndex) throws IllegalActionException {
> +		print("getInside");
> +
> +		Receiver[][] localReceivers;
> +
> +		try {
> +			_workspace.getReadAccess();
> +
> +			// Note that the getInsideReceivers() method might throw an
> +			// IllegalActionException if there's no director.
> +			localReceivers = getInsideReceivers();
> +			print("localReceivers.length: " + localReceivers.length);
> +
> +			if (channelIndex >= localReceivers.length) {
> +				if (!isOutput()) {
> +					throw new IllegalActionException(this,
> +							"Port is not an output port!");
> +				} else {
> +					throw new IllegalActionException(this, "Channel index "
> +							+ channelIndex
> +							+ " is out of range, because inside width is only "
> +							+ getWidthInside() + ".");
> +				}
> +			}
> +
> +			if (localReceivers[channelIndex] == null) {
> +				throw new IllegalActionException(this,
> +						"No receiver at inside index: " + channelIndex + ".");
> +			}
> +		} finally {
> +			_workspace.doneReading();
> +		}
> +
> +		Token token = null;
> +
> +		for (int j = 0; j < localReceivers[channelIndex].length; j++) {
> +			Token localToken = localReceivers[channelIndex][j].get();
> +			print("token in getInside: " + localToken.toString());
> +			if (token == null) {
> +				token = localToken;
> +			}
> +		}
> +
> +		if (token == null) {
> +			throw new NoTokenException(this, "No token to return.");
> +		}
> +
> +		print("get from inside channel " + channelIndex + ": " + token);
> +		tokens.add(token);
> +
> +		return token;
> +	}
> +
> +	/**
> +   *
> +   */
> +	public void sendInside(int channelIndex, Token token)
> +			throws IllegalActionException, ptolemy.actor.NoRoomException {
> +		Receiver[][] farReceivers;
> +
> +		print("send inside to channel " + channelIndex + ": " + token);
> +
> +		try {
> +			_workspace.getReadAccess();
> +
> +			// Note that the getRemoteReceivers() method doesn't throw
> +			// any non-runtime exception.
> +			farReceivers = deepGetReceivers();
> +			// farReceivers = getReceivers();
> +
> +			if ((farReceivers == null) || (farReceivers.length <= channelIndex)
> +					|| (farReceivers[channelIndex] == null)) {
> +				return;
> +			}
> +		} finally {
> +			_workspace.doneReading();
> +		}
> +
> +		print("far receivers: " + farReceivers[channelIndex].length);
> +		print("channel to send to receivers: " + channelIndex);
> +		if (farReceivers[channelIndex].length > 0) {
> +			print("sending inside to: "
> +					+ farReceivers[channelIndex][0].toString());
> +			print("receiver hash: " + farReceivers[channelIndex][0].hashCode());
> +			print("workspace hash: " + workspace().hashCode());
> +			// printWorkspace(workspace());
> +			print("port name: " + getName());
> +			// Delegate to the receiver to handle putting to all
> +			// receivers, since domain-specific techniques might be relevant.
> +			// farReceivers[channelIndex][0].putToAll(token,
> +			// farReceivers[channelIndex]);
> +			farReceivers[channelIndex][0].put(token);
> +		}
> +		print("does the receiver have a token now? "
> +				+ farReceivers[0][0].hasToken());
> +		print("done sending tokens");
> +	}
> +
> +	/**
> +   *
> +   */
> +	public boolean hasTokenInside(int channelIndex)
> +			throws IllegalActionException {
> +		print("hasTokenInside");
> +		// The getInsideReceivers() method throws an
> +		// IllegalActionException if there's no director.
> +		Receiver[][] receivers = getInsideReceivers();
> +		print("receivers length: " + receivers.length);
> +		print("receivers[0][0]: " + receivers[0][0].toString());
> +		print("receiver[0][0] hash: " + receivers[0][0].hashCode());
> +		print("workspace hash: " + workspace().hashCode());
> +		print("port name: " + getName());
> +		// printWorkspace(workspace());
> +		boolean result = false;
> +
> +		if (channelIndex >= receivers.length) {
> +			if (!isOutput()) {
> +				throw new IllegalActionException(this,
> +						"Port is not an output port!");
> +			} else {
> +				throw new IllegalActionException(this, "Channel index "
> +						+ channelIndex
> +						+ " is out of range, because inside width is only "
> +						+ getWidthInside() + ".");
> +			}
> +		}
> +
> +		if (receivers[channelIndex] != null) {
> +			for (int j = 0; j < receivers[channelIndex].length; j++) {
> +				print("checking for tokens in hasTokenInside: " + channelIndex
> +						+ ", " + j);
> +				if (receivers[channelIndex][j].hasToken()) {
> +					print("receiver has token");
> +					result = true;
> +					break;
> +				} else {
> +					print("receiver does not have a token");
> +				}
> +			}
> +		}
> +
> +		print("hasTokenInside on channel " + channelIndex + " returns "
> +				+ result);
> +
> +		return result;
> +	}
> +
> +	/**
> +   *
> +   */
> +	private void print(String message) {
> +		DistributedLogger.print("DistributedInputPort:" + this.getName() + ": "
> +				+ message, DistributedLogger.LOW);
> +	}
> +
> +	/**
> +   *
> +   */
> +	private void printWorkspace(Workspace workspace) {
> +		print("<workspace elements>");
> +		Iterator i = workspace.directoryList().iterator();
> +		while (i.hasNext()) {
> +			NamedObj no = (NamedObj) i.next();
> +			print(no.getName());
> +		}
> +		print("</workspace elements>");
> +	}
> +
> +	Vector tokens;
> +}
> 
> Added: trunk/src/org/kepler/distributed/DistributedInputActor.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/DistributedInputActor.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/DistributedInputActor.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,125 @@
> +/**
> + *    '$RCSfile$'
> + *
> + *     '$Author: aschultz $'
> + *       '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + *   '$Revision: 16353 $'
> + *
> + *  For Details: http://www.kepler-project.org
> + *
> + * Copyright (c) 2004 The Regents of the University of California.
> + * All rights reserved.
> + *
> + * Permission is hereby granted, without written agreement and without
> + * license or royalty fees, to use, copy, modify, and distribute this
> + * software and its documentation for any purpose, provided that the
> + * above copyright notice and the following two paragraphs appear in
> + * all copies of this software.
> + *
> + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
> + * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
> + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
> + * IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY
> + * OF SUCH DAMAGE.
> + *
> + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
> + * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY
> + * OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
> + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
> + */
> +
> +package org.kepler.distributed;
> +
> +import java.util.Vector;
> +
> +import ptolemy.actor.TypedIOPort;
> +import ptolemy.data.Token;
> +import ptolemy.data.type.BaseType;
> +import ptolemy.kernel.CompositeEntity;
> +import ptolemy.kernel.util.IllegalActionException;
> +import ptolemy.kernel.util.NameDuplicationException;
> +
> +/**
> + * '$Author: aschultz $' '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + * '$Revision: 16353 $'
> + */
> +public class DistributedInputActor extends ptolemy.actor.TypedAtomicActor
> +		implements RemoteActor {
> +
> +	private Vector tokenVec = new Vector();
> +	private TypedIOPort outputPort;
> +
> +	/**
> +	 * Constructor
> +	 * 
> +	 * @param portType
> +	 */
> +	public DistributedInputActor(CompositeEntity container, String name,
> +			String portType) throws NameDuplicationException,
> +			IllegalActionException {
> +		super(container, name);
> +		outputPort = new TypedIOPort(this, "output", false, true);
> +		print("setting port type of " + name + " to be " + portType);
> +		outputPort.setTypeEquals(BaseType.forName(portType));
> +		print("setting result : " + outputPort.getType());
> +	}
> +
> +	public DistributedInputActor(CompositeEntity container, String name)
> +			throws NameDuplicationException, IllegalActionException {
> +		super(container, name);
> +		outputPort = new TypedIOPort(this, "output", false, true);
> +	}
> +
> +	/**
> +	 * fire
> +	 */
> +	public void fire() throws IllegalActionException {
> +		super.fire();
> +		print("DistributedInputActor firing");
> +		if (tokenVec.size() > 0) { // send one token for each fire. this might
> +									// need to be changed to
> +			// send them all.
> +			Token t = (Token) tokenVec.remove(tokenVec.size() - 1);
> +			print("sending token: " + t.toString());
> +			outputPort.broadcast(t);
> +		}
> +
> +	}
> +
> +	/**
> +	 * load the remote data collected by the slave
> +	 * 
> +	 * @param tokens
> +	 *            the token array to load
> +	 */
> +	public void loadRemoteData(Token[] tokens) {
> +		for (int i = 0; i < tokens.length; i++) {
> +			print("loading token: " + tokens[i].toString());
> +			tokenVec.add(tokens[i]);
> +		}
> +	}
> +
> +	/**
> +	 * load the remote data collected by the slave
> +	 * 
> +	 * @param t
> +	 *            the token to add
> +	 */
> +	public void loadRemoteData(Token t) {
> +		print("loading token: " + t.toString());
> +		tokenVec.add(t);
> +	}
> +
> +	private void print(String message) {
> +		DistributedLogger.print("DistributedInputActor." + this.getName()
> +				+ ": " + message, DistributedLogger.LOW);
> +	}
> +
> +	public boolean postfire() throws IllegalActionException {
> +
> +		return false;
> +	}
> +
> +}
> 
> Added: trunk/src/org/kepler/distributed/DistributedLogger.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/DistributedLogger.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/DistributedLogger.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,100 @@
> +/**
> + *    '$RCSfile$'
> + *
> + *     '$Author: aschultz $'
> + *       '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + *   '$Revision: 16353 $'
> + *
> + *  For Details: http://www.kepler-project.org
> + *
> + * Copyright (c) 2004 The Regents of the University of California.
> + * All rights reserved.
> + *
> + * Permission is hereby granted, without written agreement and without
> + * license or royalty fees, to use, copy, modify, and distribute this
> + * software and its documentation for any purpose, provided that the
> + * above copyright notice and the following two paragraphs appear in
> + * all copies of this software.
> + *
> + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
> + * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
> + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
> + * IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY
> + * OF SUCH DAMAGE.
> + *
> + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
> + * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY
> + * OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
> + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
> + */
> +
> +package org.kepler.distributed;
> +
> +import java.io.File;
> +import java.io.FileWriter;
> +import java.io.IOException;
> +import java.util.Date;
> +
> +/**
> + * '$Author: aschultz $' '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + * '$Revision: 16353 $'
> + */
> +public class DistributedLogger {
> +	/** file to write to **/
> +	public static File LOGFILE = new File("distributed-output.log");
> +
> +	public static int ALWAYS = 4; // always print the message
> +	public static int HIGH = 3;
> +	public static int MEDIUM = 2;
> +	public static int LOW = 1;
> +	public static int NONE = 0; // never print the message
> +	public static int DEFAULT = 3; // the default level
> +
> +	/** set this variable to set the priority level **/
> +	public static int priorityLevel = HIGH;
> +
> +	public static void print(String msg, int priority) {
> +		if (priority >= priorityLevel) {
> +			System.out.println(msg);
> +		}
> +	}
> +
> +	/**
> +	 * prints a message to stdout with the default priority level
> +	 */
> +	public static void print(String msg) {
> +		print(msg, DEFAULT);
> +	}
> +
> +	/**
> +	 * writes a message to the LOGFILE
> +	 */
> +	public static void write(String msg) throws IOException {
> +		write(LOGFILE, msg);
> +	}
> +
> +	/**
> +	 * writes a message to a file with a timestamp
> +	 */
> +	public static void write(File f, String msg) throws IOException {
> +		write(f, msg, DEFAULT);
> +	}
> +
> +	/**
> +	 * writes a message to a file with a timestamp
> +	 */
> +	public static void write(File f, String msg, int priority)
> +			throws IOException {
> +		if (priority >= priorityLevel) {
> +			Date d = new Date();
> +			String dstring = d.toString();
> +			String line = dstring + " -- " + msg;
> +			FileWriter fw = new FileWriter(f, true);
> +			fw.write(line, 0, line.length());
> +			fw.flush();
> +			fw.close();
> +		}
> +	}
> +}
> 
> Added: trunk/src/org/kepler/distributed/DistributedPortParameter.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/DistributedPortParameter.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/DistributedPortParameter.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,104 @@
> +/**
> + *    '$RCSfile$'
> + *
> + *     '$Author: aschultz $'
> + *       '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + *   '$Revision: 16353 $'
> + *
> + *  For Details: http://www.kepler-project.org
> + *
> + * Copyright (c) 2004 The Regents of the University of California.
> + * All rights reserved.
> + *
> + * Permission is hereby granted, without written agreement and without
> + * license or royalty fees, to use, copy, modify, and distribute this
> + * software and its documentation for any purpose, provided that the
> + * above copyright notice and the following two paragraphs appear in
> + * all copies of this software.
> + *
> + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
> + * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
> + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
> + * IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY
> + * OF SUCH DAMAGE.
> + *
> + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
> + * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY
> + * OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
> + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
> + */
> +
> +package org.kepler.distributed;
> +
> +import java.util.Vector;
> +
> +import ptolemy.actor.parameters.PortParameter;
> +import ptolemy.data.Token;
> +import ptolemy.kernel.CompositeEntity;
> +import ptolemy.kernel.util.IllegalActionException;
> +import ptolemy.kernel.util.NameDuplicationException;
> +
> +/**
> + * '$Author: aschultz $' '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + * '$Revision: 16353 $'
> + */
> +public class DistributedPortParameter extends PortParameter implements
> +		RemoteActor {
> +	private Vector tokenVec = new Vector();
> +
> +	/**
> +	 * Constructor
> +	 */
> +	public DistributedPortParameter(CompositeEntity container, String name)
> +			throws NameDuplicationException, IllegalActionException {
> +		super(container, name);
> +	}
> +
> +	/**
> +	 * load the remote data collected by the slave
> +	 * 
> +	 * @param tokens
> +	 *            the token array to load
> +	 */
> +	public void loadRemoteData(Token[] tokens) {
> +		for (int i = 0; i < tokens.length; i++) {
> +			print("loading token: " + tokens[i].toString());
> +			tokenVec.add(tokens[i]);
> +		}
> +	}
> +
> +	/**
> +	 * load the remote data collected by the slave
> +	 * 
> +	 * @param t
> +	 *            the token to add
> +	 */
> +	public void loadRemoteData(Token t) {
> +		print("loading token: " + t.toString());
> +		tokenVec.add(t);
> +	}
> +
> +	/**
> +	 * get the data from the tokenVec instead of the port
> +	 */
> +	public void update() throws IllegalActionException {
> +		print("updating " + this.getName());
> +		if (tokenVec.size() > 0) { // send one token for each fire. this might
> +									// need to be changed to
> +			// send them all.
> +			Token t = (Token) tokenVec.remove(tokenVec.size() - 1);
> +			print("sending token: " + t.toString());
> +			setCurrentValue(t);
> +		}
> +	}
> +
> +	/**
> +	 * print output
> +	 */
> +	private void print(String message) {
> +		DistributedLogger.print("DistributedPortParameter." + this.getName()
> +				+ ": " + message, DistributedLogger.LOW);
> +	}
> +}
> 
> Added: trunk/src/org/kepler/distributed/DistributedSDFDirector.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/DistributedSDFDirector.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/DistributedSDFDirector.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,127 @@
> +/**
> + *    '$RCSfile$'
> + *
> + *     '$Author: aschultz $'
> + *       '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + *   '$Revision: 16353 $'
> + *
> + *  For Details: http://www.kepler-project.org
> + *
> + * Copyright (c) 2004 The Regents of the University of California.
> + * All rights reserved.
> + *
> + * Permission is hereby granted, without written agreement and without
> + * license or royalty fees, to use, copy, modify, and distribute this
> + * software and its documentation for any purpose, provided that the
> + * above copyright notice and the following two paragraphs appear in
> + * all copies of this software.
> + *
> + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
> + * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
> + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
> + * IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY
> + * OF SUCH DAMAGE.
> + *
> + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
> + * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY
> + * OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
> + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
> + */
> +
> +package org.kepler.distributed;
> +
> +import ptolemy.domains.sdf.kernel.SDFDirector;
> +import ptolemy.kernel.CompositeEntity;
> +import ptolemy.kernel.util.IllegalActionException;
> +import ptolemy.kernel.util.NameDuplicationException;
> +import ptolemy.kernel.util.NamedObj;
> +import ptolemy.kernel.util.Workspace;
> +
> +/**
> + * '$Author: aschultz $' '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + * '$Revision: 16353 $'
> + */
> +public class DistributedSDFDirector extends SDFDirector {
> +	/**
> +	 * Constructor
> +	 */
> +	public DistributedSDFDirector() throws IllegalActionException,
> +			NameDuplicationException {
> +		super();
> +	}
> +
> +	/**
> +	 * Constructor
> +	 */
> +	public DistributedSDFDirector(CompositeEntity container, String name)
> +			throws IllegalActionException, NameDuplicationException {
> +		super(container, name);
> +	}
> +
> +	/**
> +	 * Constructor
> +	 */
> +	public DistributedSDFDirector(Workspace w) throws IllegalActionException,
> +			NameDuplicationException {
> +		super(w);
> +	}
> +
> +	public void initialize() throws IllegalActionException {
> +		super.initialize();
> +		NamedObj container = getContainer();
> +		print("container: " + container.getName());
> +	}
> +
> +	public boolean prefire() throws IllegalActionException {
> +		print("Director calling prefire");
> +		boolean b = super.prefire();
> +		return b;
> +	}
> +
> +	public void fire() throws IllegalActionException {
> +		/*
> +		 * FireThread ft1 = new FireThread(); print("firing thread1");
> +		 * ft1.start(); FireThread ft2 = new FireThread();
> +		 * print("firing thread2"); ft2.start(); int count = 0; while(!ft1.done
> +		 * && !ft2.done) { if(count % 1000 == 0) System.out.print("waiting. ");
> +		 * count++; }
> +		 */
> +		print("director firing");
> +		super.fire();
> +		print("done firing");
> +	}
> +
> +	public void firefire() throws IllegalActionException {
> +		print("firefire");
> +		super.fire();
> +	}
> +
> +	/**
> +	 * print a message
> +	 */
> +	private void print(String msg) {
> +		DistributedLogger.print("DistributedSDFDirector: " + msg,
> +				DistributedLogger.HIGH);
> +	}
> +
> +	private class FireThread extends Thread {
> +		SDFDirector dir;
> +		public boolean done = false;
> +
> +		public FireThread() {
> +		}
> +
> +		public void run() {
> +			try {
> +				print("firing in thread");
> +				firefire();
> +				done = true;
> +			} catch (Exception e) {
> +				System.out.println("Error running fire: " + e.getMessage());
> +			}
> +		}
> +
> +	}
> +}
> 
> Added: trunk/src/org/kepler/distributed/DistributedServer.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/DistributedServer.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/DistributedServer.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,208 @@
> +//  Copyright (c) 2007, Regents of the University of California
> +//  All rights reserved.
> +//
> +//  Redistribution and use in source and binary forms, with or without
> +//  modification, are permitted provided that the following conditions are
> +//  met:
> +//
> +//    * Redistributions of source code must retain the above copyright notice,
> +//  this list of conditions and the following disclaimer.
> +//    * Redistributions in binary form must reproduce the above copyright
> +//  notice, this list of conditions and the following disclaimer in the
> +//  documentation and/or other materials provided with the distribution.
> +//    * Neither the name of the University of California, San Diego (UCSD) nor
> +//  the names of its contributors may be used to endorse or promote products
> +//  derived from this software without specific prior written permission.
> +//
> +//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
> +//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> +//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> +//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> +//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
> +//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
> +//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
> +//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
> +//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> +//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
> +//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +//
> +//
> +//  FILE
> +//  DistributedServer.java  -
> +//      org.ecoinformatics.seek.distrib.DistributedServer
> +//
> +//  CLASS HIERARCHY
> +//
> +//      |
> +//      +-org.ecoinformatics.seek.distrib.DistributedServer
> +//
> +//  PRINCIPAL AUTHOR
> +//  Lucas Gilbert, SDSC/UCSD
> +//
> +//
> +package org.kepler.distributed;
> +
> +import java.io.IOException;
> +import java.rmi.Remote;
> +import java.rmi.RemoteException;
> +import java.util.List;
> +import java.util.Map;
> +
> +import ptolemy.data.Token;
> +
> +/**
> + * A distributed server to execute ptolemy actors in a distributed manner.
> + * 
> + * '$Author: aschultz $' '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + * '$Revision: 16353 $'
> + */
> +public interface DistributedServer extends Remote {
> +	/**
> +	 * Adds tokens to the remote workflow. Shortcut for,
> +	 * InputCommunicationStubActor.put( Token[] tokens )
> +	 */
> +	public void put(Token[] tokens, String portName) throws RemoteException,
> +			IOException;
> +
> +	/**
> +	 * The master/recieving workflow should call this method and have a thread
> +	 * waiting for the return, if more iteration results are expected. Shortcut
> +	 * for, OutputCommunicationStubActor.get( )
> +	 */
> +	public Token[] get(String portName) throws RemoteException, IOException;
> +
> +	/**
> +	 * Loads this actor into the remote workflow
> +	 * 
> +	 * @param inputPortTypeMap
> +	 * @param actorMOML
> +	 * @param attList
> +	 * @throws Exception
> +	 *             if there is an exception while parsing the Moml of
> +	 *             distributedActor
> +	 */
> +	public void loadActor(String actorName, String distributedActorMOML,
> +			List newAttMap, Map inputPortTypeMap, SlaveAccessToken token)
> +			throws RemoteException, InvalidTokenException;
> +
> +	// TODO unnecessary?
> +	// run automatically called and workflow blocks until tokens put into Input
> +	// actor?
> +	public void run(SlaveAccessToken token) throws InvalidTokenException,
> +			Exception;
> +
> +	/**
> +	 * called when the master is ready for the slave to run
> +	 */
> +	public void ready(SlaveAccessToken token) throws InvalidTokenException,
> +			RemoteException, IOException;
> +
> +	// ///////////////////////////////////////////////////////////////////////////
> +	// These methods were formerly in the JobController interface. the
> +	// DistributedServer interface and the JobController interface are now
> +	// merged
> +	// to make it easier to make calls to both, since SlaveController implements
> +	// both interfaces.
> +
> +	/**
> +	 * return the status of the job. @See SlaveController for a list of return
> +	 * codes.
> +	 */
> +	public int getSlaveState(Credential credential) throws RemoteException,
> +			IOException, CredentialException;
> +
> +	/**
> +	 * return the status of the job. @See SlaveController for a list of return
> +	 * codes.
> +	 */
> +	public int getJobStatus(Credential credential) throws RemoteException,
> +			IOException, CredentialException;
> +
> +	/**
> +	 * return the progress the current job if there is one. the return value is
> +	 * an integer between -1 and 100 where -1 mean an error has occured, 0 is
> +	 * "just started" and 100 is "finished". An implementer does not necessarily
> +	 * have to return any number between 0 and 100 if progress cannot be
> +	 * determined, but should always return 0 or 100 if a job is just begun or
> +	 * is finished.
> +	 */
> +	public int progress(Credential credential) throws RemoteException,
> +			IOException, CredentialException;
> +
> +	/**
> +	 * Starts a job that has been stopped. Does nothing if the job is already
> +	 * started.
> +	 */
> +	public void start(Credential credential) throws RemoteException,
> +			IOException, CredentialException;
> +
> +	/**
> +	 * Stops a job that is running. Does nothing if the job is already stopped.
> +	 */
> +	public void stop(Credential credential) throws RemoteException,
> +			IOException, CredentialException;
> +
> +	/**
> +	 * restarts a job. If a job is not restartable due to data contraints, or
> +	 * other reason, this should throw a NotRestartableException
> +	 */
> +	public void restart(Credential credential) throws RemoteException,
> +			IOException, NotRestartableException, CredentialException;
> +
> +	/**
> +	 * authenticate a user and return a credential which can be passed to the
> +	 * other functions of this interface to prove authentication.
> +	 */
> +	public Credential authenticate(String username, String password)
> +			throws RemoteException, IOException,
> +			org.kepler.authentication.AuthenticationException;
> +
> +	/**
> +	 * return the current cpu usage which should be an integer between 0 and
> +	 * 100.
> +	 */
> +	public int getCPUUsage() throws RemoteException, IOException;
> +
> +	/**
> +	 * return the current memory usage
> +	 */
> +	public MemoryUsage getMemoryUsage() throws RemoteException, IOException;
> +
> +	/**
> +	 * returns true if the implementing node is available to accept jobs, false
> +	 * otherwise.
> +	 */
> +	public boolean available() throws RemoteException, IOException;
> +
> +	/**
> +	 * get the username of the current user
> +	 */
> +	public String getCurrentUser() throws RemoteException, IOException;
> +
> +	/**
> +	 * request to use the slave for execution. this method returns a credential
> +	 * which must be used to make requests to the slave. when the credential
> +	 * expires, the slave will cancel any running jobs and revert to being
> +	 * available to other clients. If a job is still running, the expiration
> +	 * time can be incremented by calling requestSlave() additional times.
> +	 */
> +	public SlaveAccessToken requestSlave(Credential c) throws RemoteException,
> +			IOException;
> +
> +	/**
> +	 * release the slave to be used by other clients
> +	 */
> +	public void releaseSlave() throws RemoteException, IOException;
> +
> +	/**
> +	 * returns the host name of the slave
> +	 */
> +	public String getHostname() throws RemoteException, IOException;
> +
> +	/**
> +	 * returns the lsid of the registry document that is registering this node.
> +	 * if the node is not registered, it returns null
> +	 */
> +	public String getRegistryId() throws RemoteException, IOException;
> +
> +}
> 
> Added: trunk/src/org/kepler/distributed/DistributedServerAttribute.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/DistributedServerAttribute.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/DistributedServerAttribute.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,65 @@
> +/**
> + * For Details: http://kepler.ecoinformatics.org
> + *
> + *  '$RCSfile$'
> + *  Copyright: 2000 Regents of the University of California and the
> + *              National Center for Ecological Analysis and Synthesis
> + *    Authors: @authors@
> + *    Release: @release@
> + *
> + *   '$Author: aschultz $'
> + *     '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + * '$Revision: 16353 $'
> + *
> + * Copyright (c) 2003 The Regents of the University of California.
> + * All rights reserved.
> + *
> + * Permission is hereby granted, without written agreement and without
> + * license or royalty fees, to use, copy, modify, and distribute this
> + * software and its documentation for any purpose, provided that the
> + * above copyright notice and the following two paragraphs appear in
> + * all copies of this software.
> + *
> + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
> + * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
> + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
> + * IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY
> + * OF SUCH DAMAGE.
> + *
> + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
> + * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY
> + * OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
> + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
> + */
> +
> +package org.kepler.distributed;
> +
> +import ptolemy.kernel.util.IllegalActionException;
> +import ptolemy.kernel.util.NameDuplicationException;
> +import ptolemy.kernel.util.NamedObj;
> +import ptolemy.kernel.util.StringAttribute;
> +import ptolemy.kernel.util.Workspace;
> +
> +/**
> + * This is a placeholder for distributed server information within the
> + * DistributedCompositeActor
> + */
> +public class DistributedServerAttribute extends StringAttribute {
> +	public DistributedServerAttribute() {
> +		super();
> +		setPersistent(true);
> +	}
> +
> +	public DistributedServerAttribute(Workspace w) {
> +		super(w);
> +		setPersistent(true);
> +	}
> +
> +	public DistributedServerAttribute(NamedObj container, String name)
> +			throws IllegalActionException, NameDuplicationException {
> +		super(container, name);
> +		setPersistent(true);
> +	}
> +}
> 
> Added: trunk/src/org/kepler/distributed/DistributionFactory.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/DistributionFactory.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/DistributionFactory.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,205 @@
> +//  Copyright (c) 2007, Regents of the University of California
> +//  All rights reserved.
> +//
> +//  Redistribution and use in source and binary forms, with or without
> +//  modification, are permitted provided that the following conditions are
> +//  met:
> +//
> +//    * Redistributions of source code must retain the above copyright notice,
> +//  this list of conditions and the following disclaimer.
> +//    * Redistributions in binary form must reproduce the above copyright
> +//  notice, this list of conditions and the following disclaimer in the
> +//  documentation and/or other materials provided with the distribution.
> +//    * Neither the name of the University of California, San Diego (UCSD) nor
> +//  the names of its contributors may be used to endorse or promote products
> +//  derived from this software without specific prior written permission.
> +//
> +//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
> +//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> +//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> +//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> +//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
> +//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
> +//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
> +//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
> +//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> +//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
> +//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +//
> +//
> +//  FILE
> +//  DistributionFactory.java  -
> +//     org.ecoinformatics.seek.distrib.DistributionFactory
> +//
> +//
> +//  PRINCIPAL AUTHOR
> +//  Lucas Gilbert, SDSC/UCSD
> +//
> +//
> +package org.kepler.distributed;
> +
> +import java.lang.reflect.Constructor;
> +import java.lang.reflect.InvocationTargetException;
> +import java.net.URI;
> +import java.rmi.RemoteException;
> +import java.util.HashMap;
> +
> +/**
> + * '$Author: aschultz $' '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + * '$Revision: 16353 $'
> + */
> +class DistributionFactory {
> +	/**
> +	 * Registration for other file types so they are known and used by the
> +	 * FileFactory methods.
> +	 * 
> +	 * 
> +	 * TODO Not sure about making the registration public yet.
> +	 */
> +	static HashMap classToType = new HashMap();
> +	static {
> +		// TODO move to JiniController?
> +		// register JiniController
> +		// registerController( JiniController.class,
> +		// DistributedCompositeActor.class, URI.class
> +		// );
> +	}
> +
> +	// ----------------------------------------------------------------------
> +	// Utility Methods
> +	// ----------------------------------------------------------------------
> +	// TODO not sure what I want to make public
> +	// the (General..., General... ...)
> +	// would require a valid connection for some controller
> +	// the class one isn't strict enough
> +	/**
> +	 * Stores these class types for later use. Does not use the values from this
> +	 * object. The connection of a MasterController will not be used when
> +	 * creating another.
> +	 */
> +	static void registerController(MasterController controller,
> +			DistributedCompositeActor actor, URI configFile) {
> +		registerController(controller.getClass(), actor.getClass(), configFile
> +				.getClass());
> +	}
> +
> +	/**
> +	 * Stores these class types for later use. Does not use the values from this
> +	 * object. The connection of a MasterController will not be used when
> +	 * creating another.
> +	 */
> +	static void registerController(Class controller, Class actor,
> +			Class configFile) {
> +		if (controller == null) {
> +			throw new NullPointerException("Controller cannot be null");
> +		}
> +		if (actor != null) {
> +			classToType.put(controller, actor);
> +		}
> +		if (configFile != null) {
> +			classToType.put(actor, configFile);
> +		}
> +	}
> +
> +	/**
> +	 * Returns true iff <code>controller</code> been registered.
> +	 */
> +	static boolean isControllerRegistered(MasterController controller) {
> +		return classToType.containsKey(controller.getClass());
> +	}
> +
> +	private static Object createObject(Constructor constructor,
> +			Object[] arguments) throws RemoteException {
> +		try {
> +			return constructor.newInstance(arguments);
> +		} catch (InstantiationException e) {
> +			// TODO
> +			e.printStackTrace();
> +		} catch (IllegalAccessException e) {
> +			e.printStackTrace();
> +		} catch (IllegalArgumentException e) {
> +			e.printStackTrace();
> +		} catch (InvocationTargetException e) {
> +			Throwable x = e.getCause();
> +			if (x instanceof RemoteException)
> +				throw (RemoteException) x;
> +			e.printStackTrace();
> +		}
> +		return null;
> +	}
> +
> +	private static Object fromMap(Object key, Object arg)
> +			throws RemoteException {
> +		return fromMap(key, new Object[] { arg });
> +	}
> +
> +	// first argument is the key for the Hashmap
> +	private static Object fromMap(Object key, Object[] args)
> +			throws RemoteException {
> +		if ((key != null) && (args != null)) {
> +			Object main = classToType.get(key);
> +			if (main == null)
> +				return null;
> +			Class[] argsClass = new Class[args.length];
> +			for (int i = 0; i < args.length; i++) {
> +				argsClass[i] = args[i].getClass();
> +			}
> +			try {
> +				return ((Class) main).getConstructor(argsClass).newInstance(
> +						args);
> +			} catch (NoSuchMethodException e) {
> +				// TODO
> +				e.printStackTrace();
> +			} catch (InstantiationException e) {
> +				e.printStackTrace();
> +			} catch (IllegalAccessException e) {
> +				e.printStackTrace();
> +			} catch (IllegalArgumentException e) {
> +				e.printStackTrace();
> +			} catch (InvocationTargetException e) {
> +				Throwable x = e.getCause();
> +				if (x instanceof RemoteException)
> +					throw (RemoteException) x;
> +				e.printStackTrace();
> +			}
> +		}
> +		return null;
> +	}
> +
> +	// ----------------------------------------------------------------------
> +	// Factory Methods
> +	// ----------------------------------------------------------------------
> +	/*
> +	 * static MasterController newMasterController( DistributedCompositeActor
> +	 * actor, URI configFile ) throws IllegalArgumentException, RemoteException
> +	 * { return new MasterController( actor, new InputStream(configFile) ); }
> +	 */
> +
> +	static SlaveController newSlaveController(DistributedCompositeActor actor,
> +			URI configFile) throws IllegalArgumentException, RemoteException {
> +		// TODO
> +		SlaveController service = null;
> +		// SlaveController service = new JiniController( actor, configFile );
> +		// (SlaveController) fromMap( read( configFile ), new Object[]{actor,
> +		// configFile} );
> +		if (service == null) {
> +			// TODODefault to ?
> +			// return
> +		}
> +		return service;
> +	}
> +}
> +
> +/*
> + * try { Class serviceDefinition; //TODO hashmap - if/else for registration of
> + * others serviceDefinition = JiniController.class; Class[] argsClass = new
> + * Class[] { DistributedCompositeActor.class, URI.class }; Object[] args = new
> + * Object[] { actor, configFile }; Constructor constructor; constructor =
> + * serviceDefinition.getConstructor(argsClass); service = (SlaveController)
> + * constructor.newInstance(args); } catch (InstantiationException e) { //TODO
> + * exceptions, probably just convert them all into an IllegalArgumentException
> + * e.printStackTrace(); } catch (IllegalAccessException e) {
> + * e.printStackTrace(); } catch (InvocationTargetException e) {
> + * e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace();
> + * } return service; } }
> + */
> \ No newline at end of file
> 
> Added: trunk/src/org/kepler/distributed/InvalidTokenException.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/InvalidTokenException.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/InvalidTokenException.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,57 @@
> +//  Copyright (c) 2007, Regents of the University of California
> +//  All rights reserved.
> +//
> +//  Redistribution and use in source and binary forms, with or without
> +//  modification, are permitted provided that the following conditions are
> +//  met:
> +//
> +//    * Redistributions of source code must retain the above copyright notice,
> +//  this list of conditions and the following disclaimer.
> +//    * Redistributions in binary form must reproduce the above copyright
> +//  notice, this list of conditions and the following disclaimer in the
> +//  documentation and/or other materials provided with the distribution.
> +//    * Neither the name of the University of California, San Diego (UCSD) nor
> +//  the names of its contributors may be used to endorse or promote products
> +//  derived from this software without specific prior written permission.
> +//
> +//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
> +//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> +//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> +//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> +//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
> +//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
> +//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
> +//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
> +//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> +//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
> +//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +//
> +//  PRINCIPAL AUTHOR
> +//  Chad Berkley
> +//
> +//
> +package org.kepler.distributed;
> +
> +/**
> + * '$Author: aschultz $' '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + * '$Revision: 16353 $'
> + * 
> + * Exception for errors related to SlaveAccessTokens
> + */
> +public class InvalidTokenException extends Exception {
> +	public InvalidTokenException() {
> +		super();
> +	}
> +
> +	public InvalidTokenException(String message) {
> +		super(message);
> +	}
> +
> +	public InvalidTokenException(String message, Throwable cause) {
> +		super(message, cause);
> +	}
> +
> +	public InvalidTokenException(Throwable cause) {
> +		super(cause);
> +	}
> +}
> 
> Added: trunk/src/org/kepler/distributed/JobController.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/JobController.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/JobController.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,131 @@
> +//  Copyright (c) 2007, Regents of the University of California
> +//  All rights reserved.
> +//
> +//  Redistribution and use in source and binary forms, with or without
> +//  modification, are permitted provided that the following conditions are
> +//  met:
> +//
> +//    * Redistributions of source code must retain the above copyright notice,
> +//  this list of conditions and the following disclaimer.
> +//    * Redistributions in binary form must reproduce the above copyright
> +//  notice, this list of conditions and the following disclaimer in the
> +//  documentation and/or other materials provided with the distribution.
> +//    * Neither the name of the University of California, San Diego (UCSD) nor
> +//  the names of its contributors may be used to endorse or promote products
> +//  derived from this software without specific prior written permission.
> +//
> +//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
> +//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> +//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> +//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> +//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
> +//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
> +//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
> +//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
> +//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> +//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
> +//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +//
> +//  PRINCIPAL AUTHOR
> +//  Chad Berkley
> +//
> +//
> +package org.kepler.distributed;
> +
> +import java.io.IOException;
> +import java.rmi.Remote;
> +import java.rmi.RemoteException;
> +
> +/**
> + * '$Author: aschultz $' '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + * '$Revision: 16353 $'
> + * 
> + * An interface for controlling remote jobs
> + */
> +public interface JobController extends Remote {
> +	/**
> +	 * return the status of the job. @See SlaveController for a list of return
> +	 * codes.
> +	 */
> +	public int getSlaveState(Credential credential) throws RemoteException,
> +			IOException, CredentialException;
> +
> +	/**
> +	 * return the status of the job. @See SlaveController for a list of return
> +	 * codes.
> +	 */
> +	public int getJobStatus(Credential credential) throws RemoteException,
> +			IOException, CredentialException;
> +
> +	/**
> +	 * return the progress the current job if there is one. the return value is
> +	 * an integer between -1 and 100 where -1 mean an error has occured, 0 is
> +	 * "just started" and 100 is "finished". An implementer does not necessarily
> +	 * have to return any number between 0 and 100 if progress cannot be
> +	 * determined, but should always return 0 or 100 if a job is just begun or
> +	 * is finished.
> +	 */
> +	public int progress(Credential credential) throws RemoteException,
> +			IOException, CredentialException;
> +
> +	/**
> +	 * Starts a job that has been stopped. Does nothing if the job is already
> +	 * started.
> +	 */
> +	public void start(Credential credential) throws RemoteException,
> +			IOException, CredentialException;
> +
> +	/**
> +	 * Stops a job that is running. Does nothing if the job is already stopped.
> +	 */
> +	public void stop(Credential credential) throws RemoteException,
> +			IOException, CredentialException;
> +
> +	/**
> +	 * restarts a job. If a job is not restartable due to data contraints, or
> +	 * other reason, this should throw a NotRestartableException
> +	 */
> +	public void restart(Credential credential) throws RemoteException,
> +			IOException, NotRestartableException, CredentialException;
> +
> +	/**
> +	 * authenticate a user and return a credential which can be passed to the
> +	 * other functions of this interface to prove authentication.
> +	 */
> +	public Credential authenticate(String username, String password)
> +			throws RemoteException, IOException,
> +			org.kepler.authentication.AuthenticationException;
> +
> +	/**
> +	 * return the current cpu usage which should be an integer between 0 and
> +	 * 100.
> +	 */
> +	public int getCPUUsage() throws RemoteException, IOException;
> +
> +	/**
> +	 * return the current memory usage
> +	 */
> +	public MemoryUsage getMemoryUsage() throws RemoteException, IOException;
> +
> +	/**
> +	 * returns true if the implementing node is available to accept jobs, false
> +	 * otherwise.
> +	 */
> +	public boolean available() throws RemoteException, IOException;
> +
> +	/**
> +	 * request to use the slave for execution. this method returns a credential
> +	 * which must be used to make requests to the slave. when the credential
> +	 * expires, the slave will cancel any running jobs and revert to being
> +	 * available to other clients. If a job is still running, the expiration
> +	 * time can be incremented by calling requestSlave() additional times.
> +	 */
> +	public SlaveAccessToken requestSlave(Credential c) throws RemoteException,
> +			IOException;
> +
> +	/**
> +	 * release the slave to be used by other clients
> +	 */
> +	public void releaseSlave() throws RemoteException, IOException;
> +
> +}
> 
> Added: trunk/src/org/kepler/distributed/KeplerRemoteJobMonitorServlet.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/KeplerRemoteJobMonitorServlet.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/KeplerRemoteJobMonitorServlet.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,1083 @@
> +/**
> + *    '$RCSfile$'
> + *
> + *     '$Author: aschultz $'
> + *       '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + *   '$Revision: 16353 $'
> + *
> + *  For Details: http://kepler.ecoinformatics.org
> + *
> + * Copyright (c) 2007 The Regents of the University of California.
> + * All rights reserved.
> + *
> + * Permission is hereby granted, without written agreement and without
> + * license or royalty fees, to use, copy, modify, and distribute this
> + * software and its documentation for any purpose, provided that the
> + * above copyright notice and the following two paragraphs appear in
> + * all copies of this software.
> + *
> + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
> + * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
> + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
> + * IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY
> + * OF SUCH DAMAGE.
> + *
> + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
> + * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY
> + * OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
> + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
> + */
> +
> +package org.kepler.distributed;
> +
> +import java.io.File;
> +import java.io.FileReader;
> +import java.io.IOException;
> +import java.io.PrintWriter;
> +import java.rmi.Naming;
> +import java.rmi.RemoteException;
> +import java.util.Enumeration;
> +import java.util.Hashtable;
> +import java.util.ResourceBundle;
> +import java.util.StringTokenizer;
> +import java.util.Timer;
> +
> +import javax.servlet.ServletConfig;
> +import javax.servlet.ServletException;
> +import javax.servlet.http.HttpServlet;
> +import javax.servlet.http.HttpServletRequest;
> +import javax.servlet.http.HttpServletResponse;
> +import javax.servlet.http.HttpSession;
> +
> +import org.ecoinformatics.ecogrid.client.RegistryServiceClient;
> +import org.ecoinformatics.ecogrid.registry.stub.RegistryEntryType;
> +import org.kepler.objectmanager.lsid.KeplerLSID;
> +import org.kepler.objectmanager.repository.EcogridRepository;
> +import org.kepler.objectmanager.repository.Repository;
> +import org.kepler.objectmanager.repository.RepositoryException;
> +import org.kepler.objectmanager.repository.RepositoryManager;
> +import org.kepler.objectmanager.repository.EcogridRepository.RegistryClientContainer;
> +
> +import com.oreilly.servlet.multipart.FilePart;
> +import com.oreilly.servlet.multipart.MultipartParser;
> +import com.oreilly.servlet.multipart.ParamPart;
> +import com.oreilly.servlet.multipart.Part;
> +
> +/**
> + * Servlet to handle incoming requests for remote job information
> + * 
> + *@author berkley
> + *@created June 28, 2007
> + */
> +public class KeplerRemoteJobMonitorServlet extends HttpServlet {
> +	// this is the default location for the access list for admins
> +	private static String ACCESSLIST = "/usr/local/devtools/jakarta-tomcat/webapps/KeplerRemoteJobMonitorServlet/servlet-access-list";
> +	private static Hashtable sessionHash = new Hashtable();
> +	private Timer timer = null;
> +	private static boolean sitemapScheduled;
> +
> +	/**
> +	 * Initialize the servlet by creating appropriate database connections
> +	 * 
> +	 *@param config
> +	 *            Description of the Parameter
> +	 *@exception ServletException
> +	 *                Description of the Exception
> +	 */
> +	public void init(ServletConfig config) throws ServletException {
> +		print("Initializing KeplerRemoteJobMonitorServlet");
> +		super.init(config);
> +	}
> +
> +	/**
> +	 * Close all db connections from the pool
> +	 */
> +	public void destroy() {
> +		print("Destroying KeplerRemoteJobMonitorServlet");
> +	}
> +
> +	/**
> +	 * Handle "GET" method requests from HTTP clients
> +	 * 
> +	 *@param request
> +	 *            Description of the Parameter
> +	 *@param response
> +	 *            Description of the Parameter
> +	 *@exception ServletException
> +	 *                Description of the Exception
> +	 *@exception IOException
> +	 *                Description of the Exception
> +	 */
> +	public void doGet(HttpServletRequest request, HttpServletResponse response)
> +			throws ServletException, IOException {
> +		handleGetOrPost(request, response);
> +	}
> +
> +	/**
> +	 * Handle "POST" method requests from HTTP clients
> +	 * 
> +	 *@param request
> +	 *            Description of the Parameter
> +	 *@param response
> +	 *            Description of the Parameter
> +	 *@exception ServletException
> +	 *                Description of the Exception
> +	 *@exception IOException
> +	 *                Description of the Exception
> +	 */
> +	public void doPost(HttpServletRequest request, HttpServletResponse response)
> +			throws ServletException, IOException {
> +		handleGetOrPost(request, response);
> +	}
> +
> +	/**
> +	 * Control servlet response depending on the action parameter specified
> +	 * 
> +	 *@param request
> +	 *            Description of the Parameter
> +	 *@param response
> +	 *            Description of the Parameter
> +	 *@exception ServletException
> +	 *                Description of the Exception
> +	 *@exception IOException
> +	 *                Description of the Exception
> +	 */
> +	private void handleGetOrPost(HttpServletRequest request,
> +			HttpServletResponse response) throws ServletException, IOException {
> +		String ctype = request.getContentType();
> +		if (ctype != null && ctype.startsWith("multipart/form-data")) {
> +			handleMultipartForm(request, response);
> +		} else {
> +			String name = null;
> +			String[] value = null;
> +			Hashtable params = new Hashtable();
> +
> +			Enumeration paramlist = request.getParameterNames();
> +			while (paramlist.hasMoreElements()) {
> +				name = (String) paramlist.nextElement();
> +				value = request.getParameterValues(name);
> +				params.put(name, value);
> +			}
> +
> +			// handle param is emptpy
> +			if (params.isEmpty() || params == null) {
> +				return;
> +			}
> +
> +			String action = ((String[]) params.get("action"))[0];
> +			print("Action is: " + action);
> +
> +			// This block handles session management for the servlet
> +			// by looking up the current session information for all actions
> +			// other than "login" and "logout"
> +			String username = null;
> +			String password = null;
> +			String[] groupnames = null;
> +			String sess_id = null;
> +			name = null;
> +
> +			// handle login action
> +			if (action.equals("login")) {
> +				PrintWriter out = response.getWriter();
> +				handleLoginAction(out, params, request, response);
> +				out.close();
> +			} else if (action.equals("logout")) {
> +				PrintWriter out = response.getWriter();
> +				handleLogoutAction(out, params, request, response);
> +				out.close();
> +			}
> +
> +			// Now that we know the session is valid, we can delegate the
> +			// request
> +			// to a particular action handler
> +			if (action.equals("showSlaveStatus")) {
> +				PrintWriter out = response.getWriter();
> +				// query the registry to find the slaves that are currently
> +				// online
> +				handleShowSlaveStatusAction(out, params, request, response);
> +			} else if (action.equals("removeNode")) {
> +				PrintWriter out = response.getWriter();
> +				handleAdminAction(out, params, request, response, action);
> +			} else if (action.equals("stopNode")) {
> +				PrintWriter out = response.getWriter();
> +				handleAdminAction(out, params, request, response, action);
> +			} else {
> +				PrintWriter out = response.getWriter();
> +				out.println("<?xml version=\"1.0\"?>");
> +				out.println("<error>");
> +				out
> +						.println("Error: action not registered.  Please report this error.");
> +				out.println("</error>");
> +				out.close();
> +			}
> +		}
> +	}
> +
> +	/**
> +	 * handle an action that requires login and admin privs
> +	 */
> +	private void handleAdminAction(PrintWriter out, Hashtable params,
> +			HttpServletRequest request, HttpServletResponse response,
> +			String action) {
> +		// get the session info
> +		HttpSession session = request.getSession(true);
> +		String currentSessionid = session.getId();
> +		session = (HttpSession) sessionHash.get(currentSessionid);
> +
> +		// get the confirmed variable
> +		boolean confirmed = false;
> +		String confirmedStr = null;
> +		if (params.containsKey("confirmed")) {
> +			confirmedStr = ((String[]) params.get("confirmed"))[0];
> +		}
> +		String serviceId = ((String[]) params.get("serviceId"))[0];
> +		String endpoint = ((String[]) params.get("endpoint"))[0];
> +
> +		if (confirmedStr != null
> +				&& confirmedStr.trim().toLowerCase().equals("true")) {
> +			confirmed = true;
> +		}
> +
> +		if (session == null) {
> +			// the user is not logged in, redirect them to the login page
> +			String redirect = getRedirect("/KeplerRemoteJobMonitorServlet");
> +			out.print(redirect);
> +			return;
> +		}
> +
> +		// we know the user is logged in. now check if they are an admin user
> +		String username = (String) session.getAttribute("username");
> +		boolean adminUser = checkAdminUser(username);
> +
> +		if (!adminUser) {
> +			throwException(out, "You do not have permission to perform the "
> +					+ action + " action.", "handleAdminAction", null);
> +		}
> +
> +		// redirect this to the appropriate action handler method
> +		if (action.equals("removeNode")) {
> +			if (!confirmed) {
> +				String targetUrl = "/KeplerRemoteJobMonitorServlet/jobMonitor?action="
> +						+ "removeNode&serviceId="
> +						+ serviceId
> +						+ "&endpoint="
> +						+ endpoint + "&confirmed=true";
> +				String returnUrl = "/KeplerRemoteJobMonitorServlet/jobMonitor?action=showSlaveStatus";
> +				String message = "Removing the node will make it impossible for other "
> +						+ "Kepler clients to find this node.  Are you sure you want to do this?";
> +				displayConfirmPage(targetUrl, returnUrl, message, out);
> +			} else {
> +				handleRemoveNodeAction(out, params, request, response);
> +			}
> +		} else if (action.equals("stopNode")) {
> +			if (!confirmed) {
> +				String targetUrl = "/KeplerRemoteJobMonitorServlet/jobMonitor?"
> +						+ "action=stopNode&serviceId=" + serviceId
> +						+ "&endpoint=" + endpoint + "&confirmed=true";
> +				String returnUrl = "/KeplerRemoteJobMonitorServlet/jobMonitor?action=showSlaveStatus";
> +				String message = "Stopping the execution of the slave might cause "
> +						+ "any Kepler clients relying on it to fail.  Are you sure you want "
> +						+ "to do this?";
> +				displayConfirmPage(targetUrl, returnUrl, message, out);
> +			} else {
> +				handleStopNodeAction(out, params, request, response);
> +			}
> +		} else {
> +			throwException(out, "Action " + action
> +					+ " not registered as admin "
> +					+ "action.  Please report this error.",
> +					"handleAdminAction", null);
> +		}
> +	}
> +
> +	/**
> +	 * handle the stopNode action
> +	 */
> +	private void handleStopNodeAction(PrintWriter out, Hashtable params,
> +			HttpServletRequest request, HttpServletResponse response) {
> +		HttpSession session = request.getSession(true);
> +		String currentSessionid = session.getId();
> +		session = (HttpSession) sessionHash.get(currentSessionid);
> +		String serviceId = ((String[]) params.get("serviceId"))[0];
> +		String endpoint = ((String[]) params.get("endpoint"))[0];
> +		String username = (String) session.getAttribute("username");
> +		String password = (String) session.getAttribute("password");
> +		// get an RMI fix on the endpoint and ask it nicely to stop doing
> +		// whatever it is doing
> +		try {
> +			// authenticate and get a credential for each host
> +			DistributedServer controller = (DistributedServer) Naming
> +					.lookup("rmi://" + endpoint + "/SlaveControllerInstance");
> +			Credential credential = null;
> +			// check to see if the user is already logged in to this slave
> +			credential = (Credential) session.getAttribute("credential-"
> +					+ endpoint);
> +			if (credential == null || credential.isExpired()) { // if the user
> +																// is not
> +																// already
> +																// logged in,
> +																// try to log in
> +				try {
> +					credential = controller.authenticate(username, password);
> +					session.setAttribute("credential-" + endpoint, credential);
> +				} catch (org.kepler.authentication.AuthenticationException authe) { // if
> +																					// we
> +																					// can't
> +																					// auth
> +																					// for
> +																					// this
> +																					// host,
> +																					// go
> +																					// on
> +																					// to
> +																					// the
> +																					// next
> +					throwException(out, "Could not authenticate user "
> +							+ username + " against host " + endpoint + ": "
> +							+ authe.getMessage(), "handleStopNodeAction", authe);
> +					return;
> +				}
> +			}
> +
> +			// now try to stop the execution
> +			controller.stop(credential);
> +
> +			// redirect the user back to the status page
> +			String redirect = getRedirect("/KeplerRemoteJobMonitorServlet/jobMonitor?action=showSlaveStatus");
> +			out.print(redirect);
> +		} catch (Exception e) {
> +			throwException(out, "Could not stop slave execution: "
> +					+ e.getMessage(), "handleStopNodeAction", e);
> +		}
> +	}
> +
> +	/**
> +	 * deregister a node from the registry
> +	 */
> +	private void handleRemoveNodeAction(PrintWriter out, Hashtable params,
> +			HttpServletRequest request, HttpServletResponse response) {
> +		HttpSession session = request.getSession(true);
> +		String serviceId = ((String[]) params.get("serviceId"))[0];
> +		print("removing serviceId " + serviceId);
> +		// remove the node
> +		try {
> +			RepositoryManager repMan = RepositoryManager.getInstance();
> +			Repository rep = repMan.getRepository("keplerRepository");
> +			if (!(rep instanceof EcogridRepository)) {
> +				throw new RepositoryException(
> +						"The repository must be an EcogridRepository.");
> +			}
> +			KeplerLSID lsid = new KeplerLSID(serviceId);
> +			EcogridRepository ecorep = (EcogridRepository) rep;
> +			ecorep.removeRegistryEntry(lsid);
> +			String redirect = getRedirect("/KeplerRemoteJobMonitorServlet/jobMonitor?action=showSlaveStatus");
> +			out.print(redirect);
> +		} catch (Exception e) {
> +			throwException(out, "Could not deregister with the ecogrid: "
> +					+ e.getMessage(), "handleRemoveNodeAction", e);
> +		}
> +	}
> +
> +	/**
> +	 * show the status of all slaves currently registered in the earthgrid
> +	 * registry
> +	 */
> +	private void handleShowSlaveStatusAction(PrintWriter out, Hashtable params,
> +			HttpServletRequest request, HttpServletResponse response) {
> +		// make sure the user is logged in and can access this information
> +		HttpSession session = request.getSession(true);
> +		String currentSessionid = session.getId();
> +		session = (HttpSession) sessionHash.get(currentSessionid);
> +
> +		if (session == null) {
> +			// throwException(out,
> +			// "You are not logged in.  Please login, then try again.",
> +			// "handleShowSlaveStatusAction", null);
> +			String redirect = getRedirect("/KeplerRemoteJobMonitorServlet");
> +			out.print(redirect);
> +			return;
> +		}
> +
> +		// we know the user is logged in. now check if they are an admin user
> +		String ecogridsessionid = (String) sessionHash.get("ecogridSessionid");
> +		String username = (String) session.getAttribute("username");
> +		String password = (String) session.getAttribute("password");
> +		boolean adminUser = checkAdminUser(username);
> +
> +		try {
> +			// get the EcogridRepository
> +			EcogridRepository ecorep;
> +			ecorep = getEcogridRepository();
> +			RegistryClientContainer ecoclientcont = ecorep.getRegistryClient();
> +			RegistryServiceClient ecoclient = ecoclientcont.client;
> +			String sessionid = ecoclientcont.sessionid;
> +
> +			// query the registry
> +			// could also use ecogridsessionid here
> +			RegistryEntryType[] regentries = ecoclient.list(sessionid);
> +
> +			if (regentries == null) {
> +				// throwException(out, "There are no registry entries.",
> +				// "handleShowSlaveStatusAction", null);
> +				out
> +						.println("<html><head></head><body><h2>No Registry Entries Found</h2></body></html>");
> +				return;
> +			}
> +			out.println("<html><head></head><body>\n");
> +			out.println("<h2>Currently Registered Kepler Nodes</h2>\n");
> +			out
> +					.println("<table border=\"1\" cellpadding=\"2\" cellspacing=\"2\" "
> +							+ "width=\"100%\">");
> +			out
> +					.println("<tr><th>Host</th><th>Accepting New Jobs?</th>"
> +							+ "<th>Current User</th><th>Slave State</th><th>Job Status</th><th>Job Progress</th>"
> +							+ "<th>Memory Usage</th>");
> +			if (adminUser) {
> +				out.println("<th>Admin</th>\n");
> +			}
> +			out.println("</tr>\n");
> +			for (int i = 0; i < regentries.length; i++) {
> +				// get the id of each entry
> +				String id = regentries[i].getId();
> +				print("Registry Entry ID: " + id);
> +				if (id == null) {
> +					print("WARNING: Could not process the registry entry because it had no id.");
> +					continue;
> +				}
> +				// create an lsid out of the id
> +				ResourceBundle repositoryBundle = ResourceBundle
> +						.getBundle("ptolemy/configs/kepler/repositoryBundle");
> +				String lsidAuthority = repositoryBundle
> +						.getString("keplerRepository.lsidAuthority");
> +				String lsid = "urn:lsid:"
> +						+ lsidAuthority
> +						+ ":"
> +						+ id.substring(0, id.indexOf("."))
> +						+ ":"
> +						+ id
> +								.substring(id.indexOf(".") + 1, id
> +										.lastIndexOf(".")) + ":"
> +						+ id.substring(id.lastIndexOf(".") + 1, id.length());
> +				String endpoint = regentries[i].getEndPoint();
> +				try {
> +					// authenticate and get a credential for each host
> +					DistributedServer controller = (DistributedServer) Naming
> +							.lookup("rmi://" + endpoint
> +									+ "/SlaveControllerInstance");
> +					Credential credential = null;
> +					// check to see if the user is already logged in to this
> +					// slave
> +					credential = (Credential) session
> +							.getAttribute("credential-" + endpoint);
> +					if (credential == null || credential.isExpired()) { // if
> +																		// the
> +																		// user
> +																		// is
> +																		// not
> +																		// already
> +																		// logged
> +																		// in,
> +																		// try
> +																		// to
> +																		// log
> +																		// in
> +						try {
> +							credential = controller.authenticate(username,
> +									password);
> +							session.setAttribute("credential-" + endpoint,
> +									credential);
> +						} catch (org.kepler.authentication.AuthenticationException authe) { // if
> +																							// we
> +																							// can't
> +																							// auth
> +																							// for
> +																							// this
> +																							// host,
> +																							// go
> +																							// on
> +																							// to
> +																							// the
> +																							// next
> +							out
> +									.println("<tr><td>Cannot authenticate for this host: "
> +											+ authe.getMessage()
> +											+ "</td></tr>\n");
> +							continue;
> +						}
> +					}
> +
> +					String currentUser = "None";
> +					String slaveAvail = "Error getting data";
> +					String slaveState = "Error getting data";
> +					String jobStatus = "Error getting data";
> +					String jobProgress = "Error getting data";
> +					String memcpu = "Error getting data";
> +
> +					// catch all of these exceptions seperately so that the
> +					// failure of one
> +					// does not affect the data display of others.
> +
> +					try {
> +						currentUser = getCurrentUser(endpoint, credential,
> +								controller);
> +					} catch (Exception e) {
> +						print("Could not display the current user: "
> +								+ e.getMessage());
> +					}
> +
> +					try {
> +						slaveAvail = getSlaveAvailability(endpoint, credential,
> +								controller);
> +					} catch (Exception e) {
> +						print("Could not display slave availability: "
> +								+ e.getMessage());
> +					}
> +
> +					try {
> +						slaveState = getSlaveState(endpoint, credential,
> +								controller);
> +					} catch (Exception e) {
> +						print("Could not display slave state: "
> +								+ e.getMessage());
> +					}
> +
> +					try {
> +						jobStatus = getJobStatus(endpoint, credential,
> +								controller);
> +					} catch (Exception e) {
> +						print("Could not display job status: " + e.getMessage());
> +					}
> +
> +					try {
> +						jobProgress = getJobProgress(endpoint, credential,
> +								controller)
> +								+ "";
> +					} catch (Exception e) {
> +						print("Could not display job progress: "
> +								+ e.getMessage());
> +					}
> +
> +					try {
> +						memcpu = getMemCPUUsage(endpoint, credential,
> +								controller);
> +					} catch (Exception e) {
> +						print("Could not display slave mem/cpu usage: "
> +								+ e.getMessage());
> +					}
> +
> +					// got a credential, now we can get some info from the slave
> +					out.println("<tr>\n");
> +					// host
> +					out.println("<td>" + endpoint + "</td>\n");
> +					// is the host available for jobs?
> +					out.println("<td>" + slaveAvail + "</td>\n");
> +					// get the current user
> +					out.println("<td>" + currentUser + "</td>\n");
> +					// get the slave state
> +					out.println("<td>" + slaveState + "</td>\n");
> +					// job status
> +					out.println("<td>" + jobStatus + "</td>\n");
> +					// job progress
> +					out.println("<td>" + jobProgress + "</td>\n");
> +					// mem/cpu
> +					out.println("<td>" + memcpu + "</td>\n");
> +					if (adminUser) { // admin facilities get printed here
> +						out.println("<td>");
> +						out
> +								.println("<a href=\"/KeplerRemoteJobMonitorServlet/jobMonitor?action=removeNode&serviceId="
> +										+ lsid
> +										+ "&endpoint="
> +										+ endpoint
> +										+ "\">Deregister</a><br/>");
> +						if (slaveState.equals("JOB_RUNNING")) { // only show
> +																// stop if its
> +																// running
> +							out
> +									.println("<a href=\"/KeplerRemoteJobMonitorServlet/jobMonitor?action=stopNode&serviceId="
> +											+ lsid
> +											+ "&endpoint="
> +											+ endpoint
> +											+ "\">Stop</a><br/>");
> +						}
> +						out.println("</td>");
> +					}
> +					out.println("</tr>\n");
> +				} catch (Exception slaveException) {
> +					out.println("<td>No data for host " + endpoint);
> +					if (adminUser) {
> +						out
> +								.println("<a href=\"/KeplerRemoteJobMonitorServlet/jobMonitor?action=removeNode&serviceId="
> +										+ lsid
> +										+ "&endpoint="
> +										+ endpoint
> +										+ "\"> (Deregister)</a><br/>");
> +					}
> +					out.println("</td>\n");
> +					print("Error displaying data for host " + endpoint + ": "
> +							+ slaveException.getMessage());
> +					slaveException.printStackTrace();
> +				}
> +			}
> +			out.println("</table></body></html>");
> +			// build the results
> +			// print the results to the PrintWriter
> +		} catch (Exception e) {
> +			throwException(out,
> +					"Error showing slave status: " + e.getMessage(),
> +					"handleShowSlaveStatusAction", e);
> +			print("Error showing slave status: " + e.getMessage());
> +			e.printStackTrace();
> +			return;
> +		}
> +	}
> +
> +	/**
> +	 * returns the current user's DN, or "None" if there is no user
> +	 */
> +	private String getCurrentUser(String host, Credential credential,
> +			DistributedServer controller) throws RemoteException, IOException {
> +		String user = controller.getCurrentUser();
> +		return user;
> +	}
> +
> +	/**
> +	 * check to see if the host is accepting jobs
> +	 */
> +	private String getSlaveAvailability(String host, Credential credential,
> +			DistributedServer controller) throws RemoteException, IOException {
> +		// return "Yes" or "No"
> +		boolean b = controller.available();
> +		if (b) {
> +			return "Yes";
> +		}
> +		return "No";
> +	}
> +
> +	/**
> +	 * get the state of a slave
> +	 */
> +	private String getSlaveState(String host, Credential credential,
> +			DistributedServer controller) throws RemoteException, IOException,
> +			CredentialException {
> +		int s = controller.getSlaveState(credential);
> +		if (s == SlaveController.JOB_RUNNING) {
> +			return "JOB_RUNNING";
> +		} else {
> +			return "NO_JOB";
> +		}
> +	}
> +
> +	/**
> +	 * get the status of a running job (if there is one) for a host
> +	 */
> +	private String getJobStatus(String host, Credential credential,
> +			DistributedServer controller) throws RemoteException, IOException,
> +			CredentialException {
> +		int s = controller.getJobStatus(credential);
> +		if (s == SlaveController.JOB_STOPPED) {
> +			return "JOB_STOPPED";
> +		} else if (s == SlaveController.JOB_RUNNING) {
> +			return "JOB_RUNNING";
> +		} else if (s == SlaveController.JOB_RESTARTING) {
> +			return "JOB_RESTARTING";
> +		} else if (s == SlaveController.JOB_INITIALIZING) {
> +			return "JOB_INITIALIZING";
> +		} else {
> +			return "NO_JOB";
> +		}
> +	}
> +
> +	/**
> +	 * get the progress of a running job (if there is one). returns an integer
> +	 * between 0 and 100. 0 is a job that is not running, 100 is one that is
> +	 * done. Any integer inbetween could be interpreted as a percentage of the
> +	 * runtime, but this is just an estimate.
> +	 */
> +	private int getJobProgress(String host, Credential credential,
> +			DistributedServer controller) throws RemoteException, IOException,
> +			CredentialException {
> +		int s = controller.progress(credential);
> +		return s;
> +	}
> +
> +	/**
> +	 * get the memory and cpu usage for a host
> +	 */
> +	private String getMemCPUUsage(String host, Credential credential,
> +			DistributedServer controller) throws RemoteException, IOException,
> +			CredentialException {
> +		MemoryUsage mu = controller.getMemoryUsage();
> +		long used = mu.getUsed();
> +		long avail = mu.getAvailable();
> +		long max = mu.getMax();
> +		return "available: " + avail + "<br/>used: " + used
> +				+ "<br/>vm maximum: " + max + "<br/>";
> +	}
> +
> +	/**
> +	 * checks to see if the user is on the admin list. if the user is an admin,
> +	 * return true.
> +	 */
> +	private boolean checkAdminUser(String username) {
> +		try {
> +			// get the list
> +			File accessList = new File(ACCESSLIST);
> +			char[] c = new char[1024];
> +			StringBuffer accessListContents = new StringBuffer();
> +			if (accessList.exists()) {
> +				FileReader fr = new FileReader(accessList);
> +				int numread = fr.read(c, 0, 1024);
> +				while (numread != -1) {
> +					String s = new String(c, 0, numread);
> +					accessListContents.append(s);
> +					numread = fr.read(c, 0, 1024);
> +				}
> +			} else {
> +				print("ERROR: Could not find access list.  No admins registered. "
> +						+ "The list should be here: "
> +						+ ACCESSLIST
> +						+ ".  If it's not " + "please create it.");
> +			}
> +			// check the list
> +			StringTokenizer st = new StringTokenizer(accessListContents
> +					.toString());
> +			while (st.hasMoreTokens()) {
> +				String token = st.nextToken();
> +				if (token.trim().equals(username.trim())) {
> +					// found an admin
> +					print("user " + username + " IS an admin.");
> +					return true;
> +				}
> +			}
> +			// return the result.
> +			print("user " + username + " is NOT an admin.");
> +			return false;
> +		} catch (Exception e) {
> +			print("ERROR: could not check for admin users: " + e.getMessage());
> +			return false;
> +		}
> +	}
> +
> +	/**
> +	 * get the keplerRepository and make sure it's an ecogrid repository
> +	 */
> +	private EcogridRepository getEcogridRepository() throws Exception {
> +		RepositoryManager repMan = RepositoryManager.getInstance();
> +		Repository rep = repMan.getRepository("keplerRepository");
> +		if (!(rep instanceof EcogridRepository)) {
> +			throw new Exception(
> +					"The chosen repository is not an EcogridRepository. "
> +							+ "The repository must be an EcogridRepository.");
> +		}
> +		EcogridRepository ecorep = (EcogridRepository) rep;
> +		return ecorep;
> +	}
> +
> +	/**
> +	 * print an error message to the user and return
> +	 */
> +	private void throwException(PrintWriter out, String message,
> +			String methodName, Exception e) {
> +		print("Error in KeplerRemoteJobMonitorServlet." + methodName);
> +		print(message);
> +		if (e != null) {
> +			e.printStackTrace();
> +		}
> +		out.println("<?xml version=\"1.0\"?>");
> +		out.println("<error>");
> +		out.println("<message>" + message + "</message>");
> +		out.println("<method>KeplerRemoteJobMonitoryServlet." + methodName
> +				+ "</method>");
> +		out.println("<stacktrace>");
> +		if (e != null) {
> +			e.printStackTrace(out);
> +		}
> +		out.println("</stacktrace>");
> +		out.println("</error>");
> +	}
> +
> +	// LOGIN & LOGOUT SECTION
> +	/**
> +	 * Handle the login request. Create a new session object. Do user
> +	 * authentication through the session.
> +	 * 
> +	 *@param out
> +	 *            Description of the Parameter
> +	 *@param params
> +	 *            Description of the Parameter
> +	 *@param request
> +	 *            Description of the Parameter
> +	 *@param response
> +	 *            Description of the Parameter
> +	 */
> +	private void handleLoginAction(PrintWriter out, Hashtable params,
> +			HttpServletRequest request, HttpServletResponse response) {
> +		HttpSession session = request.getSession(true);
> +		try {
> +			if (params.get("username") == null) {
> +				response.setContentType("text/xml");
> +				throwException(out, "No username supplied with request.",
> +						"handleLoginAction", null);
> +				return;
> +			}
> +
> +			if (params.get("password") == null) {
> +				response.setContentType("text/xml");
> +				throwException(out, "No password supplied with request.",
> +						"handleLoginAction", null);
> +				return;
> +			}
> +
> +			String username = ((String[]) params.get("username"))[0];
> +			print("user " + username + " is trying to login");
> +			String password = ((String[]) params.get("password"))[0];
> +
> +			// login via the grid
> +			EcogridRepository ecorep = getEcogridRepository();
> +			String ecogridSessionid = ecorep.loginEcoGrid(username, password);
> +
> +			if (ecogridSessionid != null && !ecogridSessionid.equals("")) {
> +				String id = session.getId();
> +				session.setAttribute("ecogridSessionid", ecogridSessionid);
> +				session.setAttribute("username", username);
> +				session.setAttribute("password", password);
> +				sessionHash.put(id, session);
> +			} else { // if we can't get an ecogrid session id then scrap it.
> +				throwException(out, "Could not login to EarthGrid.",
> +						"handleLoginAction", null);
> +				return;
> +			}
> +
> +			String url = "/KeplerRemoteJobMonitorServlet/jobMonitor?action=showSlaveStatus";
> +			String redirect = getRedirect(url);
> +			out.println(redirect);
> +		} catch (Exception e) {
> +			throwException(out, "Error logging in: " + e.getMessage(),
> +					"handleLoginAction", e);
> +			return;
> +		}
> +
> +	}
> +
> +	/**
> +	 * embeds the html message into a basic html wrapper
> +	 */
> +	private String embedInHtml(String html) {
> +		StringBuffer sb = new StringBuffer();
> +		sb
> +				.append("<html><head><title>Kepler Remote Computing</title></head><body>\n");
> +		sb.append(html);
> +		sb.append("</body></html>\n");
> +		return sb.toString();
> +	}
> +
> +	/**
> +	 * Handle the logout request. Close the connection.
> +	 * 
> +	 *@param out
> +	 *            Description of the Parameter
> +	 *@param params
> +	 *            Description of the Parameter
> +	 *@param request
> +	 *            Description of the Parameter
> +	 *@param response
> +	 *            Description of the Parameter
> +	 */
> +	private void handleLogoutAction(PrintWriter out, Hashtable params,
> +			HttpServletRequest request, HttpServletResponse response) {
> +		/*
> +		 * String qformat = "xml"; if(params.get("qformat") != null) { qformat =
> +		 * ((String[])params.get("qformat"))[0]; } / close the connection
> +		 * HttpSession sess = request.getSession(false);
> +		 * print("After get session in logout request"); if(sess != null) {
> +		 * print("The session id " + sess.getId() +
> +		 * " will be invalidate in logout action");
> +		 * print("The session contains user " + sess.getAttribute("username") +
> +		 * " will be invalidate in logout action"); sess.invalidate(); } /
> +		 * produce output StringBuffer output = new StringBuffer();
> +		 * output.append("<?xml version=\"1.0\"?>"); output.append("<logout>");
> +		 * output.append("User logged out"); output.append("</logout>"); /format
> +		 * and transform the output if(qformat.equals("xml")) {
> +		 * response.setContentType("text/xml"); out.println(output.toString());
> +		 * } else { try { DBTransform trans = new DBTransform();
> +		 * response.setContentType("text/html");
> +		 * trans.transformXMLDocument(output.toString(), "-//NCEAS//login//EN",
> +		 * "-//W3C//HTML//EN", qformat, out, null); } catch(Exception e) {
> +		 * print( "Error in MetaCatServlet.handleLogoutAction" +
> +		 * e.getMessage()); } }
> +		 */
> +	}
> +
> +	/**
> +	 * Handle documents passed to metacat that are encoded using the
> +	 * "multipart/form-data" mime type. This is typically used for uploading
> +	 * data files which may be binary and large.
> +	 * 
> +	 *@param request
> +	 *            Description of the Parameter
> +	 *@param response
> +	 *            Description of the Parameter
> +	 */
> +	private void handleMultipartForm(HttpServletRequest request,
> +			HttpServletResponse response) {
> +		PrintWriter out = null;
> +		String action = null;
> +
> +		// Parse the multipart form, and save the parameters in a Hashtable and
> +		// save the FileParts in a hashtable
> +
> +		Hashtable params = new Hashtable();
> +		Hashtable fileList = new Hashtable();
> +		int sizeLimit = 1024;
> +		print("The size limit of uploaded data files is: " + sizeLimit);
> +
> +		try {
> +			MultipartParser mp = new MultipartParser(request,
> +					sizeLimit * 1024 * 1024);
> +			Part part;
> +			while ((part = mp.readNextPart()) != null) {
> +				String name = part.getName();
> +
> +				if (part.isParam()) {
> +					// it's a parameter part
> +					ParamPart paramPart = (ParamPart) part;
> +					String value = paramPart.getStringValue();
> +					params.put(name, value);
> +					if (name.equals("action")) {
> +						action = value;
> +					}
> +				} else if (part.isFile()) {
> +					// it's a file part
> +					FilePart filePart = (FilePart) part;
> +					fileList.put(name, filePart);
> +
> +					// Stop once the first file part is found, otherwise going
> +					// onto the
> +					// next part prevents access to the file contents. So...for
> +					// upload
> +					// to work, the datafile must be the last part
> +					break;
> +				}
> +			}
> +		} catch (IOException ioe) {
> +			try {
> +				out = response.getWriter();
> +			} catch (IOException ioe2) {
> +				print("Fatal Error: couldn't get response output stream.");
> +			}
> +			out.println("<?xml version=\"1.0\"?>");
> +			out.println("<error>");
> +			out.println("Error: problem reading multipart data.");
> +			out.println("</error>");
> +		}
> +
> +		// Get the session information
> +		String username = null;
> +		String password = null;
> +		String[] groupnames = null;
> +		String sess_id = null;
> +
> +		// be aware of session expiration on every request
> +		HttpSession sess = request.getSession(true);
> +		if (sess.isNew()) {
> +			// session expired or has not been stored b/w user requests
> +			username = "public";
> +			sess.setAttribute("username", username);
> +		} else {
> +			username = (String) sess.getAttribute("username");
> +			password = (String) sess.getAttribute("password");
> +			groupnames = (String[]) sess.getAttribute("groupnames");
> +			try {
> +				sess_id = (String) sess.getId();
> +			} catch (IllegalStateException ise) {
> +				print("error in  handleMultipartForm: this shouldn't "
> +						+ "happen: the session should be valid: "
> +						+ ise.getMessage());
> +			}
> +		}
> +
> +		// Get the out stream
> +		try {
> +			out = response.getWriter();
> +		} catch (IOException ioe2) {
> +			print("Fatal Error: couldn't get response " + "output stream.");
> +		}
> +
> +		if (action.equals("upload")) {
> +			if (username != null && !username.equals("public")) {
> +				// handleUploadAction(request, out, params, fileList, username,
> +				// groupnames);
> +			} else {
> +
> +				out.println("<?xml version=\"1.0\"?>");
> +				out.println("<error>");
> +				out.println("Permission denied for " + action);
> +				out.println("</error>");
> +			}
> +		} else {
> +			/*
> +			 * try { out = response.getWriter(); } catch (IOException ioe2) {
> +			 * System.err.println("Fatal Error: couldn't get response output
> +			 * stream.");
> +			 */
> +			out.println("<?xml version=\"1.0\"?>");
> +			out.println("<error>");
> +			out
> +					.println("Error: action not registered.  Please report this error.");
> +			out.println("</error>");
> +		}
> +		out.close();
> +	}
> +
> +	/**
> +	 * print html to redirect a user to the login page
> +	 * 
> +	 * @param url
> +	 *            the url to redirect to
> +	 */
> +	private String getRedirect(String url) {
> +		StringBuffer sb = new StringBuffer();
> +		sb.append("<html>\n");
> +		sb.append("<head>\n");
> +		sb.append("<title>Redirecting....</title>\n");
> +		sb.append("<meta HTTP-EQUIV=\"refresh\"\n");
> +		sb.append("CONTENT=0;URL=" + url + ">\n");
> +		sb.append("</head>\n");
> +		sb.append("<body>\n");
> +		sb.append("</body>\n");
> +		sb.append("</html>\n");
> +		return sb.toString();
> +	}
> +
> +	/**
> +	 * creates a confirmation page that allows a user to confirm an action and
> +	 * go forward with it or allows them to cancel and go back
> +	 */
> +	private void displayConfirmPage(String targetUrl, String returnUrl,
> +			String message, PrintWriter out) {
> +		StringBuffer sb = new StringBuffer();
> +		sb.append("<html><head><title>Confirm</title></head><body>");
> +		sb.append("<h3>");
> +		sb.append(message);
> +		sb.append("</h3>");
> +		sb.append("<h4><a href=\"" + targetUrl + "\">Continue</a><br/>");
> +		sb.append("    <a href=\"" + returnUrl
> +				+ "\">Return to previous page</a></h4>");
> +		sb.append("</body></html>");
> +		out.print(sb.toString());
> +		out.flush();
> +	}
> +
> +	/**
> +	 * print a message to System.out
> +	 * 
> +	 *@param message
> +	 *            Description of the Parameter
> +	 */
> +	private void print(String message) {
> +		DistributedLogger.print("KeplerRemoteJobMonitorServlet: " + message,
> +				DistributedLogger.LOW);
> +	}
> +}
> 
> Added: trunk/src/org/kepler/distributed/MasterController.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/MasterController.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/MasterController.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,369 @@
> +//  Copyright (c) 2007, Regents of the University of California
> +//  All rights reserved.
> +//
> +//  Redistribution and use in source and binary forms, with or without
> +//  modification, are permitted provided that the following conditions are
> +//  met:
> +//
> +//    * Redistributions of source code must retain the above copyright notice,
> +//  this list of conditions and the following disclaimer.
> +//    * Redistributions in binary form must reproduce the above copyright
> +//  notice, this list of conditions and the following disclaimer in the
> +//  documentation and/or other materials provided with the distribution.
> +//    * Neither the name of the University of California, San Diego (UCSD) nor
> +//  the names of its contributors may be used to endorse or promote products
> +//  derived from this software without specific prior written permission.
> +//
> +//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
> +//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> +//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> +//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> +//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
> +//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
> +//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
> +//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
> +//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> +//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
> +//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +//
> +//
> +//  FILE
> +//  MasterController.java -
> +//     org.ecoinformatics.seek.distrib.MasterController
> +//
> +//  CLASS HIERARCHY
> +//
> +//      |
> +//      +-org.ecoinformatics.seek.distrib.MasterController
> +//
> +//  PRINCIPAL AUTHOR
> +//  Lucas Gilbert, SDSC/UCSD
> +//
> +//
> +package org.kepler.distributed;
> +
> +import java.io.IOException;
> +import java.io.InputStream;
> +import java.rmi.Naming;
> +import java.rmi.Remote;
> +import java.rmi.RemoteException;
> +import java.util.HashMap;
> +import java.util.List;
> +import java.util.Map;
> +import java.util.Vector;
> +
> +import ptolemy.data.Token;
> +
> +/**
> + * Connects to multiple remote SlaveControllers. Manages communications for
> + * sending and recieving tokens.
> + * 
> + * '$Author: aschultz $' '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + * '$Revision: 16353 $'
> + */
> +// TODO should it be subclassing slave or is that confusing?
> +public class MasterController extends SlaveController implements Remote {
> +	private Slave[] slave;
> +	private int totalSlaves = 0;
> +	private Vector availableSlaves;
> +	private SlaveAvailableThread sat;
> +
> +	/*
> +	 * The mastercontroller contains a slave controller, instead of being the
> +	 * slave, because the latter was causing problems when using localhost
> +	 */
> +	private SlaveController localSlave;
> +
> +	/**
> +	 *@param actor
> +	 *            Description of the Parameter
> +	 * @param inputPortTypeMap
> +	 * @param parentAttributeList
> +	 *            The list of attributes of parent flow.
> +	 *@param config
> +	 *            Description of the Parameter
> +	 *@exception RemoteException
> +	 *                Description of the Exception
> +	 *@exception Exception
> +	 *                Description of the Exception
> +	 *@throws RemoteException
> +	 *             - if failed to export object
> +	 */
> +	public MasterController(DistributedCompositeActor actor, List newAttIt,
> +			Map inputPortTypeMap, InputStream config) throws RemoteException,
> +			Exception {
> +		String[] userInfo = DistributedConfigDialog.getUserInfo();
> +		String username = userInfo[0];
> +		String org = userInfo[1];
> +		String password = userInfo[2];
> +		String dn = "uid=" + username + ",o=" + org
> +				+ ",dc=ecoinformatics,dc=org";
> +
> +		// Should just be a text file a couple lines long...
> +		byte[] data = new byte[config.available()];
> +		if (config.available() != config.read(data)) {
> +			throw new Exception("config file error");
> +		}
> +
> +		// I think windows can leave these characters behind.
> +		String hostList = new String(data).replaceAll("\r", "");
> +		String[] hosts = hostList.split("\n");
> +		totalSlaves = hosts.length;
> +		slave = new Slave[totalSlaves];
> +		availableSlaves = new Vector();
> +		String actorName = actor.getName();
> +		String actorMOML = actor.exportMoMLPlain();
> +
> +		// bind server object to object in client
> +		for (int i = 0; i < totalSlaves; i++) {
> +			if (hosts[i] != null && hosts[i].length() > 0) {
> +				try {
> +					print("using host: " + hosts[i]);
> +					slave[i] = new Slave((DistributedServer) Naming
> +							.lookup("rmi://" + hosts[i]
> +									+ "/SlaveControllerInstance"));
> +				} catch (Exception e) {
> +					e.printStackTrace();
> +					if (e.getCause() instanceof java.net.ConnectException) {
> +						// just ignore it. unless all fail.
> +					}
> +					throw e;
> +				}
> +				// RMI call
> +				try {
> +					// authenticate, then request the slave
> +					Credential c = slave[i].getServer().authenticate(dn,
> +							password);
> +					SlaveAccessToken token = slave[i].getServer().requestSlave(
> +							c);
> +					slave[i].setCredential(c);
> +					slave[i].setToken(token);
> +					print("slave " + slave[i].getServer().getHostname()
> +							+ " authtoken: " + token.toString());
> +					slave[i].getServer().loadActor(actorName, actorMOML,
> +							newAttIt, inputPortTypeMap, token);
> +				} catch (Exception e) { // something happened with this slave
> +					print("ERROR: Could not use slave " + hosts[i]);
> +					e.printStackTrace();
> +				}
> +			}
> +			// TODO: make sure one connection succeeded
> +		}
> +
> +		files = new HashMap();
> +		sat = new SlaveAvailableThread();
> +		sat.start();
> +	}
> +
> +	/**
> +	 * Connect to network
> +	 */
> +	protected void init() {
> +		try {
> +			localSlave = new SlaveController();
> +		} catch (Exception e) {
> +			print("Exception occurred: " + e);
> +		}
> +	}
> +
> +	/**
> +	 * @return true, if this master is connected to a remote system
> +	 */
> +	public boolean isConnected() {
> +		// TODO
> +		return true;
> +	}
> +
> +	/**
> +	 * this is called by the DCA when all data has been transfered and the
> +	 * workflow can be sent to the slave to be run.
> +	 */
> +	public void readyToRun(Slave slave) throws Exception {
> +		synchronized (slave) {
> +			slave.getServer().ready(slave.getToken());
> +		}
> +	}
> +
> +	/**
> +	 * Adds tokens to the remote workflow.
> +	 * 
> +	 *@param tokens
> +	 *            Description of the Parameter
> +	 *@exception RemoteException
> +	 *                Description of the Exception
> +	 *@exception IOException
> +	 *                Description of the Exception
> +	 */
> +	public void put(Slave slave, Token[] tokens, String portName)
> +			throws RemoteException, IOException {
> +		checkDataTokens(tokens);
> +
> +		synchronized (slave) {
> +			// RMI
> +			slave.getServer().put(tokens, portName);
> +		}
> +	}
> +
> +	/**
> +	 * get a slave. this method blocks if there are no slaves available
> +	 */
> +	public Slave getSlave() {
> +		while (availableSlaves.size() == 0) {
> +			// print("waiting for available slaves...");
> +			try {
> +				Thread.currentThread().sleep(1000); // wait 1 second
> +			} catch (Exception e) {
> +				// thread was interrupted...do nothing.
> +			}
> +		}
> +		Slave s = (Slave) availableSlaves.remove(0);
> +		print("getting slave: " + s.toString());
> +		print("availableSlaves: " + availableSlaves.toString());
> +		return s;
> +	}
> +
> +	/**
> +	 * remove a host
> +	 */
> +	public void releaseSlave(Slave slave) {
> +		availableSlaves.addElement(slave);
> +	}
> +
> +	/**
> +	 * The master/recieving workflow should call this method and have a thread
> +	 * waiting for the return, if more iteration results are expected. Shortcut
> +	 * for, OutputCommunicationStubActor.get( )
> +	 * 
> +	 *@return Description of the Return Value
> +	 *@exception RemoteException
> +	 *                Description of the Exception
> +	 *@exception IOException
> +	 *                Description of the Exception
> +	 */
> +	public Token[] get(Slave slave, String portName) throws RemoteException,
> +			IOException {
> +		print("get token from slave " + slave.getServer().getHostname()
> +				+ "at port: " + portName);
> +		// RMI
> +		Token[] resultTokens = slave.getServer().get(portName);
> +		return resultTokens;
> +	}
> +
> +	/**
> +	 * This is called by the DCA to let the master know that the wf execution is
> +	 * done
> +	 */
> +	public void done() throws Exception {
> +		// release the slaves here
> +		print("done executing...releasing slaves.");
> +		Vector v = new Vector();
> +		for (int i = 0; i < slave.length; i++) {
> +			try {
> +				slave[i].getServer().releaseSlave();
> +				if (!availableSlaves.contains(slave[i])) {
> +					availableSlaves.addElement(slave[i]);
> +				}
> +				// sat.stop = true;
> +			} catch (Exception e) {
> +				print("ERROR: could not release slave "
> +						+ slave[i].getServer().getHostname());
> +				print("You may want to release this slave manually via the web interface.");
> +			}
> +		}
> +	}
> +
> +	/**
> +	 * will return true if one or more slaves are available for execution
> +	 */
> +	public boolean slavesAvailable() {
> +		if (availableSlaves.size() > 0) {
> +			return true;
> +		}
> +		return false;
> +	}
> +
> +	/**
> +	 * main
> +	 */
> +	public static void main(String[] args) {
> +		try {
> +			// MasterController master = new MasterController(
> +			// new DistributedCompositeActor(new ptolemy.actor.CompositeActor(),
> +			// "hi" ), null,
> +			// new
> +			// FileInputStream("c:/kepler/configs/ptolemy/configs/kepler/DistributedKepler.config")
> +			// );
> +
> +			// master.fileTest();
> +		} catch (Throwable ex) {
> +			System.err.println("Command failed: " + ex);
> +			ex.printStackTrace();
> +		}
> +	}
> +
> +	/**
> +	 * returns the number of slaves that will be executed on
> +	 */
> +	public int getNumberOfSlaves() {
> +		return totalSlaves;
> +	}
> +
> +	/**
> +	 * print debug output
> +	 */
> +	private void print(String message) {
> +		DistributedLogger.print("MasterController: " + message,
> +				DistributedLogger.HIGH);
> +	}
> +
> +	/**
> +	 * a class to continuously check of a slave is available
> +	 */
> +	private class SlaveAvailableThread extends Thread {
> +		public boolean stop = false;
> +
> +		public SlaveAvailableThread() {
> +
> +		}
> +
> +		public void run() {
> +			print("SlaveAvailableThread is running");
> +			try {
> +				boolean avail = false;
> +				while (true) {
> +					// print("looking for available slaves");
> +					for (int i = 0; i < slave.length; i++) {
> +						String hostname = slave[i].getServer().getHostname();
> +						// print("checking " + hostname);
> +						int slavestate = slave[i].getServer().getSlaveState(
> +								slave[i].getCredential());
> +						// print("slave state: " + slavestate);
> +						// print("NO_JOB: " + SlaveController.NO_JOB);
> +						// print("JOB_INIT: " +
> +						// SlaveController.JOB_INITIALIZING);
> +						if (slavestate == SlaveController.NO_JOB
> +								|| slavestate == SlaveController.JOB_INITIALIZING) {
> +							if (!availableSlaves.contains(slave[i])) {
> +								availableSlaves.addElement(slave[i]);
> +							}
> +							// print(hostname + " IS available");
> +							// print("There are currently " +
> +							// availableSlaves.size() +
> +							// " available for execution.");
> +						} else {
> +							// print(hostname + " is NOT available");
> +						}
> +					}
> +
> +					if (stop)
> +						return;
> +					// check once every other second
> +					this.sleep(2000);
> +				}
> +			} catch (Exception e) {
> +				print("Error checking slave availability: " + e.getMessage());
> +				e.printStackTrace();
> +			}
> +		}
> +	}
> +}
> 
> Added: trunk/src/org/kepler/distributed/MemoryUsage.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/MemoryUsage.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/MemoryUsage.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,96 @@
> +//  Copyright (c) 2007, Regents of the University of California
> +//  All rights reserved.
> +//
> +//  Redistribution and use in source and binary forms, with or without
> +//  modification, are permitted provided that the following conditions are
> +//  met:
> +//
> +//    * Redistributions of source code must retain the above copyright notice,
> +//  this list of conditions and the following disclaimer.
> +//    * Redistributions in binary form must reproduce the above copyright
> +//  notice, this list of conditions and the following disclaimer in the
> +//  documentation and/or other materials provided with the distribution.
> +//    * Neither the name of the University of California, San Diego (UCSD) nor
> +//  the names of its contributors may be used to endorse or promote products
> +//  derived from this software without specific prior written permission.
> +//
> +//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
> +//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> +//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> +//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> +//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
> +//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
> +//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
> +//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
> +//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> +//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
> +//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +//
> +//
> +//  FILE
> +//  DataToken.java -
> +//     org.kepler.distributed.DataToken
> +//
> +//  CLASS HIERARCHY
> +//  java.lang.Object
> +//	|
> +//  	+-ptolemy.data.Token
> +//	      |
> +//	      +-org.kepler.distributed.DataToken
> +//
> +//
> +//  PRINCIPAL AUTHOR
> +//  Chad Berkley
> +//
> +//
> +package org.kepler.distributed;
> +
> +import java.io.Serializable;
> +
> +/**
> + * '$Author: aschultz $' '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + * '$Revision: 16353 $'
> + * 
> + * this is a container class for memory usage data. It stores the available and
> + * used memory and can return both values independently.
> + */
> +public class MemoryUsage implements Serializable {
> +	private long available;
> +	private long used;
> +	private long max;
> +
> +	/**
> +	 * constructor
> +	 * 
> +	 * @param available
> +	 *            the available system memory
> +	 * @param used
> +	 *            the used system memory
> +	 */
> +	public MemoryUsage(long available, long used, long max) {
> +		this.available = available;
> +		this.used = used;
> +		this.max = max;
> +	}
> +
> +	/**
> +	 * return the available system memory
> +	 */
> +	public long getAvailable() {
> +		return available;
> +	}
> +
> +	/**
> +	 * return the used system memory
> +	 */
> +	public long getUsed() {
> +		return used;
> +	}
> +
> +	/**
> +	 * return the maximum amount this virtual machine can acquire
> +	 */
> +	public long getMax() {
> +		return max;
> +	}
> +}
> 
> Added: trunk/src/org/kepler/distributed/NotRestartableException.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/NotRestartableException.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/NotRestartableException.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,70 @@
> +//  Copyright (c) 2007, Regents of the University of California
> +//  All rights reserved.
> +//
> +//  Redistribution and use in source and binary forms, with or without
> +//  modification, are permitted provided that the following conditions are
> +//  met:
> +//
> +//    * Redistributions of source code must retain the above copyright notice,
> +//  this list of conditions and the following disclaimer.
> +//    * Redistributions in binary form must reproduce the above copyright
> +//  notice, this list of conditions and the following disclaimer in the
> +//  documentation and/or other materials provided with the distribution.
> +//    * Neither the name of the University of California, San Diego (UCSD) nor
> +//  the names of its contributors may be used to endorse or promote products
> +//  derived from this software without specific prior written permission.
> +//
> +//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
> +//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> +//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> +//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> +//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
> +//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
> +//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
> +//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
> +//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> +//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
> +//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +//
> +//
> +//  FILE
> +//  DataToken.java -
> +//     org.kepler.distributed.DataToken
> +//
> +//  CLASS HIERARCHY
> +//  java.lang.Object
> +//	|
> +//  	+-ptolemy.data.Token
> +//	      |
> +//	      +-org.kepler.distributed.DataToken
> +//
> +//
> +//  PRINCIPAL AUTHOR
> +//  Chad Berkley
> +//
> +//
> +package org.kepler.distributed;
> +
> +/**
> + * '$Author: aschultz $' '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + * '$Revision: 16353 $'
> + * 
> + * An exception that is thrown if a job is not restartable
> + */
> +public class NotRestartableException extends Exception {
> +	public NotRestartableException() {
> +		super();
> +	}
> +
> +	public NotRestartableException(String message) {
> +		super(message);
> +	}
> +
> +	public NotRestartableException(String message, Throwable cause) {
> +		super(message, cause);
> +	}
> +
> +	public NotRestartableException(Throwable cause) {
> +		super(cause);
> +	}
> +}
> 
> Added: trunk/src/org/kepler/distributed/RemoteActor.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/RemoteActor.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/RemoteActor.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,51 @@
> +/**
> + *    '$RCSfile$'
> + *
> + *     '$Author: aschultz $'
> + *       '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + *   '$Revision: 16353 $'
> + *
> + *  For Details: http://www.kepler-project.org
> + *
> + * Copyright (c) 2004 The Regents of the University of California.
> + * All rights reserved.
> + *
> + * Permission is hereby granted, without written agreement and without
> + * license or royalty fees, to use, copy, modify, and distribute this
> + * software and its documentation for any purpose, provided that the
> + * above copyright notice and the following two paragraphs appear in
> + * all copies of this software.
> + *
> + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
> + * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
> + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
> + * IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY
> + * OF SUCH DAMAGE.
> + *
> + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
> + * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY
> + * OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
> + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
> + */
> +
> +package org.kepler.distributed;
> +
> +import ptolemy.data.Token;
> +
> +/**
> + * '$Author: aschultz $' '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + * '$Revision: 16353 $'
> + */
> +public interface RemoteActor {
> +	/**
> +	 * remotely load an array of tokens
> +	 */
> +	public void loadRemoteData(Token[] tokens);
> +
> +	/**
> +	 * remotely add a token
> +	 */
> +	public void loadRemoteData(Token token);
> +}
> 
> Added: trunk/src/org/kepler/distributed/Slave.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/Slave.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/Slave.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,94 @@
> +//  Copyright (c) 2007, Regents of the University of California
> +//  All rights reserved.
> +//
> +//  Redistribution and use in source and binary forms, with or without
> +//  modification, are permitted provided that the following conditions are
> +//  met:
> +//
> +//    * Redistributions of source code must retain the above copyright notice,
> +//  this list of conditions and the following disclaimer.
> +//    * Redistributions in binary form must reproduce the above copyright
> +//  notice, this list of conditions and the following disclaimer in the
> +//  documentation and/or other materials provided with the distribution.
> +//    * Neither the name of the University of California, San Diego (UCSD) nor
> +//  the names of its contributors may be used to endorse or promote products
> +//  derived from this software without specific prior written permission.
> +//
> +//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
> +//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> +//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> +//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> +//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
> +//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
> +//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
> +//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
> +//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> +//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
> +//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +//
> +package org.kepler.distributed;
> +
> +/**
> + * '$Author: aschultz $' '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + * '$Revision: 16353 $' class to hold all pertinent info about a slave
> + */
> +public class Slave {
> +	private DistributedServer server = null;
> +	private Credential c = null;
> +	private SlaveAccessToken token = null;
> +
> +	/**
> +	 * constructor
> +	 */
> +	public Slave(DistributedServer server) {
> +		this.server = server;
> +	}
> +
> +	/**
> +	 * set the credential
> +	 */
> +	public void setCredential(Credential c) {
> +		this.c = c;
> +	}
> +
> +	/**
> +	 * set the token
> +	 */
> +	public void setToken(SlaveAccessToken t) {
> +		this.token = t;
> +	}
> +
> +	/**
> +	 * get the DistributedServer
> +	 */
> +	public DistributedServer getServer() {
> +		return server;
> +	}
> +
> +	/**
> +	 * get the credential
> +	 */
> +	public Credential getCredential() {
> +		return c;
> +	}
> +
> +	/**
> +	 * get the token
> +	 */
> +	public SlaveAccessToken getToken() {
> +		return token;
> +	}
> +
> +	/**
> +	 * return a string rep of this class
> +	 */
> +	public String toString() {
> +		String s = "";
> +		try {
> +			s = "Slave: " + server.getHostname();
> +		} catch (Exception e) {
> +		}
> +		s += " Token: " + token.toString();
> +		return s;
> +	}
> +}
> 
> Added: trunk/src/org/kepler/distributed/SlaveAccessToken.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/SlaveAccessToken.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/SlaveAccessToken.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,88 @@
> +//  Copyright (c) 2007, Regents of the University of California
> +//  All rights reserved.
> +//
> +//  Redistribution and use in source and binary forms, with or without
> +//  modification, are permitted provided that the following conditions are
> +//  met:
> +//
> +//    * Redistributions of source code must retain the above copyright notice,
> +//  this list of conditions and the following disclaimer.
> +//    * Redistributions in binary form must reproduce the above copyright
> +//  notice, this list of conditions and the following disclaimer in the
> +//  documentation and/or other materials provided with the distribution.
> +//    * Neither the name of the University of California, San Diego (UCSD) nor
> +//  the names of its contributors may be used to endorse or promote products
> +//  derived from this software without specific prior written permission.
> +//
> +//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
> +//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> +//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> +//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> +//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
> +//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
> +//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
> +//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
> +//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> +//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
> +//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +//
> +//  PRINCIPAL AUTHOR
> +//  Chad Berkley
> +//
> +//
> +package org.kepler.distributed;
> +
> +import java.io.Serializable;
> +
> +/**
> + * '$Author: aschultz $' '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + * '$Revision: 16353 $'
> + * 
> + * Class for slave token info
> + */
> +public class SlaveAccessToken implements Serializable {
> +	private long expiration;
> +	private Credential credential;
> +
> +	/**
> +	 * constructor
> +	 * 
> +	 * @param expiration
> +	 *            the time in milliseconds that the users slave session expires
> +	 * @param credential
> +	 *            the credential of the user that owns the token
> +	 */
> +	public SlaveAccessToken(long expiration, Credential credential) {
> +		this.expiration = expiration;
> +		this.credential = credential;
> +	}
> +
> +	/**
> +	 * get the credential
> +	 */
> +	public Credential getCredential() {
> +		return credential;
> +	}
> +
> +	/**
> +	 * get the expiration time
> +	 */
> +	public long getExpiration() {
> +		return expiration;
> +	}
> +
> +	public boolean equals(SlaveAccessToken token) {
> +		print("token: " + token);
> +		print("this: " + this);
> +		if (token != null && this.expiration == token.getExpiration()
> +				&& this.credential.equals(token.getCredential())) {
> +			return true;
> +		}
> +		return false;
> +	}
> +
> +	private void print(String msg) {
> +		DistributedLogger.print("SlaveAccessToken: " + msg,
> +				DistributedLogger.LOW);
> +	}
> +}
> 
> Added: trunk/src/org/kepler/distributed/SlaveController.java
> ===================================================================
> --- trunk/src/org/kepler/distributed/SlaveController.java	                        (rev 0)
> +++ trunk/src/org/kepler/distributed/SlaveController.java	2009-01-15 19:06:11 UTC (rev 16356)
> @@ -0,0 +1,1721 @@
> +//  Copyright (c) 2007, Regents of the University of California
> +//  All rights reserved.
> +//
> +//  Redistribution and use in source and binary forms, with or without
> +//  modification, are permitted provided that the following conditions are
> +//  met:
> +//
> +//    * Redistributions of source code must retain the above copyright notice,
> +//  this list of conditions and the following disclaimer.
> +//    * Redistributions in binary form must reproduce the above copyright
> +//  notice, this list of conditions and the following disclaimer in the
> +//  documentation and/or other materials provided with the distribution.
> +//    * Neither the name of the University of California, San Diego (UCSD) nor
> +//  the names of its contributors may be used to endorse or promote products
> +//  derived from this software without specific prior written permission.
> +//
> +//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
> +//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> +//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> +//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> +//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
> +//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
> +//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
> +//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
> +//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> +//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
> +//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +//
> +//
> +//  FILE
> +//  SlaveController.java -
> +//     org.ecoinformatics.seek.distrib.SlaveController
> +//
> +//  CLASS HIERARCHY
> +//
> +//      |
> +//      +-org.kepler.distributed.SlaveController
> +//
> +//
> +//  PRINCIPAL AUTHOR
> +//  Lucas Gilbert, SDSC/UCSD
> +//
> +//
> +package org.kepler.distributed;
> +
> +import java.io.File;
> +import java.io.FileNotFoundException;
> +import java.io.FileReader;
> +import java.io.FileWriter;
> +import java.io.IOException;
> +import java.rmi.Naming;
> +import java.rmi.Remote;
> +import java.rmi.RemoteException;
> +import java.rmi.server.UnicastRemoteObject;
> +import java.util.HashMap;
> +import java.util.Hashtable;
> +import java.util.Iterator;
> +import java.util.List;
> +import java.util.Map;
> +import java.util.ResourceBundle;
> +import java.util.UUID;
> +import java.util.Vector;
> +
> +import org.ecoinformatics.ecogrid.registry.stub.RegistryEntryType;
> +import org.kepler.authentication.AuthenticationException;
> +import org.kepler.authentication.AuthenticationManager;
> +import org.kepler.authentication.AuthenticationService;
> +import org.kepler.authentication.Domain;
> +import org.kepler.authentication.LDAPAuthenticationService;
> +import org.kepler.authentication.ProxyEntity;
> +import org.kepler.objectmanager.lsid.KeplerLSID;
> +import org.kepler.objectmanager.repository.EcogridRepository;
> +import org.kepler.objectmanager.repository.Repository;
> +import org.kepler.objectmanager.repository.RepositoryException;
> +import org.kepler.objectmanager.repository.RepositoryManager;
> +
> +import ptolemy.actor.CompositeActor;
> +import ptolemy.actor.ExecutionListener;
> +import ptolemy.actor.IOPort;
> +import ptolemy.actor.Manager;
> +import ptolemy.actor.TypedIORelation;
> +import ptolemy.actor.gui.MoMLApplication.IgnoreErrorHandler;
> +import ptolemy.actor.parameters.ParameterPort;
> +import ptolemy.actor.parameters.PortParameter;
> +import ptolemy.data.StringToken;
> +import ptolemy.data.Token;
> +import ptolemy.data.expr.Parameter;
> +import ptolemy.kernel.util.ChangeListener;
> +import ptolemy.kernel.util.ChangeRequest;
> +import ptolemy.kernel.util.Workspace;
> +import ptolemy.moml.MoMLParser;
> +import ptolemy.moml.filter.BackwardCompatibility;
> +import ptolemy.moml.filter.RemoveGraphicalClasses;
> +import edu.sdsc.grid.io.local.LocalRandomAccessFile;
> +
> +/**
> + * '$Author: aschultz $' '$Date: 2009-01-14 19:37:44 -0800 (Wed, 14 Jan 2009) $'
> + * '$Revision: 16353 $'
> + */
> +public class SlaveController extends UnicastRemoteObject implements
> +		DistributedServer, DistributedFileServer, ChangeListener,
> +		ExecutionListener, Remote {
> +	protected Manager _manager = null;
> +	protected Hashtable outputHash = new Hashtable();
> +	private Hashtable inputActorHash = new Hashtable();
> +	private Throwable _sawThrowable = null;
> +	private boolean _executionFinishedOrError = false;
> +	private CompositeActor dca;
> +	private int jobStatus;
> +	private int jobProgress;
> +	private String registryFileLSID;
> +	private static String serverName = "";
> +	private String aclOrder;
> +	private String[] allowedUsers;
> +	private String[] deniedUsers;
> +	private SlaveAccessToken currentToken = null;
> +	private String hostName;
> +	private SlaveTokenChecker checker;
> +	private boolean checkerStop = false;
> +
> +	private static final long EXPIRATION_LENGTH = 3600000; // one hour
> +
> +	// JobStatus variables
> +	/** the job is stopped. Either the user stopped it or it finished. */
> +	public static final int JOB_STOPPED = 0;
> +	/** the job is running. */
> +	public static final int JOB_RUNNING = 1;
> +	/**
> +	 * the user has told the job to restart and it has not yet started running
> +	 * again
> +	 */
> +	public static final int JOB_RESTARTING = 2;
> +	/** the job is initializing */
> +	public static final int JOB_INITIALIZING = 3;
> +	/** there is no job on this slave */
> +	public static final int NO_JOB = 4;
> +	/** there was an error during the last execution and the job is now stopped */
> +	public static final int JOB_ERROR = 5;
> +
> +	/**
> +	 * File registry for access by remote systems
> +	 */
> +	protected HashMap files;
> +
> +	/**
> +	 *@exception RemoteException
> +	 *                Description of the Exception
> +	 *@throws RemoteException
> +	 *             - if failed to export object
> +	 */
> +	public SlaveController(boolean register, String userList, String regServer,
> +			String hostName) throws RemoteException {
> +		super();
> +		init();
> +		this.hostName = hostName;
> +		try {
> +			processParams(register, userList, regServer);
> +		} catch (Exception e) {
> +			throw new RemoteException(
> +					"SlaveController could not process given user"
> +							+ "parameters: " + e.getMessage());
> +		}
> +
> +		jobStatus = NO_JOB;
> +		jobProgress = 0;
> +		print("Ready");
> +	}
> +
> +	/**
> +	 * default constructor. this sets register to false and provides no
> +	 * userList, regServer or hostName
> +	 */
> +	public SlaveController() throws RemoteException {
> +		this(false, "", "", "");
> +	}
> +
> +	/**
> +	 * Connect to network
> +	 */
> +	protected void init() {
> +		try {
> +			Naming.rebind("SlaveControllerInstance", this);
> +		} catch (Exception e) {
> +			print("Exception occurred: " + e);
> +		}
> +		files = new HashMap();
> +	}
> +
> +	// /////////////////////////////////////////////////////////////////
> +	// // Remote communication methods ////
> +
> +	/**
> +	 * Loads this actor into a local workflow
> +	 * 
> +	 *@param distributedActor
> +	 *            Description of the Parameter
> +	 *@exception RemoteException
> +	 *                Description of the Exception
> +	 *@throws Exception
> +	 *             if there is an exception while parsing the Moml of
> +	 *             distributedActor
> +	 */
> +	public void loadActor(String actorName, String distributedActor,
> +			List parentAttributeMap, Map inputPortTypeMap,
> +			SlaveAccessToken token) throws RemoteException,
> +			InvalidTokenException {
> +		print("load actor");
> +
> +		// check to make sure the token is valid
> +		checkTokenValidity(token);
> +
> +		// DEBUG: to print out the created workflow
> +		try {
> +			print("Printing DCA model output...");
> +			File f = new File("master-slave/origmodel.xml");
> +			FileWriter fw = new FileWriter(f);
> +			fw.write(distributedActor, 0, distributedActor.length());
> +			fw.flush();
> +			fw.close();
> +			print("model file written to " + f.getAbsolutePath());
> +
> +			print("Printing parentAttributeList...");
> +			File f1 = new File("master-slave/parentAttributeList.xml");
> +			fw = new FileWriter(f1);
> +			/*
> +			 * for(int i=0; i<parentAttributeMap.size(); i++){ Parameter
> +			 * oneAttribute = (Parameter)parentAttributeMap.toString();
> +			 * fw.write(oneAttribute.exportMoML(), 0,
> +			 * oneAttribute.exportMoML().length()); } fw.flush(); fw.close();
> +			 */
> +			// System.out.print("parentAttributeMap:" +
> +			// parentAttributeMap.toString());
> +			// print("parentAttributeMap:" + parentAttributeMap.toString());
> +			print("parentAttributeList file written to " + f1.getAbsolutePath());
> +		} catch (Exception e) {
> +			print("error writing tmp file: " + e.getMessage());
> +		}
> +
> +		jobStatus = JOB_INITIALIZING;
> +		jobProgress = 1;
> +		MoMLParser parser = new MoMLParser();
> +		// The test suite calls MoMLSimpleApplication multiple times,
> +		// and the list of filters is static, so we reset it each time
> +		// so as to avoid adding filters every time we run an auto test.
> +		// We set the list of MoMLFilters to handle Backward Compatibility.
> +		MoMLParser.setMoMLFilters(BackwardCompatibility.allFilters());
> +		// Filter out any graphical classes.
> +		MoMLParser.addMoMLFilter(new RemoveGraphicalClasses());
> +		// the toplevel workflow
> +		CompositeActor toplevel = null;
> +
> +		try {
> +			parser.setErrorHandler(new IgnoreErrorHandler());
> +			dca = (CompositeActor) parser.parse(distributedActor);
> +		} catch (Exception exception) {
> +			if (exception instanceof ptolemy.kernel.util.IllegalActionException)
> +				print("ptolemy.kernel.util.IllegalActionException");
> +			print(exception.getMessage());
> +		}
> +
> +		Iterator portListItt = dca.outputPortList().iterator();
> +		while (portListItt.hasNext()) { // change the port class names so we can
> +										// hijack the dataflow with rmi
> +			IOPort origPort = (IOPort) portListItt.next();
> +			origPort.setClassName("org.kepler.distributed.DistributedIOPort");
> +			print("setting " + origPort.getName()
> +					+ "'s class to DistributedIOPort");
> +		}
> +
> +		List portParamList = dca.attributeList(PortParameter.class);
> +		Iterator portParamIterator = null;
> +		if (portParamList != null) {
> +			portParamIterator = portParamList.iterator();
> +		}
> +
> +		while (portParamIterator.hasNext()) {
> +			PortParameter pp = (PortParameter) portParamIterator.next();
> +			pp.setClassName("org.kepler.distributed.DistributedPortParameter");
> +			print("setting " + pp.getName()
> +					+ "'s class to DistributedPortParameter");
> +			// also need to add these to the actorHash but do it below after the
> +			// parse
> +		}
> +
> +		distributedActor = dca.exportMoML();
> +		// strip the crap off the top
> +		distributedActor = distributedActor.substring(distributedActor
> +				.indexOf("<entity name=\"" + actorName), distributedActor
> +				.length());
> +
> +		// change to a DCA. we no longer want the composite to be distributed
> +		// or else we'll go into an infinite loop
> +		String old = "org.kepler.distributed.DistributedCompositeActor";
> +		int index = distributedActor.indexOf(old);
> +		distributedActor = distributedActor.substring(0, index)
> +				+ "ptolemy.actor.TypedCompositeActor"
> +				+ distributedActor.substring(index + old.length());
> +
> +		// parse the actor
> +		parser.reset();
> +		try {
> +			// dca = (CompositeActor)parser.parse(distributedActor);
> +		} catch (Exception exception) {
> +			if (exception instanceof ptolemy.kernel.util.IllegalActionException)
> +				print("ptolemy.kernel.util.IllegalActionException");
> +			print(exception.getMessage());
> +		}
> +
> +		// String distributedActorName = dca.getName();
> +		parser.reset();
> +
> +		ResourceBundle repositoryBundle = ResourceBundle
> +				.getBundle("ptolemy/configs/kepler/repositoryBundle");
> +		String lsidAuthority = repositoryBundle
> +				.getString("keplerRepository.lsidAuthority");
> +
> +		// the outer wrapper of the workflow with an SDF director
> +		String topLevelXML = "<?xml version=\"1.0\" standalone=\"no\"?>\n"
> +				+ "<!DOCTYPE entity PUBLIC \"-//UC Berkeley//DTD MoML 1//EN\" "
> +				+ "    \"http://ptolemy.eecs.berkeley.edu/xml/dtd/MoML_1.dtd\"> \n"
> +				+ "<entity name=\"distributedModel\" class=\"ptolemy.actor.TypedCompositeActor\">\n";
> +
> +		// "    <property name=\"SDF Director\" class=\"ptolemy.domains.sdf.kernel.SDFDirector\">\n"
> +		// +
> +		// "        <property name=\"iterations\" class=\"ptolemy.data.expr.Parameter\" value=\"1\">\n"
> +		// +
> +		// "        </property>\n" +
> +		// "        <property name=\"vectorizationFactor\" class=\"ptolemy.data.expr.Parameter\" value=\"1\">\n"
> +		// +
> +		// "        </property>\n" +
> +		// "        <property name=\"allowDisconnectedGraphs\" class=\"ptolemy.data.expr.Parameter\" value=\"true\">\n"
> +		// +
> +		// "        </property>\n" +
> +		// "        <property name=\"allowRateChanges\" class=\"ptolemy.data.expr.Parameter\" value=\"true\">\n"
> +		// +
> +		// "        </property>\n" +
> +		// "        <property name=\"constrainBufferSizes\" class=\"ptolemy.data.expr.Parameter\" value=\"true\">\n"
> +		// +
> +		// "        </property>\n" +
> +		// "        <property name=\"period\" class=\"ptolemy.data.expr.Parameter\" value=\"0.0\">\n"
> +		// +
> +		// "        </property>\n" +
> +		// "        <property name=\"synchronizeToRealTime\" class=\"ptolemy.data.expr.Parameter\" value=\"false\">\n"
> +		// +
> +		// "        </property>\n" +
> +		// "        <property name=\"timeResolution\" class=\"ptolemy.moml.SharedParameter\" value=\"1E-10\">\n"
> +		// +
> +		// "        </property>\n" +
> +		// "        <property name=\"Scheduler\" class=\"ptolemy.domains.sdf.kernel.SDFScheduler\">\n"
> +		// +
> +		// "            <property name=\"constrainBufferSizes\" class=\"ptolemy.data.expr.Parameter\" value=\"constrainBufferSizes\">\n"
> +		// +
> +		// "            </property>\n" +
> +		// "        </property>\n" +
> +		// "        <property name=\"entityId\" class=\"org.kepler.moml.NamedObjId\" value=\"urn:lsid:"
> +		// + lsidAuthority + ":director:1:1\">\n" +
> +		// "        </property>\n" +
> +		// "        <property name=\"class\" class=\"ptolemy.kernel.util.StringAttribute\" value=\"ptolemy.domains.sdf.kernel.SDFDirector\">\n"
> +		// +
> +		// "            <property name=\"id\" class=\"ptolemy.kernel.util.StringAttribute\" value=\"urn:lsid:"
> +		// + lsidAuthority + ":directorclass:1:1\">\n" +
> +		// "            </property>\n" +
> +		// "        </property>\n" +
> +		// "        <property name=\"semanticType000\" class=\"org.kepler.sms.SemanticType\" value=\"urn:lsid:localhost:onto:1:1#Director\">\n"
> +		// +
> +		// "        </property>\n" +
> +		// "        <property name=\"semanticType111\" class=\"org.kepler.sms.SemanticType\" value=\"urn:lsid:localhost:onto:2:1#Director\">\n"
> +		// +
> +		// "        </property>\n" +
> +		// "        <property name=\"_location\" class=\"ptolemy.kernel.util.Location\" value=\"{105, 365}\">\n"
> +		// +
> +		// "        </property>\n" +
> +		// "    </property>\n";
> +
> +		// paste in attributes of its container
> +		for (int i = 0; i < parentAttributeMap.size(); i++) {
> +			topLevelXML += parentAttributeMap.toString();
> +		}
> +		topLevelXML += "   \n\n<!-- DCA -->\n\n";
> +		// paste in our new actor
> +		topLevelXML += distributedActor;
> +		topLevelXML += "   \n\n<!-- end DCA -->\n\n";
> +
> +		topLevelXML += "</entity>\n";
> +
> +		print("Done creating workflow.");
> +
> +		// DEBUG: to print out the created workflow
> +		try {
> +			print("Printing generated model output...");
> +			File f = new File("master-slave/dynmodel-initial.xml");
> +			FileWriter fw = new FileWriter(f);
> +			fw.write(topLevelXML, 0, topLevelXML.length());
> +			fw.flush();
> +			fw.close();
> +			print("model file written to " + f.getAbsolutePath());
> +		} catch (Exception e) {
> +			print("error writing tmp file: " + e.getMessage());
> +		}
> +
> +		Workspace workspace = null;
> +		try {
> +			// parse the whole thing
> +			toplevel = (CompositeActor) parser.parse(topLevelXML);
> +			workspace = toplevel.workspace();
> +			// add new parameter for slave specifying it is slave. It is for
> +			// distributed provenance.
> +			Parameter addedPara = new Parameter(toplevel, "isSlave");
> +			addedPara.setExpression("true");
> +		} catch (Exception e) {
> +			print("error parsing topLevel xml: " + e.getMessage());
> +		}
> +
> +		// //add parent parameter if there are no these parameter in the slave.
> +		// Iterator keyIt= parentParaMap.keySet().iterator();
> +		// while(keyIt.hasNext()){
> +		// String paraName = (String)keyIt.next();
> +		// //String paraExpression = (String)parentParaMap.get(paraName);
> +		// if(toplevel.getAttribute(paraName)==null)
> +		// {
> +		// print("add parent para: "+ paraName);
> +		// String para[] = (String[])parentParaMap.get(paraName);
> +		// print("added parent para: "+ para);
> +		// Parameter addedPara = new Parameter(toplevel, paraName);
> +		// addedPara.setExpression(para[1]);
> +		// addedPara.setClassName(para[0]);
> +		// }
> +		// }
> +
> +		// get the DCA from the workflow object
> +		dca = (CompositeActor) toplevel.getEntity(actorName);
> +
> +		// if the dca is empty, don't do anything
> +		if (dca == null) {
> +			print("CompositeActor instance is null");
> +			return;
> +		}
> +		List inputPortList = dca.inputPortList();
> +		Iterator portIterator = null;
> +		if (inputPortList != null) {
> +			// find all of the user created ports and replace them with
> +			// DistributedInputActors. This allows the RMI calls from the master
> +			// to be used at runtime.
> +			portIterator = dca.inputPortList().iterator();
> +		}
> +		if (portIterator == null) {
> +			print("portIterator is null");
> +			return; // TODO probably good enough?
> +		}
> +		print("looking for ports");
> +		try {
> +			int inputActorIndex = 0;
> +			while (portIterator.hasNext()) {
> +				// for every input port, we're going to add a
> +				// distributedInputActor to the
> +				// workflow, then connect it just as the port was connected
> +				IOPort port = (IOPort) portIterator.next();
> +				if (port instanceof ParameterPort) {
> +					continue;
> +				}
> +				String portName = port.getName();
> +				print("===============processing port " + portName
> +						+ "===============");
> +				// set the type of ports according to its type in master.
> +				//
> +
> +				String portType = (String) inputPortTypeMap.get(portName);
> +				print("The type port " + portName + " is : " + portType);
> +
> +				// create the input actor
> +				DistributedInputActor dia = new DistributedInputActor(dca,
> +						"DIA" + portName, portType);
> +				// add the dia to the inputActorHash so that we can feed the
> +				// correct
> +				// RMI data to the right actor.
> +				inputActorHash.put(dia.getName(), dia);
> +				// connect the new actor to a relation then connect any ports to
> +				// that
> +				// relation. this prevents getting an exception if the input
> +				// port
> +				// goes to a relation then to multiple other ports
> +				TypedIORelation rootRelation = new TypedIORelation(dca, dia
> +						.getName()
> +						+ "RootRelation" + inputActorIndex);
> +				IOPort p = (IOPort) dia.getPort("output");
> +				print("creating link between " + p.getName() + " and "
> +						+ rootRelation.getName());
> +				p.link(rootRelation);
> +
> +				print("created new DIA: " + dia.getName());
> +				Iterator insidePortIterator = port.insidePortList().iterator();
> +				print("looking for connected ports");
> +				int insidePortIndex = 0;
> +				while (insidePortIterator.hasNext()) { // connect each port to
> +														// the new actor
> +					IOPort insidePort = (IOPort) insidePortIterator.next();
> +					print("insidePort " + insidePortIndex + ": "
> +							+ insidePort.toString());
> +					// create a new relation
> +					print("creating new relation: " + dia.getName()
> +							+ "Relation" + insidePortIndex);
> +					TypedIORelation r = new TypedIORelation(dca, dia.getName()
> +							+ "Relation" + insidePortIndex);
> +					print("creating link between " + rootRelation.getName()
> +							+ " and " + r.getName());
> +					rootRelation.link(r);
> +
> +					// unlink the old relation
> +					insidePort.unlink(0);
> +					insidePortIndex++;
> +					// link the new one
> +					print("creating link between " + insidePort.getName()
> +							+ " and " + r.getName());
> +					insidePort.link(r);
> +					// tell the runtime engine that the connections changed
> +					dca.connectionsChanged(insidePort);
> +					dca.connectionsChanged(p);
> +				}
> +				// clean up by removing the old relations
> +				port.unlinkAllInside();
> +				inputActorIndex++;
> +				print("===============done with port " + portName
> +						+ "===============");
> +			}
> +		} catch (Exception e) {
> +			print("Error: " + e.getMessage());
> +			e.printStackTrace();
> +			throw new RemoteException("Error converting ports to "
> +					+ "DistributedInputActors: " + e.getMessage());
> +		}
> +
> +		// handle port parameters
> +		/*
> +		 * Port parameters are an Attribute with an embedded port. They need to
> +		 * be replaced with a DistributedPortParam which will allow the slave to
> +		 * add data to the portparam remotely via rmi
> +		 */
> +		portParamList = dca.attributeList(PortParameter.class);
> +		portParamIterator = null;
> +		if (portParamList != null) {
> +			portParamIterator = portParamList.iterator();
> +		}
> +		// find all the port params and replace with distributePortParameter
> +		int portParamCount = 0;
> +		while (portParamIterator.hasNext()) {
> +			PortParameter pp = (PortParameter) portParamIterator.next();
> +			String ppName = pp.getName();
> +			print("++++++++++++procesing port param: " + ppName
> +					+ "++++++++++++++");
> +			// remove the original port param so we don't get naming conflicts
> +			// pp.setName(ppName + "old");
> +			// pp.setContainer(null);
> +			// DistributedPortParameter dpp = new DistributedPortParameter(dca,
> +			// ppName);
> +			inputActorHash.put("DIA" + pp.getName(), pp);
> +			// dpp.setExpression(pp.getExpression());
> +			print("++++++++++++done with port param: " + ppName
> +					+ "++++++++++++++");
> +		}
> +
> +		// DEBUG: prints out the finished model from the toplevel object
> +		try {
> +			File f = new File("master-slave/dynmodel-finished.xml");
> +			FileWriter fw = new FileWriter(f);
> +			fw.write(toplevel.exportMoML(), 0, toplevel.exportMoML().length());
> +			fw.flush();
> +			fw.close();
> +			print("wrote " + f.getAbsolutePath());
> +		} catch (Exception e) {
> +			print("error writing tmp file: " + e.getMessage());
> +		}
> +
> +		if (inputActorHash.size() == 0) {
> +			// if we can't find the DIA, throw an exception
> +			throw new RemoteException(
> +					"Could not locate a DistributedInputActor "
> +							+ "which must be included in a distributed workflow.");
> +		}
> +
> +		Iterator outputPortItt = dca.outputPortList().iterator();
> +		while (outputPortItt.hasNext()) {
> +			IOPort outputPort = (IOPort) outputPortItt.next();
> +			outputHash.put(outputPort.getName(), outputPort);
> +		}
> +
> +		try {
> +			print("loadActor workspace " + workspace);
> +			_manager = new Manager(workspace, "VergilApplication");
> +
> +			print("loadActor _manager " + _manager);
> +			toplevel.setManager(_manager);
> +		} catch (Exception e) {
> +			print("error parsing topLevel xml: " + e.getMessage());
> +		}
> +
> +		print("loadActor toplevel " + toplevel);
> +		toplevel.addChangeListener(this);
> +		_manager.addExecutionListener(this);
> +		print("loadActor end " + this);
> +
> +	}
> +
> +	// TODO start the remote immediately, it will wait for tokens?
> +	/**
> +	 * Main processing method for the SlaveController object
> +	 * 
> +	 *@exception Exception
> +	 *                Description of the Exception
> +	 */
> +	public void run(SlaveAccessToken token) throws Exception,
> +			InvalidTokenException {
> +		// check to make sure the token is valid
> +		checkTokenValidity(token);
> +
> +		jobStatus = JOB_RUNNING;
> +		jobProgress = 1;
> +		print("Slave begin to run: " + _manager);
> +		_manager.execute();
> +		print("Slave executed: ");
> +
> +		// PtExecuteApplication uses _activeCount to determine when
> +		// the models are done. We can't do that here because
> +		// executeError() might be called from a different thread.
> +		// PtExecuteApplication handles this by deferring the change
> +		// to the Swing event thread. We don't have a Swing event thread,
> +		// so we are stuck with a busy loop.
> +		while (!_executionFinishedOrError) {
> +			Thread.yield();
> +		}
> +
> +		if (_sawThrowable != null) {
> +			if (_sawThrowable instanceof Exception) {
> +				jobStatus = JOB_ERROR;
> +				_sawThrowable.printStackTrace();
> +				throw (Exception) _sawThrowable;
> +			} else {
> +				jobStatus = JOB_ERROR;
> +				Exception x = new Exception();
> +				x.printStackTrace();
> +				x.initCause(_sawThrowable);
> +				throw x;
> +			}
> +		}
> +
> +		jobStatus = NO_JOB;
> +	}
> +
> +	/**
> +	 * Adds tokens to the remote workflow. Shortcut for,
> +	 * InputCommunicationStubActor.put( Token[] tokens )
> +	 * 
> +	 *@param tokens
> +	 *            Description of the Parameter
> +	 *@exception RemoteException
> +	 *                Description of the Exception
> +	 *@exception IOException
> +	 *                Description of the Exception
> +	 */
> +	public void put(Token[] tokens, String portName) throws RemoteException,
> +			IOException {
> +		print("tokens coming from port: " + portName);
> +		for (int i = 0; i < tokens.length; i++) {
> +			print("token: " + tokens[i].toString());
> +		}
> +		String actorName = "DIA" + portName;
> +		RemoteActor ro = (RemoteActor) inputActorHash.get(actorName);
> +
> +		// DistributedInputActor dia =
> +		// (DistributedInputActor)inputActorHash.get(actorName);
> +		// put the RMI data on the DistributedInputActor
> +		print("loading remote data onto " + actorName);
> +
> +		ro.loadRemoteData(tokens);
> +	}
> +
> +	/**
> +	 * The master/recieving workflow should call this method and have a thread
> +	 * waiting for the return, if more iteration results are expected. Shortcut
> +	 * for, OutputCommunicationStubActor.get( )
> +	 * 
> +	 * @param portName
> +	 *            portName the name of the port to get data from
> +	 * @return Description of the Return Value
> +	 * @exception RemoteException
> +	 *                Description of the Exception
> +	 * @exception IOException
> +	 *                Description of the Exception
> +	 */
> +	public Token[] get(String portName) throws RemoteException, IOException {
> +		print("SlaveController get");
> +		IOPort port = (IOPort) outputHash.get(portName);
> +		if (port == null) {
> +			throw new RemoteException("The port '" + portName
> +					+ "' does not exist " + "on this slave.");
> +		}
> +
> +		try {
> +			Token temp = port.get(0);
> +			if (temp.toString().equals("NULL")) {
> +				return null;
> +			} else {
> +				print("SlaveController get token: " + temp);
> +				temp = checkDataToken(temp);
> +				print("SlaveController get token after check data token: "
> +						+ temp);
> +				return new Token[] { temp };
> +			}
> +		} catch (Throwable e) {
> +			e.printStackTrace();
> +		}
> +		return new Token[] { new StringToken("remote token return failed") };
> +	}
> +
> +	// /////////////////////////////////////////////////////////////////
> +	// // Workflow execution methods ////
> +
> +	/**
> +	 * React to a change request has been successfully executed by doing
> +	 * nothing. This method is called after a change request has been executed
> +	 * successfully. In this class, we do nothing.
> +	 * 
> +	 *@param change
> +	 *            The change that has been executed, or null if the change was
> +	 *            not done via a ChangeRequest.
> +	 */
> +	public void changeExecuted(ChangeRequest change) {
> +
> +	}
> +
> +	/**
> +	 * React to a change request that has resulted in an exception. This method
> +	 * is called after a change request was executed, but during the execution
> +	 * in an exception was thrown. This method throws a runtime exception with a
> +	 * description of the original exception.
> +	 * 
> +	 *@param change
> +	 *            The change that was attempted or null if the change was not
> +	 *            done via a ChangeRequest.
> +	 *@param exception
> +	 *            The exception that resulted.
> +	 */
> +	public void changeFailed(ChangeRequest change, Exception exception) {
> +		// If we do not implement ChangeListener, then ChangeRequest
> +		// will print any errors to stdout and continue.
> +		// This causes no end of trouble with the test suite
> +		// We can't throw an Exception here because this method in
> +		// the base class does not throw Exception.
> +		String description = "";
> +
> +		if (change != null) {
> +			description = change.getDescription();
> +		}
> +
> +		throw new RuntimeException("MoMLSimplApplication.changeFailed(): "
> +				+ description + " failed: ", exception);
> +	}
> +
> +	/**
> +	 * Report an execution failure. This method will be called when an exception
> +	 * or error is caught by a manager. Exceptions are reported this way when
> +	 * the run() or startRun() methods of the manager are used to perform the
> +	 * execution. If instead the execute() method is used, then exceptions are
> +	 * not caught, and are instead just passed up to the caller of the execute()
> +	 * method. Those exceptions are not reported here (unless, of course, the
> +	 * caller of the execute() method does so). In this class, we set a flag
> +	 * indicating that execution has finished.
> +	 * 
> +	 *@param manager
> +	 *            The manager controlling the execution.
> +	 *@param throwable
> +	 *            The throwable to report.
> +	 */
> +	public void executionError(Manager manager, Throwable throwable) {
> +		jobStatus = JOB_ERROR;
> +		jobProgress = -1;
> +		_executionFinishedOrError = true;
> +		_sawThrowable = throwable;
> +		throw new RuntimeException("Execution error "
> +				+ Thread.currentThread().getName(), throwable);
> +	}
> +
> +	/**
> +	 * Report that the current execution has finished and the wrapup sequence
> +	 * has completed normally. The number of successfully completed iterations
> +	 * can be obtained by calling getIterationCount() on the manager. In this
> +	 * class, we set a flag indicating that execution has finished.
> +	 * 
> +	 *@param manager
> +	 *            The manager controlling the execution.
> +	 */
> +	public void executionFinished(Manager manager) {
> +		_executionFinishedOrError = true;
> +	}
> +
> +	/**
> +	 * Report that the manager has changed state. To access the new state, use
> +	 * the getState() method of Manager. In this class, do nothing.
> +	 * 
> +	 *@param manager
> +	 *            The manager controlling the execution.
> +	 *@see Manager#getState()
> +	 */
> +	public void managerStateChanged(Manager manager) {
> +
> +	}
> +
> +	/**
> +	 * Execute the same model again.
> +	 * 
> +	 *@exception Exception
> +	 *                if there was a problem rerunning the model.
> +	 */
> +	public void rerun() throws Exception {
> +		_manager.execute();
> +	}
> +
> +	/**
> +	 * the master calls this when it's ready for the slave to run
> +	 */
> +	public void ready(SlaveAccessToken token) throws InvalidTokenException {
> +		checkTokenValidity(token);
> +		try {
> +			print("%%%%%%%%%%%%%%%%%%running kepler remotely%%%%%%%%%%%%%%%%%%%%%%%");
> +			run(token);
> +			print("$$$$$$$$$$$$$$$$$$done running kepler remotely$$$$$$$$$$$$$$$$$$");
> +		} catch (Throwable t) {
> +			// TODO: this method should be returning exceptions to the master
> +			print("Error running kepler on slave: " + t.getMessage());
> +			t.printStackTrace();
> +		}
> +	}
> +
> +	// /////////////////////////////////////////////////////////////////
> +	// // File Server methods ////
> +
> +	/**
> +	 * Register a file to be read remotely, the location according to
> +	 * <code>token</code>.
> +	 * 
> +	 * @return a randomly generated cookie
> +	 */
> +	public String registerFile(DataToken token) throws IOException {
> +		if (token == null) {
> +			// TODO return null or error?
> +			return null;
> +		}
> +		String cookieString = token.getCookie();
> +		files.put(cookieString, token.getRandomAccessFile());
> +
> +		return cookieString;
> +	}
> +
> +	/**
> +	 * Register a file with this <code>cookie</code> to be read remotely, the
> +	 * location according to <code>token</code>.
> +	 */
> +	public void registerFile(DataToken token, String cookie) throws IOException {
> +		if (token == null)
> +			return;
> +		if (cookie == null || cookie.length() == 0)
> +			throw new NullPointerException("Cookie cannot be null");
> +
> +		files.put(cookie, token.getRandomAccessFile());
> +	}
> +
> +	/**
> +	 * Remote system reads the file registered as <code>cookie</code>
> +	 */
> +	public byte[] read(String cookie, long seek, int length)
> +			throws RemoteException, IOException {
> +		/*
> +		 * Need a byte buffer as a return value so it transfers the bytes
> +		 * through the rmi connection, instead of transfering a memory pointer
> +		 * around the jvm.
> +		 */
> +		LocalRandomAccessFile file = (LocalRandomAccessFile) files.get(cookie);
> +		if (file == null)
> +			throw new FileNotFoundException();// TODO?
> +
> +		byte[] buffer = new byte[length];
> +		synchronized (file) {
> +			if (file.getFilePointer() != seek) {
> +				// suppose it is more efficient to check first?
> +				file.seek(seek);
> +			}
> +			file.read(buffer);
> +		}
> +		return buffer;
> +	}
> +
> +	/**
> +	 * Remote system reads the file registered as <code>cookie</code>
> +	 */
> +	public long length(String cookie) throws RemoteException, IOException {
> +		LocalRandomAccessFile file = (LocalRandomAccessFile) files.get(cookie);
> +		if (file == null)
> +			throw new FileNotFoundException();// TODO or just return 0;?
> +
> +		return file.length();
> +	}
> +
> +	/**
> +	 * Checks this token to see if it is a StringToken meant to represent local
> +	 * files. If so, it is changed those a DataTokens for remote access.
> +	 */
> +	protected Token checkDataToken(Token token) throws IOException {
> +		if (token instanceof StringToken) {
> +			String tokenVal = ((StringToken) token).stringValue();
> +			// comment the following sentences because the file may be
> +			// represented without beginning with 'file:/'
> +			// if(!tokenVal.startsWith("file:/"))
> +			// {
> +			// print("string datatoken: " + token);
> +			// return token;
> +			// }
> +
> +			if (token instanceof DataToken) {
> +				// if the DataToken references a local file, e.g. file://
> +				// makes sure the reference is universal, accessible from the
> +				// slave.
> +				File temp = new File(((StringToken) token).stringValue());
> +				if (!temp.isDirectory()) {
> +					print("registering token as datatoken: " + temp.toURI());
> +					registerFile((DataToken) token);
> +				}
> +			} else {
> +				File temp = new File(((StringToken) token).stringValue());
> +				if (temp.exists() && !temp.isDirectory()) {
> +					// if the string is a valid filepath
> +					// TODO? *assumes* the string is meant to actually be that
> +					// file.
> +					print("registering token as datatoken: " + temp.toURI());
> +					token = new DataToken(temp.toURI());
> +					registerFile((DataToken) token);
> +				}
> +
> +			}
> +		}
> +		return token;
> +	}
> +
> +	/**
> +	 * Checks these tokens to see if they contain StringTokens meant to
> +	 * represent local files. Changes those tokens to DataTokens for remote
> +	 * access.
> +	 */
> +	protected Token[] checkDataTokens(Token[] tokens) throws IOException {
> +		for (int i = 0; i < tokens.length; i++) {
> +			tokens[i] = checkDataToken(tokens[i]);
> +		}
> +		return tokens;
> +	}
> +
> +	/**
> +	 * register this node with a node registry
> +	 * 
> +	 * @param serverName
> +	 *            the name of the server (from the repositoryBundle) to use to
> +	 *            connect to the registry
> +	 * @param hostName
> +	 *            the name of this host as it should be registered in the
> +	 *            registry (i.e. hostname or IP address, etc)
> +	 */
> +	protected void registerNode(String serverName) throws RepositoryException {
> +		print("registering node with the the repository " + serverName);
> +		try {
> +			RepositoryManager repMan = RepositoryManager.getInstance();
> +			Repository rep = repMan.getRepository(serverName);
> +			if (!(rep instanceof EcogridRepository)) {
> +				throw new RepositoryException(
> +						"The repository must be an EcogridRepository.");
> +			}
> +			EcogridRepository ecorep = (EcogridRepository) rep;
> +			// String regFile = createRegistryFile();
> +			RegistryEntryType regEntry = createRegistryEntryType();
> +			// print("regFile: " + regFile);
> +			registryFileLSID = ecorep.addRegistryEntry(regEntry).toString();
> +			print("Server registered.  Registration file id: "
> +					+ registryFileLSID.toString());
> +		} catch (Exception e) {
> +			throw new RepositoryException(
> +					"Could not register with the ecogrid: " + e.getMessage());
> +		}
> +	}
> +
> +	/**
> +	 * remove this slave as a compute node on the grid
> +	 * 
> +	 * @param serverName
> +	 *            the name of the server (from the repositoryBundle) to
> +	 *            deregister from
> +	 */
> +	protected void deregisterNode(String serverName) throws RepositoryException {
> +		// delete the file that registers this node on the grid
> +		print("deregistering node with the the repository " + serverName);
> +		try {
> +			RepositoryManager repMan = RepositoryManager.getInstance();
> +			Repository rep = repMan.getRepository(serverName);
> +			if (!(rep instanceof EcogridRepository)) {
> +				throw new RepositoryException(
> +						"The repository must be an EcogridRepository.");
> +			}
> +			EcogridRepository ecorep = (EcogridRepository) rep;
> +			ecorep.removeRegistryEntry(new KeplerLSID(registryFileLSID));
> +			print("Server deregistered.  Registry file " + registryFileLSID
> +					+ " removed from registry");
> +		} catch (Exception e) {
> +			throw new RepositoryException(
> +					"Could not deregister with the ecogrid: " + e.getMessage());
> +		}
> +	}
> +
> +	/**
> +	 * do any additional cleanup that is needed.
> +	 */
> +	protected void cleanUp() {
> +
> +	}
> +
> +	// /////////////////////////////////////////////////////////////////
> +	// // JobController Methods ////
> +
> +	private Vector credentials = new Vector();
> +
> +	/**
> +	 * return the status of the last job. The status codes that can be returned
> +	 * are: JOB_STOPPED: the current job is stopped JOB_RUNNING: the current job
> +	 * is running JOB_RESTARTING: the current job is restarting, but not yet
> +	 * running JOB_INITIALIZING: the current job is initializing NO_JOB: there
> +	 * is no job
> +	 */
> +	public int getJobStatus(Credential credential) throws RemoteException,
> +			IOException, CredentialException {
> +		checkCredentials(credential);
> +		return jobStatus;
> +	}
> +
> +	/**
> +	 * return the status of the job. The status codes that can be returned are:
> +	 * JOB_RUNNING: the slave is processing a job NO_JOB: there is no job on
> +	 * this slave
> +	 */
> +	public int getSlaveState(Credential credential) throws RemoteException,
> +			IOException, CredentialException {
> +		checkCredentials(credential);
> +		return jobStatus;
> +	}
> +
> +	/**
> +	 * return the progress of a job. the return value is an integer between -1
> +	 * and 100 where -1 means an error occured, 0 is "just started" and 100 is
> +	 * "finished". An implementer does not necessarily have to return any number
> +	 * between 0 and 100 if progress cannot be determined, but should always
> +	 * return 0 or 100 if a job is just begun or is finished.
> +	 */
> +	public int progress(Credential credential) throws RemoteException,
> +			IOException, CredentialException {
> +		// first check the credential to see if the person can view this info
> +		checkCredentials(credential);
> +		return jobProgress;
> +	}
> +
> +	/**
> +	 * Starts a job that has been stopped. Does nothing if the job is already
> +	 * started.
> +	 */
> +	public void start(Credential credential) throws RemoteException,
> +			IOException, CredentialException {
> +		// This method does not currently make much sense due to the fact that
> +		// once a process is stopped, the slave is released. to make this method
> +		// useful, we'll need to implement a way that a job can live without
> +		// releasing the slave. Same with the restart method.
> +
> +		// first check the credential to see if the person can view this info
> +		checkCredentials(credential);
> +		throw new RemoteException("start() is not yet implemented.");
> +	}
> +
> +	/**
> +	 * Stops a job that is running. Does nothing if the job is already stopped.
> +	 */
> +	public void stop(Credential credential) throws RemoteException,
> +			IOException, CredentialException {
> +		print("Stopping execution...");
> +		// first check the credential to see if the person can view this info
> +		checkCredentials(credential);
> +		// throw new RemoteException("stop() is not yet implemented.");
> +		stopExecution();
> +		print("Execution stopped.");
> +	}
> +
> +	/**
> +	 * restarts a job. If a job is not restartable due to data contraints, or
> +	 * other reason, this should throw a NotRestartableException
> +	 */
> +	public void restart(Credential credential) throws RemoteException,
> +			IOException, NotRestartableException, CredentialException {
> +		// see comment on the start() method.
> +
> +		// first check the credential to see if the person can view this info
> +		checkCredentials(credential);
> +		throw new RemoteException("restart() is not yet implemented.");
> +	}
> +
> +	/**
> +	 * authenticate a user and return a credential which can be passed to the
> +	 * other functions of this interface to prove authentication.
> +	 */
> +	public Credential authenticate(String username, String password)
> +			throws RemoteException, IOException,
> +			org.kepler.authentication.AuthenticationException {
> +
> +		// first check to see if the user is allowed to access this slave
> +		boolean allowed = processUserInACL(username);
> +		if (!allowed) {
> +			throw new AuthenticationException("The user " + username + " has "
> +					+ "not been granted access to this slave node.");
> +		}
> +
> +		try {
> +			// now authenticate the user via the EarthGrid/LDAP
> +			AuthenticationManager authMan = AuthenticationManager.getManager();
> +			AuthenticationService service = authMan
> +					.getAuthenticationService("SEEK");
> +			Domain d = AuthenticationManager.getDomain("SEEK");
> +			ProxyEntity pentity = ((LDAPAuthenticationService) service)
> +					.authenticate(d, username, password);
> +			authMan.addProxyEntity(pentity);
> +			String sessionid = pentity.getCredential();
> +			// credential is valid for 24 hours
> +			Credential credential = new Credential(username, sessionid, System
> +					.currentTimeMillis() + 86400000);
> +			credentials.add(credential);
> +			return credential;
> +		} catch (AuthenticationException ae) {
> +			ae.printStackTrace();
> +			throw ae;
> +		}
> +	}
> +
> +	/**
> +	 * return the current cpu usage which should be an integer between 0 and
> +	 * 100.
> +	 */
> +	public int getCPUUsage() throws RemoteException, IOException {
> +		// implementing this method will require writing a JNI interface to
> +		// some C code because java doesn't let you look at cpu usage. This is
> +		// described here:
> +		// http://www.javaworld.com/javaworld/javaqa/2002-11/01-qa-1108-cpu.html
> +		// This isn't important enough of a feature to spend time on this right
> +		// now so i'll come back to it. -cb
> +		throw new RemoteException("getCPUUsage() is not yet implemented.");
> +	}
> +
> +	/**
> +	 * return the current memory usage
> +	 */
> +	public MemoryUsage getMemoryUsage() throws RemoteException, IOException {
> +		// get the free, total and max memory from the runtime object
> +		long freeMem = Runtime.getRuntime().freeMemory();
> +		long totalMem = Runtime.getRuntime().totalMemory();
> +		long maxMem = Runtime.getRuntime().maxMemory();
> +		return new MemoryUsage(totalMem, freeMem, maxMem);
> +	}
> +
> +	/**
> +	 * returns true if the implementing node is available to accept jobs, false
> +	 * otherwise.
> +	 */
> +	public boolean available() throws RemoteException, IOException {
> +		// if this slave is available, return true.
> +		if (currentToken == null) {
> +			return true;
> +		}
> +		return false;
> +	}
> +
> +	/**
> +	 * get the username of the current user
> +	 */
> +	public String getCurrentUser() throws RemoteException, IOException {
> +		if (currentToken == null) {
> +			return "None";
> +		}
> +
> +		return currentToken.getCredential().getUsername();
> +	}
> +
> +	/**
> +	 * request to use the slave for execution. this method returns an access
> +	 * token which must be used to make requests to the slave. when the
> +	 * credential expires, the slave will cancel any running jobs and revert to
> +	 * being available to other clients. If a job is still running, the
> +	 * expiration time can be incremented by calling requestSlave() additional
> +	 * times to get a new token.
> +	 */
> +	public synchronized SlaveAccessToken requestSlave(Credential c)
> +			throws RemoteException, IOException {
> +		try {
> +			boolean credcheck = checkCredentials(c);
> +			if (!credcheck) {
> +				throw new RemoteException(
> +						"Invalid credentials.  User "
> +								+ c.getUsername()
> +								+ " is not authorized to use this slave or has an expired credential.");
> +			}
> +		} catch (Exception e) {
> +			throw new RemoteException("Error checking credentials: "
> +					+ e.getMessage());
> +		}
> +
> +		if (currentToken == null) { // if the currentToken is null the the slave
> +									// is available
> +			long currentTime = System.currentTimeMillis();
> +
> +			currentToken = new SlaveAccessToken(
> +					EXPIRATION_LENGTH + currentTime, c);
> +			// start a thread to check if the token is expired
> +			checker = new SlaveTokenChecker();
> +			checkerStop = false;
> +			checker.start();
> +		} else { // if the currentToken is not null, allow the user to request
> +					// more time
> +			// be added to the token. we may want to impose a limit on the
> +			// number
> +			// of times this can be done or else a user might never release a
> +			// slave
> +			// but i won't implement that right now.
> +			long currentTime = System.currentTimeMillis();
> +			currentToken = new SlaveAccessToken(
> +					EXPIRATION_LENGTH + currentTime, c);
> +		}
> +		return currentToken;
> +	}
> +
> +	/**
> +	 * release the slave to be used by other clients
> +	 */
> +	public void releaseSlave() throws RemoteException, IOException { // releas
> +																		// the
> +																		// slave
> +																		// by
> +																		// setting
> +																		// currentToken
> +																		// to
> +																		// null
> +		release();
> +	}
> +
> +	/**
> +	 * returns the host name of this slave
> +	 */
> +	public String getHostname() throws RemoteException, IOException {
> +		return hostName;
> +	}
> +
> +	/**
> +	 * returns the lsid of the registry document that is registering this node.
> +	 * if the node is not registered, it returns null
> +	 */
> +	public String getRegistryId() throws RemoteException, IOException {
> +		return registryFileLSID;
> +	}
> +
> +	/**
> +	 * checks to see if the given credential is valid. returns true if it is,
> +	 * throw a CredentialException if it isn't.
> +	 */
> +	private boolean checkCredentials(Credential credential)
> +			throws CredentialException {
> +		for (int i = 0; i < credentials.size(); i++) {
> +			Credential c = (Credential) credentials.elementAt(i);
> +			// print("c: " + c.toString());
> +			// print("checking credential: " + credential.toString());
> +			if (c.equals(credential) && !c.isExpired()) {
> +				return true;
> +			}
> +		}
> +		throw new CredentialException("Invalid credentials.  Access denied.");
> +	}
> +
> +	/**
> +	 * check to see if the username is allowed to access this slave
> +	 */
> +	private boolean processUserInACL(String username) {
> +		// if(true)return true;
> +		if (aclOrder.equals("allowFirst")) { // process the allows, then remove
> +												// the denys
> +			if (allowedUsers[0].trim().equals("all")) { // allow all then remove
> +														// a few
> +				for (int i = 0; i < deniedUsers.length; i++) {
> +					if (deniedUsers[i].trim().equals(username)) { // the user is
> +																	// in the
> +																	// deny list
> +						return false;
> +					}
> +				}
> +				return true;
> +			} else { // allow specific users, then deny them
> +				boolean allowed = false;
> +				for (int i = 0; i < allowedUsers.length; i++) {
> +					if (allowedUsers[i].trim().equals(username)) {
> +						allowed = true;
> +					}
> +				}
> +
> +				for (int i = 0; i < deniedUsers.length; i++) {
> +					if (deniedUsers[i].trim().equals(username)) {
> +						allowed = false;
> +					}
> +				}
> +
> +				return allowed;
> +			}
> +		} else if (aclOrder.equals("denyFirst")) { // process the denies, then
> +													// add the allows
> +			print("processing " + username);
> +			if (deniedUsers[0].trim().equals("all")) { // deny all then add a
> +														// few
> +				for (int i = 0; i < allowedUsers.length; i++) {
> +					print(allowedUsers[i] + "   " + username);
> +					if (allowedUsers[i].trim().equals(username)) { // the user
> +																	// is in the
> +																	// allow
> +																	// list
> +						return true;
> +					}
> +				}
> +				return false;
> +			} else { // deny specific users, then allow them
> +				boolean allowed = false;
> +				for (int i = 0; i < deniedUsers.length; i++) {
> +					if (deniedUsers[i].equals(username)) {
> +						allowed = false;
> +					}
> +				}
> +
> +				for (int i = 0; i < allowedUsers.length; i++) {
> +					if (allowedUsers[i].trim().equals(username)) {
> +						allowed = true;
> +					}
> +				}
> +
> +				return allowed;
> +			}
> +		} else { // if the aclOrder is not denyFirst or allowFirst, something
> +					// weird
> +			// is going on (this was already checked) so just deny access.
> +			return false;
> +		}
> +	}
> +
> +	// /////////////////////////////////////////////////////////////////
> +	// // Main methods ////
> +
> +	/**
> +	 * Create an instance of a single model and run it. args: -register=true set
> +	 * if you want the slave to register itself with the ecogrid so other kepler
> +	 * instances can find it. this defaults to false unless you provide
> +	 * -registrationServer -userlist=<userlist> a filename of an ACL in the
> +	 * format of the file
> +	 * master-slave/resources/system.properties/DistributedKeplerSlaveACL.config. If no
> +	 * filename is provided the preceding file will be used.
> +	 * -registrationServer=<ecogridServer> the server that this node should be
> +	 * registered on as defined in the repositoryBundle. It defaults to use the
> +	 * 'keplerRepository' in repositoryBundle if -register is true and
> +	 * registrationServer is not set. -hostName=<hostname | host ip address> the
> +	 * name or ip address of this host as you want it registered on the network.
> +	 * If this is not provided, "localhost" will be used.
> +	 * 
> +	 *@param args
> +	 *            The command-line arguments
> +	 * 
> +	 */
> +	public static void main(String[] args) {
> +		boolean register = false;
> +		String userlist = "";
> +		String regServer = "";
> +		String hostname = "";
> +
> +		DataToken testFile = null;
> +
> +		// process the user params
> +		try {
> +			for (int i = 0; i < args.length; i++) {
> +				print("Using option: " + args[i]);
> +				if (args[i].indexOf("-register") != -1) {
> +					String regvalue = args[i].substring(
> +							args[i].indexOf("=") + 1, args[i].length());
> +					Boolean b = new Boolean(regvalue);
> +					register = b.booleanValue();
> +				} else if (args[i].indexOf("-userlist") != -1) {
> +					userlist = args[i].substring(args[i].indexOf("=") + 1,
> +							args[i].length());
> +				} else if (args[i].indexOf("-registrationServer") != -1) {
> +					regServer = args[i].substring(args[i].indexOf("=") + 1,
> +							args[i].length());
> +				} else if (args[i].indexOf("-hostName") != -1) {
> +					hostname = args[i].substring(args[i].indexOf("=") + 1,
> +							args[i].length());
> +				} else if (args[i].indexOf("-testFile") != -1) {
> +					testFile = new DataToken(new File(args[i].substring(args[i]
> +							.indexOf("=") + 1, args[i].length())).toURI());
> +				}
> +			}
> +
> +			// run the slave controller
> +			SlaveController sc = null;
> +			try {
> +				sc = new SlaveController(register, userlist, regServer,
> +						hostname);
> +				if (testFile != null) {
> +					print(sc.registerFile(testFile));
> +				}
> +			} catch (Exception e) {
> +				print("There was an error running the slave: " + e.getMessage());
> +				e.printStackTrace();
> +				System.exit(1);
> +			}
> +
> +			System.out.println("Type X to exit (do not use ^C) ");
> +			// wait for user input
> +			while (true) {
> +				byte[] b = new byte[1024];
> +				int numread = System.in.read(b);
> +				String input = new String(b);
> +				if (input.trim().equals("x") || input.trim().equals("X")
> +						|| input.trim().equals("exit")) { // this allows us to
> +															// deregister the
> +															// node and clean up
> +															// any temp files
> +					if (register) {
> +						System.out
> +								.println("Deregistering this node...Please do not cancel this operation!");
> +						sc.deregisterNode(serverName);
> +					}
> +					System.out.println("Cleaning up...");
> +					sc.cleanUp();
> +					System.out.println("Done.");
> +					System.exit(0);
> +				} else {
> +					System.out.println("Type X to exit (do not use ^C) ");
> +				}
> +
> +			}
> +		} catch (Throwable ex) {
> +			System.err.println("Command failed: " + ex);
> +			ex.printStackTrace();
> +		}
> +	}
> +
> +	// ////////////////////////////////////////////////////////////////
> +	// /// Private utility methods //////
> +
> +	/**
> +	 * process the command line params. called from the constructor
> +	 */
> +	private void processParams(boolean register, String userList,
> +			String regServer) throws RepositoryException {
> +		if (regServer.equals("")) {
> +			serverName = "keplerRepository";
> +		} else {
> +			serverName = regServer;
> +		}
> +
> +		if (register) { // we need to register with the network
> +			registerNode(serverName);
> +		}
> +
> +		if (userList == null || userList.equals("")) { // set the users that can
> +														// access this node
> +			userList = "master-slave/resources/system.properties/DistributedKeplerSlaveACL.config";
> +		}
> +
> +		try {
> +			processUserList(userList);
> +			for (int i = 0; i < allowedUsers.length; i++) {
> +				print("Allowed user: " + allowedUsers[i]);
> +			}
> +			for (int i = 0; i < deniedUsers.length; i++) {
> +				print("Denied user: " + deniedUsers[i]);
> +			}
> +			print("ACL Order: " + aclOrder);
> +
> +		} catch (Exception e) {
> +			throw new RepositoryException("Could not process the user list.  "
> +					+ "No one will be able to connect to the slave!: "
> +					+ e.getMessage());
> +		}
> +	}
> +
> +	/**
> +	 * build the ACL rules from the given userList
> +	 */
> +	private void processUserList(String userList) throws Exception {
> +		// fill these global variables
> +		/*
> +		 * String aclOrder; String[] allowedUsers; String[] deniedUsers;
> +		 */
> +
> +		// read the file
> +		File f = new File(userList);
> +		FileReader fr = new FileReader(f);
> +		char[] c = new char[1024];
> +		int numread = fr.read(c, 0, 1024);
> +		StringBuffer sb = new StringBuffer();
> +		while (numread != -1) {
> +			sb.append(new String(c, 0, numread));
> +			numread = fr.read(c, 0, 1024);
> +		}
> +		String s = sb.toString();
> +
> +		// process the string
> +		// look for the order
> +		int orderIndex = s.indexOf("<order>");
> +		int endOrderIndex = s.indexOf("</order>");
> +		if (orderIndex == -1 || endOrderIndex == -1) {
> +			throw new Exception(
> +					"Order attribute must exist in ACL and be closed.");
> +		}
> +		aclOrder = s.substring(orderIndex + 7, endOrderIndex).trim();
> +		if (!aclOrder.equals("allowFirst") && !aclOrder.equals("denyFirst")) {
> +			throw new Exception(
> +					"the order must either be 'allowFirst' or 'denyFirst'");
> +		}
> +
> +		// look for the allows
> +		int allowIndex = s.indexOf("<allow>");
> +		int endAllowIndex = s.indexOf("</allow>");
> +		if (allowIndex == -1 || endAllowIndex == -1) {
> +			throw new Exception(
> +					"Allow attribute must exist in ACL and be closed.");
> +		}
> +		String allowList = s.substring(allowIndex + 7, endAllowIndex);
> +		allowedUsers = allowList.trim().split("\n");
> +
> +		// look for the denys
> +		int denyIndex = s.indexOf("<deny>");
> +		int endDenyIndex = s.indexOf("</deny>");
> +		if (denyIndex == -1 || endDenyIndex == -1) {
> +			throw new Exception(
> +					"Deny attribute must exist in ACL and be closed.");
> +		}
> +		String denyList = s.substring(denyIndex + 6, endDenyIndex);
> +		deniedUsers = denyList.trim().split("\n");
> +	}
> +
> +	/**
> +	 * creates a document to send to the ecogrid to register this node.
> +	 * 
> +	 * @deprecated Please use objects, not strings of xml
> +	 */
> +	private String createRegistryFile() {
> +		// create a uuid to uniquely identify each entry
> +		// this is needed because the ecogrid registry does not support LSIDs to
> +		// uniquely identify entries
> +		UUID uuid = UUID.randomUUID();
> +		String uuidStr = uuid.toString();
> +		StringBuffer sb = new StringBuffer();
> +		sb.append("<?xml version=\"1.0\"?>\n");
> +		sb
> +				.append("<reg:RegistryEntry xmlns:reg=\"http://ecoinformatics.org/registryentry-1.0.0\"  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n");
> +		sb.append("<serviceName>KeplerRemoteComputeNode</serviceName>\n");
> +		sb.append("<wsdlURL>none</wsdlURL>\n");
> +		sb.append("<serviceType>KeplerSlaveNode</serviceType>\n");
> +		sb.append("<endPoint>" + hostName + "</endPoint>\n");
> +		sb
> +				.append("<serviceClassification>EcogridServiceRegistry</serviceClassification>\n");
> +		sb.append("<description>Kepler RMI Slave Controller</description>\n");
> +		sb.append("<id>" + uuidStr + "</id>\n");
> +		sb.append("<documentType>\n");
> +		sb
> +				.append("  <namespace>eml://ecoinformatics.org/eml-2.0.0</namespace>\n");
> +		sb.append("  <label>Ecological Metadata Language 2.0.0</label>\n");
> +		sb.append("</documentType>\n");
> +		sb.append("<documentType>\n");
> +		sb
> +				.append("  <namespace>eml://ecoinformatics.org/eml-2.0.1</namespace>\n");
> +		sb.append("  <label>Ecological Metadata Language 2.0.1</label>\n");
> +		sb.append("</documentType>\n");
> +		sb.append("</reg:RegistryEntry>\n");
> +
> +		// Example File
> +		/*
> +		 * <reg:RegistryEntry
> +		 * xmlns:reg="http://ecoinformatics.org/registryentry-1.0.0"
> +		 * xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
> +		 * <serviceName>KNB Metacat EcoGrid QueryInterface</serviceName>
> +		 * <wsdlURL
> +		 * >http://ecogrid.ecoinformatics.org/knb/schema/QueryService/QueryService
> +		 * .wsdl</wsdlURL>
> +		 * <serviceType>http://ecoinformatics.org/queryservice-1.0
> +		 * .0</serviceType>
> +		 * <endPoint>http://ecogrid.ecoinformatics.org/knb/services
> +		 * /QueryService</endPoint>
> +		 * <serviceClassification>EcogridServiceRegistry</serviceClassification>
> +		 * <description>Query Level One Class</description> <documentType>
> +		 * <namespace>eml://ecoinformatics.org/eml-2.0.0</namespace>
> +		 * <label>Ecological Metadata Language 2.0.0</label> </documentType>
> +		 * <documentType>
> +		 * <namespace>eml://ecoinformatics.org/eml-2.0.1</namespace>
> +		 * <label>Ecological Metadata Language 2.0.1</label> </documentType>
> +		 * </reg:RegistryEntry>
> +		 */
> +
> +		return sb.toString();
> +	}
> +
> +	/**
> +	 * creates a document to send to the ecogrid to register this node.
> +	 */
> +	private RegistryEntryType createRegistryEntryType() {
> +		// create a uuid to uniquely identify each entry
> +		// this is needed because the ecogrid registry does not support LSIDs to
> +		// uniquely identify entries
> +		UUID uuid = UUID.randomUUID();
> +		String uuidStr = uuid.toString();
> +
> +		RegistryEntryType entry = new RegistryEntryType();
> +		entry.setDescription("Kepler RMI Slave Controller");
> +		entry.setEndPoint(hostName);
> +		// TODO: this should be using a real docid returned from the
> +		// identifierService
> +		entry.setId(uuidStr + ".1.1");
> +		entry.setServiceClassification("EcogridServiceRegistry");
> +		entry.setServiceGroup(serverName); // not sure what the group should be,
> +											// are these grouped?
> +		entry.setServiceName("KeplerRemoteComputeNode");
> +		entry.setServiceType("KeplerSlaveNode");
> +		entry.setWsdlURL("none");
> +
> +		// optional
> +		// entry.setProvider(null);
> +		// entry.setDocumentType(null);
> +
> +		return entry;
> +	}
> +
> +	/**
> +	 * returns true if the token is valid, false otherwise.
> +	 */
> +	private void checkTokenValidity(SlaveAccessToken token)
> +			throws InvalidTokenException {
> +		print("token: " + token.toString());
> +		print("currentToken: " + currentToken);
> +		if (!token.equals(currentToken)) {
> +			throw new InvalidTokenException(
> +					"SlaveAccessToken is invalid, expired or "
> +							+ "does not match the currently allowed token.  Please call "
> +							+ "requestSlave() again to get a new token.");
> +		}
> +	}
> +
> +	/**
> +	 * stops the currently executing process and releases the slave
> +	 */
> +	private void stopExecution() {
> +		_manager.stop();
> +		release();
> +	}
> +
> +	/**
> +	 * set all the variables to release the slave
> +	 */
> +	private void release() {
> +		checkerStop = true;
> +		currentToken = null;
> +		jobProgress = 0;
> +		jobStatus = NO_JOB;
> +	}
> +
> +	/**
> +	 * print a message prepended with this class's name
> +	 */
> +	private static void print(String message) {
> +		DistributedLogger.print("SlaveController: " + message,
> +				DistributedLogger.MEDIUM);
> +	}
> +
> +	/**
> +	 * a thread to periodically check if the currentToken is expired. If it is,
> +	 * we stop execution and
> +	 */
> +	private class SlaveTokenChecker extends Thread {
> +		public SlaveTokenChecker() {
> +			// empty
> +		}
> +
> +		public void run() {
> +			while (true) {
> +				if (currentToken == null) { // the slave has been released
> +					return;
> +				}
> +				long time = System.currentTimeMillis();
> +				long tokenTime = currentToken.getExpiration();
> +				if (time > tokenTime) { // if the time has exceded the
> +										// expiration, stop the execution and
> +										// return
> +					// from this thread
> +					stopExecution();
> +					return;
> +				}
> +
> +				if (checkerStop) { // if we've asked the thread to stop, return
> +					return;
> +				}
> +				// do this every 10 seconds
> +				try {
> +					sleep(10000);
> +				} catch (java.lang.InterruptedException ie) {
> +					// if we've been interrupted and the stop flag is true, then
> +					// return
> +					// from this thread
> +					if (checkerStop) {
> +						return;
> +					}
> +				}
> +			}
> +		}
> +	}
> +}
> 
> 
> 
> ------------------------------------------------------------------------
> 
> _______________________________________________
> Kepler-cvs mailing list
> Kepler-cvs at kepler-project.org
> http://mercury.nceas.ucsb.edu/kepler/mailman/listinfo/kepler-cvs


More information about the Kepler-dev mailing list