|The scriptable application manager is a generic XCAT Component, which can act as a controller for the actual applications. The actual functionality of the manager is defined by the script it loads and executes inside a Jython interpreter, and this is the way it differs from other existing XCAT components. This leads to the ability to change the behaviour of the manager at run time, and the ability to manage various applications with minimal compilation. The manager also has the capability of sprouting predefined CCA ports at runtime, so that it can communicate with other CCA components, and use the services provided by them.|
The application manager contains a Jython interpreter into which the remote script gets downloaded. The manager exports a CCA provides port called the ScriptPort, which has methods that are required to manage the applications. In particular, it has a method runScript(), which downloads the script into the interpreter, and begins execution. This returns an integer to the callee, identifying the script execution. Using this identifier, the script in execution can be killed using the killScript() method. The runScript() method can be blocking or non-blocking.
The application managers also have a variable number of MesgPorts, through which they can send messages to other components which provide such MesgPorts. Each application manager has 'n' number of UsesMesgPorts, if they need to send messages to 'n' other components. For receiving messages, each application manager has a ProvidesMesgPort, which receives the messages and stores it in a buffer for the scripts to process. The scripts can retrieve these messages from the application managers, by invoking the getMessage() method on the manager. The scripts can send messages, using the sendMessage() method of the manager. The messages that are sent are XML strings, which conform to the following schema :
<xsd:schema xmlns:xsd="http://www.w3.org/2000/10/XMLSchema" targetNamespace="http://www.extreme.indiana.edu/xcatjava/" version="0.9"> <xsd:element name="message"> <xsd:complexType> <xsd:all> <xsd:element name="source" type="string" minOccurs="1" maxOccurs="1"/> <xsd:element ref="nameValuePair" minOccurs="0" maxOccurs="unbounded"/> </xsd:all> </xsd:complexType> </xsd:element> <xsd:element name="nameValuePair"> <xsd:complexType> <xsd:all> <xsd:element name="name" type="string" minOccurs="1" maxOccurs="1"/> <xsd:element name="value" type="string" minOccurs="1" maxOccurs="1"/> </xsd:all> </xsd:complexType> </xsd:element> </xsd:schema>
As can be observed, the message consists of a string identifying the sender and a list of (name, value) pairs, which is free to be interpreted by the receiver in any appropriate manner. This schema for the XML message is still being reviewed, and may be modified if we uncover any shortcomings.
The various administrative functions for the application managers are handled by the AppManPort and the ControlPort, that each application manager provides. The AppManPort provides methods to dynamically add provides and uses ports using the addProvidesPort() and addUsesPort() methods respectively. This capability of the application manager enables the scripts running inside it to communicate with any other XCAT component. The createJavaComponent() and createCppComponent() methods can be used to create Java and C++ components respectively, on the machine the application manager is running on. Finally, the setNumMesgListeners() method can be used to set the total number of uses MesgPorts that the application manager should have. The ControlPort provides methods start() and kill(), which have obvious meanings.
The application managers have been used successfully to manage a variety of applications, e.g the NCSA Chemical Engineering Applications, the IU Xports Application, the NCSA Weather Research and Forecasting (WRF).
The following are the steps that are typically followed to set up a set of applications using the Application Managers. We illustrate it with a toy example of two application managers (a generator, and a printer), where one has a dynamically added provides port (printer) and the other a uses port (generator). A script is downloaded into the generator, which grabs hold of the just created uses port, and transfers a string to the printer.
Start the required number of components as follows :
# create a component wrapper generator = cca.createComponent(xml_description_of_application_manager) printer = cca.createComponent(xml_description_of_application_manager) # assign a machine name cca.setMachineName(generator, "exodus.extreme.indiana.edu") cca.setMachineName(printer, "exodus.extreme.indiana.edu") # set a creation mechanism cca.setCreationMechanism(generator, "gram") cca.setCreationMechanism(printer, "gram") # create a live instance print "Creating Instance" cca.createInstance(generator) cca.createInstance(printer)
For more information on how to use the Jython Builder to create and launch components, look at the Jython Builder notes.
Add the required provides and uses ports to the above application managers as follows :
# Information for the ScriptPort on which the methods are invoked usesPortClassName = "samples.idl.scriptPort.UsesScriptPort" usesPortType = "http://www.extreme.indiana.edu/xcat/samples/wsdl#scriptPort" providesPortName = "scriptPortProvidesPort" # add a provides port to the printer methodName = "addProvidesPort" methodParams = zeros(4, Object) # information about the String provides port to be added methodParams = String("providesPrint") methodParams = String("http://www.extreme.indiana.edu/xcat/samples/wsdl#string") methodParams = String("samples.idl.string.ProvidesString") methodParams = String("samples.printer.StringImpl") cca.invokeMethodOnComponent(printer, usesPortClassName, usesPortType, providesPortName, methodName, methodParams) # add a uses port to the generator methodName = "addUsesPort" methodParams = zeros(3, Object) # information about the String uses port to be added methodParams = String("usesPrint") methodParams = String("http://www.extreme.indiana.edu/xcat/samples/wsdl#string") methodParams = String("samples.idl.string.UsesString") cca.invokeMethodOnComponent(generator, usesPortClassName, usesPortType, providesPortName, methodName, methodParams)
Connect the above ports together as follows :
print "Connecting ports" cca.connectPorts(generator, "usesPrint", printer, "providesPrint")
Download a script into remote component as follows :
# download a script into the generator print "Invoking remote method" methodName = "runScript" methodParams = zeros(1, Object) codefile = open("./generator.py", "r") code = codefile.read() methodParams = code cca.invokeMethodOnComponent(generator, usesPortClassName, usesPortType, providesPortName, methodName, methodParams)
The script generator.py above does the following :
import sys print "Grabbing hold of the uses port" myPort = manager.getUsesPort("usesPrint") print "Sending string : Hello World" myPort.sendString("Hello World")