This page introduces details about the elements of JavaSymphony. Public methods for the new classes are detailed and small excerpts of code exemplify the new features.
 

VAs

    Dynamic virtual architectures (called VAs)  allow the programmer to define a structure of heterogeneous network of computing resources.
    We distinct two main types of VAs:
  1. level-2 and lower level VAs, which correspond to computing resources like a PCs, workstations, multicore machines, processors and cores. Level-0 VA represents a cores and level-1 VA represents a processors while a level-2 VA represents a multi-core machine. 
  2. higher level VAs, which defines cluster of lower level VAs: one level-3 VA represent a cluster of level-2 VAs (e.g. workstation or PC cluster), one level-4 VA represent a cluster of level-3 VAs connected (e.g. a wide area network which connects a set of clusters) and so on.

Creating VAs

     VAs are created using JavaSymphony class VA. The constructors allow us to determine the level for a VA and constraints for the nodes to be included. Complex topologies can be created with a single line of code. The following excerpt of code illustrates the possibilities for creating VAs.
// Create low level VA representing processor cores, each VA element contains core 0 and core 1.
VA c1 = new VA(new int[]{0,1},0);
VA c2 = new VA(new int[]{0,1},0);
VA c3 = new VA(new int[]{0,1},0);
VA c4 = new VA(new int[]{0,1},0);

//create a level 1 VA representing processor  (in this case processor numbers are suplied as first argument and level value as second argument)
VA p1 = new VA(new int[]{0,1},1);
VA p2 = new VA(new int[]{0,1},1);

//Adds cores to processors
p1.addVA(c1); p1.addVA(c2);
p2.addVA(c3); p2.addVA(c4)

JSConstraints constr;
VA v1 = new VA(2); // simple level-1 VA
VA v2 = new VA(2,constr); // level-1 VA for which constraints holds

//Add processors to machines (level-2 VA), and machine to a cluster  (level-3 VA)
v1.addVA(p1); v2.addVA(p2);
VA v3 = new VA(3,2); v3.addVA(v1); v3.addVA(v2);
A level 3 VA
                                                                                                                        Figure: Example of a JavaSymphony level-3 VA

Modifying VAs

The instances of VA class are first order objects which can be passed as parameters to methods all over the network. That is why, concurrent access to modify the same virtual architecture is possible. Elements can be added to VAs with addVA, or parts of or even entire VAs can be released with free method . In order to prevent inconsistency due to this concurrent access, an lock/unlock mechanism must be use. The following example and the corresponding figure show us how to modify virtual architecture using lock/unlock mechanism.  (NOTE: For simplicity here we assume that the level-2 VAs are single processor machines) 
VA v1 = new VA(5, new  int[][] { {1,2,1}, {2,2} } );
VA v2 = new VA(4, new int[] {4,2} );

v1.lock(); // lock v1 before modifying it
....
v1.addVA(v2);
v1.free(new int[] {2,1});
....
v1.unlock(); // unlock v1 after changes are done
....
v1.free(); // delete VA when it is not needed anymore

Modifying VA 
Figure: Modifying VAs in JavaSymphony


Getting information about VAs

Various information can be obtained for VAs like: The following code excerpt will illustrate some of these features.
....
// **** v1 will be a level-2 VA
float cpuIdle = v1.getSysParamAsFloat(JSConstraints.C_CPU_IDLE);
String sURL = v1.getSysParameterAsString(JSConstraints.C_HOST_URL);
int iSwap = v1.getSysParameterAsInt(JSConstraints.C_SWAP_AVAILABLE);
....
VA v2 = v1.getPred(v1.getLevel() + 1); // obtain  the VA level and parent VA of v1
VA vn = v2.getVA(n); // obtain the n-th successor of v2
VA vLocal = VA.getLocalNode(); // obtain the local level-2 VA on which the code is running
....
int nrLeveli = v4.nrVA(i); // number of level-i VAs in v4
....
// how to traverse level-i VAs of v4
VAEnum e= v4.enumerateVA(i);
while (e.hasMoreVA())
{
    VA v5 = e.nextVA();
    ..... // do some processing on v5....
}
.....
    For a detailed list of system parameters see the appropriate example.
 

