The Webflow Backend:
The Webflow backend is written completely in Java, and employs the CORBA Framework for managing, the distributed Objects. Besides the base ORB we also employ the Naming Service for managing the modules. The Java-ORB presently in use is Inprise’s Visibroker but future implementation’s could easily employ JWORB.
Modules:
Modules are the basic nugget of computation. Modules perform two operations –
package edu.syr.npac.webflow.module;
public interface Module extends org.omg.CORBA.Object {
/** run the module code */
public void run();
/** deallocate all resources allocated by the module. Destroy the module */
public void destroy();
}
Keeping with the norm of distributed object frameworks where clients interact with remote interfaces rather than the actual implementation itself, the module in the Java-CORBA domain is an interface inherting both the Java and CORBA object models. This is an interface which extends org.omg.CORBA.Object comprising of two methods run() which corresponds to performing the operation, and destroy which performs the housekeeping’s mentioned earlier.
An application Module:
As can be easily visualized, this model doesn’t lend itself very well to computations which perform computation’s responding to attributes within a module. A nifty workaround this is to extend the module interface for accomodating various attributes for a specific application domain. Thus implementations of those interfaces are still modules, with additional attributes. An implementation of the new interface would need to implement the two methods within the module. Lets take an example application domain of Imaging where the computation attributes include
A point not mentioned so far is the fact that we need these remote objects to conform to the Beans naming conventions for reasons that would soon be clear. The Beans naming convention specifies that for a Property xyz the getter/setter methods would be named getXyx/setXyz. These naming conventions would render our remote objects for introspection. Our ImageModule interface would thus look like this, where our attributes are – width, height, pixels.
package edu.syr.npac.webflow.module.imaging;
public interface ImageModule extends edu.syr.npac.webflow.module.Module {
public void setWidth(int imgw);
public int getWidth();
public void setHeight(int imgw);
public int getHeight();
public void setPixels(int[] pixels);
public int[] getPixels();
}
An Example implementation of a Image Module
Here we just do a sample implementation of a Convex Filter. What needs to be noted here is the fact that it implements the methods defined in both the Module and ImageModule interface. Upon receipt of a request for running a module, the Module Manager simply calls a special run method which each module is required to have. An invocation the run method performs a compuation (filter) which takes all three attributes as parameters. That method is written by the module developer, and implements the module's functionality. Since each CORBA object runs in its own thread it is clear that concurrent execution of different modules is easily achieved.
This object is thus
Upon receipt of a request for running a module, the Module (in this case the ConvexFilter) calls the run method which each module is required to have. That method is written by the module developer, and implements the module's functionality.
package edu.syr.npac.webflow.impl.module.imaging;
public class ConvexFilter
extends edu.syr.npac.webflow.module.imaging._ImageModuleImplBase {
private int[] pixel;
private int imgw;
private int imgh;
/** Construct a persistently named object. */
public ConvexFilter(java.lang.String name) {
super(name);
}
/** Construct a transient object. */
public ConvexFilter() {
super();
}
public void setWidth(int nimgw) {
imgw = nimgw;
System.out.println("Set the width");
}
public int getWidth(){
return imgw;
}
public void setHeight(int nimgh) {
imgh=nimgh;
System.out.println("Set the height");
}
public int getHeight() {
return imgh;
}
public void setPixels(int[] pixels) {
pixel = new int[pixels.length];
System.arraycopy(pixels, 0, pixel, 0, pixels.length);
System.out.println("Set the pixels");
}
public int[] getPixels(){
return pixel;
}
private void filter(int[] npixel, int nimgw, int nimgh) {
System.out.println("Convex Filtering begins on the server-side....");
int radius = nimgw/2;
int _pixel[] = new int[nimgw * nimgh];
int wpixel[] = new int[nimgw];
for (int j=0; j< nimgh; j++) {
int a = j - nimgh/2;
int b = a*a;
for (int i=0; i <nimgw; i++) {
int c = i - nimgw/2;
int d = c*c;
double d1 = Math.sqrt((double)(b+d));
if ((int)d1 < radius) {
double d2 = d1 / radius;
if (d2 <= 0.5)
d2=0.5;
double d3 = d2 * c;
double d4 = d2 * a;
int _val1 = nimgw/2 + (int)d3;
int _val2 = nimgh/2 + (int)d4;
wpixel[i] = npixel[_val2* nimgw + _val1];
}
else
wpixel[i] =0;
}
System.arraycopy(wpixel,0, _pixel, j*nimgw, nimgw);
}
System.arraycopy(_pixel,0, pixel, 0, _pixel.length);
}
/**
* run the module code
*/
public void run(){
filter(pixel, imgw, imgh);
System.out.println("Invoked Filtering on the server side");
}
/**
* deallocate all resources allocated by the module. Destroy the module
*/
public void destroy(){
}
}
The Naming Service provides the ability to bind a name to an object relative to a naming context. A naming context is an object that contains a set of name bindings in which each name is unique. To resolve a name is to determine the object associated with the name in a given context. Through the use of a very general model and dealing with names in their structural form, naming service implementations can be application specific or be based on a variety of naming systems currently available on system platforms.
Graphs of naming contexts can be supported in a distributed, federated fashion. The scalable design allows the distributed, heterogeneous implementation and administration of names and name contexts. Each NameComponent
contains two strings, id
and kind
. The naming service does not interpret or manage these strings, except to ensure that each id
is unique within a given NamingContext
. Because name component attribute values are not assigned or interpreted by the naming service, higher levels of software are not constrained in terms of policies about the use and management of attribute values. This is performed by the session Server during start-up.
For ease of understanding only the parts within the session Server which are relevant to the creation of the name space have ben included. A quick graphical representation of the module looks like this
Webflow (context)
|______
Application Domain (context)
|_____
| Imaging (context)
| |___
| ConvexFilter (object)
| BathGlasFilter (object)
| Negative Filter (object)
| InputModule (object)
|_____
Computing (context)
|___
Variance (object)
Deviation (object)
try {
/* Initialize the ORB */
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args,null);
org.omg.CORBA.Object nameServiceObjRef =
orb.resolve_initial_references("NameService");
org.omg.CosNaming.NamingContext rootContext =
org.omg.CosNaming.NamingContextHelper.narrow(nameServiceObjRef);
NameComponent[] projectName = {new NameComponent("WebFlow", "")};
NamingContext projectContext=
rootContext.bind_new_context(projectName);
NameComponent[] applicationDomain = {new NameComponent("ApplicationDomain","")};
NamingContext applicationDomainContext =
projectContext.bind_new_context(applicationDomain);
NameComponent[] imagingApp =
{ new NameComponent("Imaging", "")};
NamingContext imagingContext =
applicationDomainContext.bind_new_context(imagingApp);
edu.syr.npac.webflow.module.Module convex=
new edu.syr.npac.webflow.impl.module.imaging.ConvexFilter("ConvexFilterModule");
edu.syr.npac.webflow.module.Module bathglass=
new edu.syr.npac.webflow.impl.module.imaging.BathGlassFilter("BathGlassFilterModule");
edu.syr.npac.webflow.module.Module negative=
new edu.syr.npac.webflow.impl.module.imaging.NegativeFilter("NegativeFilterModule");
edu.syr.npac.webflow.module.Module composite=
new edu.syr.npac.webflow.impl.module.imaging.CompositeModule("BathGlassFilter/ConvexFilter");
edu.syr.npac.webflow.module.Module inputModule=
new edu.syr.npac.webflow.impl.module.imaging.InputModule("ImageInputModule");
orb.connect(convex);
orb.connect(bathglass);
orb.connect(negative);
orb.connect(composite);
orb.connect(inputModule);
NameComponent[] convexName =
{ new NameComponent("ConvexFilter", "")};
imagingContext.bind(convexName, convex);
NameComponent[] bathglassName =
{ new NameComponent("BathGlassFilter", "")};
imagingContext.bind(bathglassName, bathglass);
NameComponent[] negativeName =
{ new NameComponent("NegativeFilter", "")};
imagingContext.bind(negativeName, negative);
NameComponent[] compositeName =
{ new NameComponent("CompositeFilter", "")};
imagingContext.bind(compositeName, composite);
NameComponent[] inputModuleName =
{ new NameComponent("InputModule", "")};
imagingContext.bind(inputModuleName, inputModule);
}
catch(Exception e) {
System.out.println("Exception " + e);
}
The module Manager:
The module manager provides information regarding the name space and specific modules. An explanation of these operations follow.
package edu.syr.npac.webflow.manager;
public interface moduleManager extends org.omg.CORBA.Object {
public String[] listModules();
public String[] listMethods(edu.syr.npac.webflow.module.Module _moduleObject);
public String[] listZeroArgumentMethods(java.lang.Object _moduleObject);
public org.omg.CORBA.Object getModuleHandle(java.lang.String _moduleName);
public edu.syr.npac.webflow.module.Module createTransientModule(java.lang.String _moduleName);
}
Also notice that the Module Manager has no notion of a session built into it. It can support any number of modules, and requests coming from any number of Clients.
Connection Object:
This object represents a nugget of computation. The connection Object interface show below supports the following different options
The connection Object interface is given below, a brief explanation of the eggregated widgets inside the connection Object follows.
package edu.syr.npac.webflow.connection;
public interface connectionObject extends org.omg.CORBA.Object {
public void addItem(edu.syr.npac.webflow.module.Module _module);
public void addItemToTop(edu.syr.npac.webflow.module.Module _module);
public edu.syr.npac.webflow.module.Module nextItem();
public edu.syr.npac.webflow.module.Module
removeItem(edu.syr.npac.webflow.module.Module _module);
public edu.syr.npac.webflow.module.Module
insertItemBefore (edu.syr.npac.webflow.module.Module _insert,
edu.syr.npac.webflow.module.Module _before);
public void setPersistentConnection(boolean _persistence);
public boolean isPersistentConnection();
public void compute()
throws edu.syr.npac.webflow.exception.webflowException;
public void setConnectionInfo(String info);
public void addNode(String nodeName,
edu.syr.npac.webflow.module.Module _module);
public void removeNode(String nodeName,
edu.syr.npac.webflow.module.Module _module);
public edu.syr.npac.webflow.module.Module getNode(String nodeName);
public java.lang.Object invoke(String nodeName, String propName);
}
Compute Queue:
The computeQueue is implemented as a Doubly Linked List. Each Widget in the list is an object with pointers to the next and previous Widgets. The next field of the tail-element and prev field of the head are set to NULL. The queue provides support for Priority computations by adding them to the HEAD of the list instead of appending them to the List.
class QueueWidget { Object object; QueueWidget prev; QueueWidget next; QueueWidget(Object object, QueueWidget queueWidget1, QueueWidget queueWidget2) { this.object = object; prev = queueWidget1; next = queueWidget2; } }
The object within the Queue Widget is a module. The connection Object provides methods to insert/delete/addToTop Items within the computeQueue
. Once the computeQueue is so to speak populated with a set of modules, the discovery and connection of appropriate properties is performed by the run-time system.
Compute –
The compute method tries to perform the computation, depending on the set parameters i.e. Cascaded modules sequential computation or specific property-based method hookup. The compute method throws an exception viz. WebflowException detailing the cause for the failure of the computation.
The connection Manager:
The connection manager manages the connectionObjects created by various clients. The various functions performed by the connection Manager include
package edu.syr.npac.webflow.connection;
public interface connectionManager extends org.omg.CORBA.Object {
public connectionObject createConnectionObject(String _objectName);
public void compute(java.lang.String _connectionObjectName);
public String[] listConnectionObjects();
}
Webflow Exceptions:
Webflow exceptions are checked exceptions – meaning that they are a sub-class of the java.lang.Exception, thus client programmers who wish to call the method (such as compute within the connection Object) will then need to either catch and handle the exception within the body of their methods, or declare the exception in the throws clause of their methods. Making an exception checked, forces client programmers to deal with the possibility that the exception will be thrown.
package edu.syr.npac.webflow.exception;
public class webflowException extends org.omg.CORBA.UserException {
public static final int UNKNOWN = 99;
/** The type of the exception */
public int type;
public String info="Reason is unknown";
public webflowException() {
super();
type = UNKNOWN;
}
public
webflowException(int type) {
super();
this.type = type;
}
public webflowException(webflowException e) {
super();
type = e.getType();
info = e.typeToString(type);
}
/** Return the type of the webflow Exception */
public int
getType() {
return(type);
}
public String
typeToString(int type) {
return info;
}
}
As can be seen the webflowException class contains a copy constructor. Now because we have the copy constructor in this class, the client needs to be aware of only one exception class. However this also facilitates having specific exceptions which sub-class webflow exception, to be thrown as a webflow Exception with the relevant information being copied into the type and info fields. Let us now look at one of the sub-classed exceptions.
Property Exceptions:
This class sub-classes the webflow exception and the client needn’t be aware of this exception. However it allows for clarity of code on the server side. This exception pertains to the propertyLinker and propertyConnector classes in the implementation of the connection Object.
package edu.syr.npac.webflow.exception;
public class propertyException extends webflowException {
/** The type of the exception */
public int type;
private String additionalInfo= " ";
public propertyException() {
super();
//type = UNKNOWN;
}
public
propertyException(int type) {
super();
this.type = type;
}
public int
getType() {
return(type);
}
public String
typeToString(int type) {
switch(type) {
case NO_PROPERTIES:
return ("No properties listed for this object" + getAdditionalInfo());
case NO_SUCH_PROPERTY:
return ("No such property " + getAdditionalInfo());
case PROPERTY_TYPE_MISMATCH:
return ("Property type mis-match occured between " +
getAdditionalInfo());
case NO_READ_METHOD:
return ("No read method associated with property " +
getAdditionalInfo());
case NO_WRITE_METHOD:
return ("No write method associated with property " +
getAdditionalInfo());
}
return ("Reason is unknown");
}
public void setAdditionalInfo(String _info) {
additionalInfo = _info;
}
public String getAdditionalInfo() {
return additionalInfo;
}
/** The various types of property exceptions that can be thrown. */
public static final int NO_PROPERTIES = 100;
public static final int NO_SUCH_PROPERTY = 101;
public static final int PROPERTY_TYPE_MISMATCH = 102;
public static final int NO_READ_METHOD = 103;
public static final int NO_WRITE_METHOD = 104;
}
This class contains two additional methods pertaining to the additionalInfo property. This allows us to keep plugging additional information pertaining to the exception, as it traverses up in the aggregation path.