Constraints

    For a machine in the network we distinguish two types of system parameters: static parameters, which remain unchanged during the execution of an application. like: machine name, operating system, CPU type, peak performance parameters... and dynamic parameters which change while the application is running, like system load, idle times, available memory.... JavaSymphony allows the user to specify a sets of constrain for the computing resources in the network, using the JSConstraints class. Using its setConstraints method, different restriction over the system parameters are imposed, before the machine is included in a VA. These constraints are conditions for system parameters (a list is provided in one of the examples) like upper or lower bound values or specific values. The next example will illustrate how to ask for a machine with the name different of "milena", where system should execute  less then 50% in system mode, is idle for more than 90% and has at least 10240 kBytes of unused memory.
....
JSConstraints constr = new JSConstraints();
constr.setConstraints(JSConstraints.C_HOST_URL , "!=", "milena");
constr.setConstraints(JSConstraints.C_CPU_IDLE , ">=", 90.0f);
constr.setConstraints(JSConstraints.C_CPU_SYS  , "<=", 50);
constr.setConstraints(JSConstraints.C_MEMORY_FREE_KB , ">=",  10240);
....
VA v1 = new VA(2, constr);  // requesting a level-2 VA which conforms the constraints in constr
....
    We can also verify if initial constraints or new ones hold for a specific VA, like in the following excerpt:
....
boolean initialHolds = v.constrHold();  // check if initial constraints still hold
boolean itHolds = v.constrHold(constr);  // check if new defined constraints constr hold
....

Objects in JavaSymphony

    JavaSymphony provides two types of objects which are used to develop shared memory as well as distributed applications. The Objects used to develop distributed applications are remote objects based on RMI (Remote Method Invocation) mechanism. These remote objects hide the RMI related complexties and programming details and provides abstractions to develop a distributed application.
Shared memory applications can be programmed using shared memory objects called SJSObjects. These objects represent the same high level interface as JSObjects and hide all multi-threading related details.

(a) Remote objects - JSObjects

    The remote objects are the core of distributed computing in JavaSymphony. Data and code can be sent to remote computing resource for processing using class JSObject, which represents a handle to a common Java object, placed on this remote machine. The JSObject transparently cover details of Java RMI, that is why a few condition must be fulfilled by the original class: the code for the class must exist on the remote machine previous to object creation and the class for the remote object must implement the Serializable interface for compatibility with RMI serialization.
The first condition is solved using JSCodebase class of JavaSymphony, and the second is the responsibility of the programmer who writes the code for the remote object.

(b) Shared  objects - SJSObjects

JavaSymphony provides a shared memory programming model based on shared JS (SJS) objects. A SJS object can be mapped to a node of level 0-2 according to the VA shown in VAs section and cannot be distributed onto higher-level remote VA nodes. A SJS object can also be a single-threaded or a multi-threaded object. Three types of method invocations can be used with JS as well as with SJS objects: asynchronous, synchronous, and one-sided method invocations.

Class loading

    The classes for remote object need to be loaded on the remote nodes in advanced to creation of the actual object. Specific class files, Java archives or classes at an URL address can be specified for a codebase and then loaded entirely on a specific VA, that is on each computing node/level-2 VA on that VA. Creation, addition of classes, loading on VAs and releasing of codebase is covered in the following example.
....
JSCodebase codebase = new JSCodebase(); // initialize a codebase
....
// **** adding a class file, an archive or an URL to the codebase
codebase.add("../classes.jar");
codebase.add("..testclass.class");
URL classURL = new URL("http://www.par.univie.ac.at/JS/test/file.class");
codebase.add(classURL);
...
codebase.load(v); // load the codebase on the VA v
codebase.free();  // free the codebase - its associated memory
....

Creating JS/SJS Objects 

    The JSObject's constructors set allows the user to specify original class name, arguments for its constructor, single-threaded/multi-threaded feature, location: generic on a higher level VA or specific on a level-2, level-1, or level-0 VA, and constraints for the chosen level-2 VA (when the choice exists). In addition to this, JSObjects can be created from the existing local objects. The advantage of using this features is that someone can remotely access the methods of the object if he gets a remote handle to it, that is the newly created JSObject. The following lines of codes will show us different methods to create a JSObject.
VA v1 = new VA(2); // allocate a level-2 VA
VA v2 = new VA(4,....);  // allocate level-4 VA
VA vLocal = VA.getLocalNode(); // get local level-2 VA
JSConstraints constr;
Object[] args = new Object[] {new Integer(10)};  // parameters for the new object as list of objects
....
//***** generate an object of class "ClassName''
JSObject obj1 = new JSObject("ClassName'' [, args] [, constr] [, vLocal]);

//***** generate an object on a higher level VA; JRS decides on which level-1 VA of v2 this object will be generated
JSObject obj1 = new JSObject("ClassName'',[args,] v2);

//***** generate object on a specific VA v1
JSObject obj1 = new JSObject("ClassName'',[args,] v1);

//***** convert a non-JSObject obj to a JS object obj2
ClassName obj = new ClassName(...);
JSObject obj2 = JSObject.convertToJSObject(obj [,multiThreaded]);

//***** Craete a single-threaded SJSObject on local node.
SJSObject sobj1 = new SJSObject(true,"ClassName",args);

//***** Craete a multi-threaded SJSObject on a Level-2 VA
SJSObject sobj2 = new SJSObject(false,"ClassName",args,v1);

Single-threaded/multi-threaded objects

    The JavaSymphony JS/SJS Object can be created as a single-threaded or a multi-threaded object.     We can specify the type of the object at the creation with the constructors for JSObject or at a later moment, using the method singleThreaded and multiThreaded, as we can see in the following example.
boolean multiThreaded = true;
JSObject obj1 = new JSObject(multiThreaded, "ClassName'' [,args] [,v]);

//***** objects can be made single- or multi-threaded at runtime
obj1.singleThreaded();
obj1.multiThreaded();

Lock/unlock objects

    JS objects are accessed through handles which are first order objects. They can be passed to methods and, therefore, distributed onto VAs as well. Any thread with a handle to a JS object has access to and can modify or even free this object. However, concurrent accesses to objects can be prevented by using a lock/unlock mechanism provided by JavaSymphony. The mechanism works like this: if a thread t has a handle to an object and locks it, then no other thread can access this object until thread t unlocks it again. A lock operation on an object is delayed until all unfinished methods on this object have completed execution.
JSObject obj;
....
obj.lock() // lock object
.... // do some method invocation for the object -- no interruption from other threads
obj.unlock(); // unlock object

Method Invocation

    Java/RMI imposes blocking remote method invocation which prohibits overlapping of waiting time - for results of remote method invocations to arrive - with some useful local computations. In addition to synchronous (blocking) RMI, JavaSymphony also offers asynchronous (non-blocking) and one-sided RMI (non-blocking without results). All three types of method invocations are implemented as methods of JSObject class and have similar signatures: A method name followed by a list of parameters and optionally a list of parameter types are specified. These method invocations can also be used with SJS Objects, and in this case instead of RMI  local method invocation and communication is uased. JRS uses the parameter types in order to find the correct method for invocation on a  VA. We will describe with examples all the three types of invocation.

Synchronous method invocation

    Synchronous method invocation - sinvoke blocks the calling site for as long as the result arrives. Parameters are passed as an array of objects. JavaSymphony always returns a method invocation result of class Object which must be explicitly casted to the actual class of the result. In the following code excerpt a method with name "methodName" with parameters Param1 and Param2 is invoked based on object obj.
JSObject obj = new JSObject(ClassName'');
....
Object[] params = new Object[] {new Param1(), new Param2()}
Class[]  paramTypes = new Class[] {Param1.getClass(),Param2.getClass()}; // optional types list
ResultClass result = (ResultClass)obj.sinvoke("methodName", params [,paramTypes] );

Asynchronous method invocation

    Asynchronous method invocation - ainvoke are commonly employed to parallelize computations. Again an array of objects is used to hold the method parameters. The method call, however, does not block, but immediately returns a handle. Execution continues at the calling site. If a pre-defined method handle.isReady returns TRUE then the result is available, FALSE otherwise. If the calling site wants to block until the result has arrived - for instance, because no other useful computations can be done - then method handle.getResult can be called. Note that this method returns the result object of type Object. It must be explicitly casted to the actual class of the result. 
//**** invoke remote method with parameters; a handle is returned to refer to the method's result in the future
Object[] params = {new Param1(), new Param2()};
Class[]  paramTypes = new Class[] {Param1.getClass(), Param2.getClass()};
ResultHandle handle = obj.ainvoke(``methodName'',params [,paramType]);
....
//**** verify whether result is available
if (handle.isReady()) {          
    // wait for result to arrive in blocking mode
    ResultClass result = (ResultClass)handle.getResult ();
}
else
    // do something else
....
//**** wait for result to arrive in blocking mode without checking for the result to be available
ResultClass result = (ResultClass)handle.getResult();
....

One-sided method invocation

    One-sided method invocation - oinvoke is used when the result are not needed at all. The method returns immediately, without blocking the caller. No handler or result is returned.
Object[] params = {new Param1(), new Param2()};
Class[]  paramTypes = new Class[]  {Param1.getClass(), Param2.getClass()};
obj.oinvoke(``methodName'',params [,paramTypes] );

Object migration

    One of the main features of JavaSymphony is object migration. JavaSymphony offers two forms of object migration:     JRS, however, verifies before object migration, whether any of its methods are currently being executed. If so, then migration is delayed until all unfinished method invocations have completed execution, otherwise the object can be immediately migrated.
    Explicit migration can be encoded by the JavaSymphony application programmer. For this purpose JavaSymphony allows to access system parameters for VAs (see Constraints section). System parameters for a level-i VA are averaged across its level-(i-1) VAs which is limited to system parameter values of type int and float. Methods getSysParamAsFloat, getSysParamAsInt or getSysParamAsString can be called for every architecture component to examine the system parameters of interest. Moreover, it can be verified through method constrHold whether a set of constraints currently hold for a given architecture component. For instance, in the following code excerpt it is examined whether a level-2 VA v1 on which a specific object resides has less than 50 % idle time or doesn't fulfill a set of constraints. If so, then this object can be migrated by using method migrate. If migrate is called without any parameters then JRS decides where to migrate the object. These decisions can be influenced by using the JS-Shell. As we shall see, method migrate can be invoked with a node as a parameter that defines where to migrate the object. If constraints are indicated then a node found by JRS that honors the constraints, is chosen as the target node for object migration. In some cases, it is possible that a suitable node is not found. A Java exception will be thrown that must be handled by the application programmer.
JSConstraints constr;
VA v1 = new VA(2); VA v2 = new VA(5,...);
JSCodebase cb; JSObject obj;
boolean moveCodebase = true;
....
VA v3 = obj.getVA();
// **** if v3 on which obj resides has less than 50 % idle time or constr do not hold for v3
if (v3.getSysParam(JSConstraints.C_CPU_IDLE) < 50) || !v3.constrHold(constr))
{
    obj.migrate();  // migrate object to a node destined by JRS
    obj.migrate(constr, moveCodebase);  // migrate object to a node according to a set of constraints and move all codebases as well
    obj.migrate(v1); // migrate object to a specific node/level-1 VA
    obj.migrate(v2); // migrate object to a node of v2 to be destined by JRS

    //**** specific codebase is moved to the destination VA
    obj.migrate(va, cb);
    obj.migrate(constr, cb);
    obj.migrate(cb);
}
....

Other features

Persistent Objects

    JavaSymphony provides facilities to make objects persistent by saving and loading them to/from external storage. An object can only be stored/loaded when none of its methods are currently executing which is verified by JRS. A unique string will be returned by JRS for the object just stored.
JSObject obj; String str; 
str = obj.store();  // save object on external storage