Source: Webster's Revised Unabridged Dictionary (1913) [web1913]
  1. collaboration \Col*lab`o*ra"tion\, n. The act of working together; united labor [syn: {coaction}]
  2. collaboration act of cooperating traitorously with an enemy [syn: {quislingism}]


Abstract

Etymology tit-bits aside, support for collaboration was one of the main driving forces for the original Web, created by CERN physicists to share data across high energy physics labs. Over the last decade, the Web technologies rapidly evolved and so did the collaboration capabilities of the whole framework. Ofcourse Science and Technology go through fads and fashions much like those of apparel, food and toys, and skeptics are quick to point out flaws which render the web-based collaboration model ineffectual. Like so many approaches that have come and gone in the past, the web-based collaboration model could be here to stay or could fade away like some computational hoola hoop du jour. In the remainder, I intend to explore a few issues concerning collaboration and try to frame answers to the following important questions
a)The Plot - Motives for collaboration
b)The Story so far - 2nd Generation Collaboration Environments
c)The Plot Thickens - Distributed Objects ...the next frontier?
The answers to these question hopefully would point to where the Web-based Collaboration is headed, and if we could cross the chasm between vision and reality.

Introduction

The Web has evolved from a static hypermedia system with limited expressiveness into a collection of services provided at different levels and is increasingly being perceived as critical to enterprise computing architectures. Development of Collaborataion Environments are amongst the most promising fields of new Web-applications built from these existing services using support infrastructures. First generation Collaborative systems were represented by custom Java based collaboratory server technologies such as NCSA Habanero or JavaSoft JSDA, with the former providing for sharing of state and the latter providing a Shared Framework at the data level. Both these approaches were socket based, thus allowing for realtime communication. However they share the disadvantage of being low-level mechanisms, and requiring the provision of a messaging protocol as well as the message transport. What would really obviate this is a direct object-to-object communication mechanism that would allow objects to call others' methods directly The recent onset of distributed object and/or component technologies opens new and interesting avenues for standards based collaboratory infrastructures.

However, selecting a specific direction in the exploding field of distributed object and component technologies is far from being an easy task, illustrated very well both by the myraid options and the uncertainty of overall direction in the field. The questions the we pose ourseleves is whether the Web could serve as an infrastructure for both developing and implementing business applications in a, possibly globall, distributed and collaborative business environment. In the approach to answer the question, we adopt the integrative methodology i.e. we setup a multiple-standards based framework in which the best assets of various approaches complement each other. Java Distributed Collaborative Environment as the name suggests is a Distributed Collaborative environment, implemented using both CORBA and RMI. In the sections that follow I intend to explore and contrast the rationale driving these two approaches, and the overall design of the system. In the end we take examples, which are technology demonstrations,and see how various collaboration issues are dealt with.

Collaboration


 Definition Of Collaboration
``Collaboration is a process to reach goals that cannot be achieved acting singly (or, at a minimum, cannot be reached efficiently). As a process, collaboration is a means to an end, not an end in itself. The desired end is more comprehensive and appropriate services that improve outcomes.''


 Simple GuideLines For Collaboration - The first principle:
Identification Of
Actions that should be exclusively under the preview of the user
Actions that would progate state changes to users working on copies of a paritcular tool in an established collabrative environment.


 Software Tools & The Need For Collaboration
Hitherto, design and development of software tools have focussed on single-user control.
Independent vendor solutions to address the Collaboration problem, have resulted in inter-operability problems of the software tool.




Java & Collaboration API's

Natural initial focus was on asynchronous collaboratory models (shared databases) which were more recently augmented by the synchronous components (shared displays) and are now further evolving towards the ultimate televirtual (TVR) (shared worlds) environments. Some essential Web technology thresholds towards TVR included: VRML for 3D interactive front-ends and Java that enabled real-time synchronous connections. It is our belief that if these tools are designed in Java, hardware support would be considerably broadened, expressed albeit by the Java VM.

 Specs for Collaboration API's
Collaboration API's need to provide a developer with
Means to retrofit single-user software tools to collaborative tools
Build collaboration Tools from gorunds up.


 2nd Generation Java-based Collaboration API's
Habanero from NCSA
Habanero uses the Presentation-Abstraction-Control model to administer the session and the users visual environment. The abstraction level is the application , the presentation level is responsible for processing the displays and user events while the control part is responsible for the communication aspects between the abstraction and presentation levels. The cross-platform collaboration of different tools is facilitated by sharing Java-objects which implement "The Wrapped Object Model", for routing between the different session-participants. Any class that is used in a Habanero-enabled application must already have been installed on each client's machine. Collaborative objects can share string information and any objects that implement the Wrapped or Marshallable interfaces. To share objects (other than numbers or strings) developers need to write their own Marshalling and unmarshalling routines, essentially the Marshalling method should snap shot the state of the object (to be shared) in such a way that Unmarshalling can recreate that state in a new object.

The doEvent() method in the wrapped object is where the application responds to Collaborative actions. Once an object has been marshalled to other collaborating participants, the reception of the unmarshalled object is performed in the doEvent method() which takes the Event and Marshallable object as parameters. The doEvent(0 method overrides both the handleEvent() & action() methods (reserved to process single-user related events) and requires the latter methods to return false for those events which need to be shared. This forces the Java system to pass the event to the Habanero Frame of the application.


JSDT (Java Shared Data Toolkit) from Javasoft JSDA provides a Shared Framework for Java at the data level. Data objects are shared over, specific instances of Channels- between two or more Clients. To elucidate further Channels are abstractions for data communication paths in JSDA, whereas Clients are objects which are the source or destination of data- in a collaboration environment. Any Client object which needs to register its interest in receiving messages sent over a channel must implement the Channel Consumer Interface. On similar lines if a client is interested in being notified about changes in state of some other object it should implement the Channel Observer Interface. It should be noted that a Client which references a Channel could operate on that channel, instinctively its clear that a Client could operate on Multiple channels by referencing multiple channels at the same time.

To register interest in a certain Channel, a Client first needs to join the Session which the Channel is a part of and then the Channel. A Client could be part of multiple Sessions and thus register interest in Channels acroos those various Sessions. However, a client isn't allowed to have more than one consumer on a channel, though replication of this behavior could be done in a roundabout way. As of now the only data that can be shared are byte Arrays, however its possible to share objects too using the Habanero Model or by creating ByteArrayInput/OutputStreams and using the Object serialization from RMI. Its possible to pass complex data types like images as a sequence of bytes. JSDA also has objects which encapsulate management policies for other given objects.



Distributed Objects - The Next Frontier

Second generation systems were represented by custom Java based collaboratory server technologies such as NCSA Habanero or JavaSoft JSDA. However, selecting a specific direction in the exploding field of distributed object and component technologies is not an easy task. CORBA offers one promising approach, especially from the large scale computing perspective but there are alternatives such as Java RMI or Microsoft DCOM. Finally, the World-Wide Web Consortium is developing a set of new standards such as XML, DOM, RDF and HTTP-NG which, when combined, can be viewed as yet another, new emergent distributed object model (sometimes referred as WOM) which is likely easier to be adopted by simple to medium complex distributed object/component applications.

 Common Object Request Broker

The CORBA standard tries to obviate problems resulting from boundaries such as networks, programming languages, and operating systems. CORBA can be viewed as an environment to support the development of a complete new system or an environment for integrating legacy systems and sub-systems. An implementation of the standard defines a language and platform-independent object bus called an ORB (Object Request Broker), which lets objects transparently make requests to, and receive responses from, other objects located locally or remotely. Each implementation of the CORBA standard is able to communicate with any other implementation of the standard., the protocol used to achieve this end is the Internet Inter-ORB Protocol (IIOP).



  IIOP - Internet Inter-ORB Protocol

The IIOP specification defines a set of data formatting rules, called CDR (Common Data Representation), which is tailored to the data types supported in the CORBA Interface Definition Language (IDL). Using the CDR data formatting rules, the IIOP specification also defines a set of message types that support all of the ORB semantics defined in the CORBA core specification. The messaging formats and the CDR constitue the General Inter-ORB Protocol. IIOP is the GIOP message format sent over the Transmission Control Protocol/ Internet Protocol (TCP/IP). GIOP messages could be sent over any data transport protocol. Using IIOP any CORBA client can speak to any other CORBA Object.The architecture states that CORBA objects are location transparent. The implementation, therefore, may be in the same process as the client, in a different process or on a totally different machine




 Java RMI
his section briefly provides an overview of RMI, and how it would inter-operate with other Distributed Object alternatives like CORBA. Java Remote Method Invocation (RMI) is a set of APIs designed to support remote method invocations on objects across Java virtual machines. RMI directly integrates a distributed object model into the Java language such that it allows developers to build distributed applications in Java. More technically speaking, with RMI, a Java program can make call on a remote object once it obtains a reference to the remote object, either by looking up the remote object in the bootstrap naming service provided by RMI or by receiving the reference as an argument or a return value. Currently, Java RMI uses a combination of Java Object Serialization and the Java Remote Method Protocol (JRMP) convert normal-looking method calls into remote method calls.Java RMI supports its own transport protocol today (JRMP) and plans to support other industry standard protocols in the near future, including IIOP. In order to support IIOP as it is today, JavaSoft will define a restricted subset of features of Java RMI that will work with IIOP. Developers writing their applications to this restricted subset will be able to use IIOP as their transport protocol.



 Java-Beans a Component Framework for Java

Java is more than a language- its a framework that comprises many components. It includes picoJava, a hardware implementation of the Virtual Machine; the JavaOS, an operating system implementation, and many application programming interfaces to facilitate development of a broad range of applications. Development of reusable component architectures that will allow large software systems to be designed by combining components from possibly different sources is the intended goal of JavaBeans. JavaBeans provides mechanisms to define components in Java and specify interactions amongst them. Java Beans components provide support wherein component assemblers discover properties about components. One of the other interesting aspect about JavaBeans is that it also accomodates other component architectures such as OpenDoc, ActiveX and LiveConnect. So by writing to JavaBeans the developer is assured that the components can be used in these and other component architectures.
Component Model:

A component is a software object that has the following elements

Properties (public state information readable and/or writable by a program)
Methods (Invocable at run-time by a program)
Events (notifications to a program in response to state changes in the object)

Component Framework:

A component Framework is the design of a set of API's that allow software developers to define a software components that can be dynamically combined together to create an application. A component Framework consists of two major elements :components and containers.

Components encapsulate semantically meaningful application functions. Components differ from other types of reusable software modules in that they can be modified at dsign time as binary executables instead of a modification at the source code level. Components can have a visual appearance such as a button and can be non-visual such as a data feed monitoring component.

Containers are used to hold an assembly or related components. Containers provide the shared context for components to be arranged and interact with one another. Containers also offer common access to system-level services for a components' embedded components viz. process threads and memory resources. Containers are sometimes reffered to as forms, pages frames or shells, Containers can also be used as components i.e. a container can be used as a component inside another container. Event-based protocols are used to establish relationships between a component and its container.

Since it's a "component architecture" for Java, Beans can be used in graphical programming environments, like Borland's JBuilder, or IBM's VisualAge for Java. This means that someone can use a graphical tool to connect a lot of beans together and make an application, without actually writing any Java code -- in fact, without doing any programming at all. Graphical development environments let you configure components by specifying aspects of their visual appearance (like the color or label of a button) in addition to the interactions between components (what happens when you click on a button or select a menu item).

One important aspect of Java Beans is that components don't have to be visible. This sounds like a minor distinction, but it's very important: the invisible parts of an application are the parts that do the work. So, for example, in addition to manipulating graphical widgets, like checkboxes and menus, Beans allows you to develop and manipulate components that do database access, perform computations, and so on. You can build entire applications by connecting pre-built components, without writing any code.

A "bean" is just a Java class with additional descriptive information. The descriptive information is similar to the concept of an OLE type library, though a bean is usually self-describing. Any Java class with public methods can be considered to be a bean, but a bean typically has properties and events as well as methods.

Introspection Because of Java's late binding features, a Java .class file contains the class's symbol information and method signatures, and can be scanned by a development tool to gather information about the bean. This is commonly referred to as "introspection" and is usally done by applying heuristics to the names of public methods in a Java class.

For those who are queasy about the idea of enforced naming conventions, JavaBeans provides an alternate approach. Explicit information about a class can be provided using the BeanInfo class. The programmer sets individual properties, events, methods using a Bean Info class and several descriptor class types (viz. Property Descriptor, for specifying properties or the Method Descriptor for specifying methods). To some extent, naming conventions do come into play here as well, as when defing the a BeanInfo class. When an RAD Tool wants to find out about a JavaBean, it asks with the Introspector class by name, and if the matching BeanInfo is found the tool uses the names of the properties, events and methods defined inside that pre-packages class. If not the default is to use the reflection process to investigate what methods exist inside a particular JavaBean class.

Design Patterns

The Beans specification refers to these heuristics of introspection and reflection as "design patterns".


Java Beans

Property The property metaphor in Java esentially standardizes what is common practice both in Java and other object-oriented languages. Properties are set of methods that follow special naming conventions. In the case of read/write properties, the convention is that if the property name is XYZ, then the calss the methods setXYZ and getXYZ respectively. The return type of the getter method must match the single argument to the setter method. Read-only or write-only properties have only one of these methods.

Boolean properties can have a getter method of the form isXYZ in addition to or instead of getXYZ.

Indexed Properties , are also supported in Beans, which set or get an indexed value. Indexed properties take an additional integer parameter in their getter and setter methods.


CORBA, RMI and Java (Convergence & Chemistry Of Object Models)

The combination of Java's language features viz. platform-independence, strong security model etc and CORBA's well concieved approaches to static and dynamic, synchronous and asychronous interfaces, and the rich and comprehensive set of CORBA Services truly provide the right building blocks for a distributed computing paradigm. Thus applets, either pure clients or acting themselves as CORBA servers, cen be created and compiled once, and be gauranteed to run in all the environments. With the onset of ORBlets, dynamically downloadable or browser-resident as in the case of Netscape/Visigenic ORB, CORBA boasts an even tighter integration with Java towards the evolving computing paradigm often referred to as the ObjectWeb. You can use Java to create ActiveX controls or CORBA objects. You can use IIOP to communicate between ActiveX controls or JavaBeans.

 Convergence Of Object Models

Before we proceed further it should also be noted that Java Object technology is cross-platform whereas CORBA is cross-language. The similarities in the object models stem from the support for the notion of abstract interfaces distinct from implementations or classes. Whilst having mostly identical Interface inheritance mechanisms, both Java(1.1) and CORBA support the notion of asynchronous notification of events.

This is is expressed in Java via the registration/call-back model. In this model different objects communicate indirectly with one or more listener objects acting as a bridge between the source and sink of data.
In CORBA the client can create a callback object and hand over the object reference to the server. The server can then call the client back when the event occurs. The client thus does not busy-wait for a response from the server.


 The World of Java and Distributed Objects
One of the key design requirements in the Distributed Object environment is to create nuggets of behaviour which can be shipped from place to place. Oddly enough, classes provide a nice encapsulation boundary for defining what one of these nuggets are. Java with its mobile code facility (the ability to transfer excecutable binaries to wherever they need to be executed) handles inter-object communications within its native environment.The Java RMI and Java Serialization interfaces allow Java-Objects to migrate around the network, heedless of what hardware platform they land on, and then control each other remotely. In the world of Web-based Distributed applications Java's multi-threading feature facilitates the optimal framework for the Clients to have richer presentations and the Object-Implementation Servers to support more clients.
In particular a client can create a thread and have it make a remote operation call, rather than making that remote call directly. In the same framework, a multi-threaded client can receive incoming operation requests (for example, a server call-back) to its objects without having to poll for communication events.

In case of Servers too, remote calls can be made without blocking the server. This can also be done within the code that implements an operation or attribute so that some complex algorithm may be parallelized.
The Java distributed object model is similar to the Java object model in the following ways: A reference to a remote object can be passed as an argument or returned as a result in any method invocation (local or remote). A remote object can be cast to any of the set of remote interfaces supported by the implementation using the built-in Java syntax for casting. The built-in Java instanceof operator can be used to test the remote interfaces supported by a remote object.
The Java distributed object model differs from the Java object model in these ways: Clients of remote objects interact with remote interfaces, never with the implementation classes of those interfaces. Nonremote arguments to, and results from, a remote method invocation are passed by copy rather than by reference. This is because references to objects are only useful within a single virtual machine. A remote object is passed by reference, not by copying the actual remote implementation. The semantics of some of the methods defined by class Object are specialized for remote objects. Since the failure modes of invoking remote objects are inherently more complicated than the failure modes of invoking local objects, clients must deal with additional exceptions that can occur during a remote method invocation.



 Java CORBA combination
In their recent book, Client/Server Programming with Java and CORBA, Robert Orfali and Dan Harkey put it this way-

"Java is the first step toward creating an Object Web, but it is still not enough. Java offers tremendous flexibility for distributed application development, but it currently does not support a client/server paradigm. To do this, Java needs to be augmented with a distributed object infrastructure, which is where OMG's CORBA comes into the picture. CORBA provides the missing link between the Java portable application environment and the world of intergalactic back-end services. The intersection of Java and CORBA object technologies is the natural next step in the evolution of the Object Web."

The Marriage of Java-CORBA produces a platform-independent and cross-language model for Distributed Objects. Only the Java Programming language has an inverse mapping to IDL, this allows the programmer to stay in the Java world during the developmental stage of distributed applications. Because of their low-complexity and footprint, Java CORBA implementations can run on thin networks computers and low-end consumer devices. Also Java ORBs allow Java clients to be written without requiring any special software to be installed on the client, thanks to the mobile bytecodes.

Java-CORBA greatly simplifies software upgrades of Clients in large distributed systems, this is more so in Java because of the mobile byte codes and in CORBA due to the Dynamic Invocation Interface. To elucidate further Distributed Computing hitherto comprised of many clients and a few central servers, with the Client now being downloaded onto the Desktop courtesy Java-mobile codes all that is needed is an update of this downloadable client. ORBlets which would employ the CORBA DII (Dynamic Invocation Interface) produce the same effect on the server side.

Also it imperative that to operate in today's heterogeneous computing environments, distributed applications must work on a plethora of hardware & software platforms. Suitability to business class applications calls for capabilities beyond conventional web based computing - scaleability, high availability, performance and data integrity. This is where Java & CORBA play a role which mutually complements each other, Java provides for easier distribution of CORBA-based applications with CORBA providing the where withal of a distributed infrastructure.

CORBA Beans, much like their Java counterparts JavaBeans, will be lightweight, reusable, graphically based components that will give CORBA its long-awaited distributed object model. CORBA Beans will provide mapping from Java to C++ objects and hide Interface Definition Language, making CORBA programming significantly easier.


These factors substantiate the prognosis that the CORBA/IIOP-Java combination would assume a pivotal role in shaping the Internet during the next phase of its evolution.

Java-CORBA Applications

The Development Process for writing a CORBA based application comprises of the following steps. These steps that have been outlined are typical of most CORBA applications. But there could be deviations from this general rule.
  1. Define IDL
  2. Generating client stub and server skeleton using IDL compiler
  3. Object implementation (server) using BOA or TIE approach
  4. Client implementation
  5. Register Server with an ORB daemon
  6. Run client by contacting an ORB daemon


 Defining the IDL

IDL is a specialized language for defining interfaces, and this is what facilitates the notion of interacting objects, so central to CORBA. The IDL is the means by which objects tell their potential clients what operations are available and how they should be invoked. The IDL definition defines types of objects, their attributes, the methods they export and the method parameters.,

interface ImageFilter {
  typedef sequence sequence_of_long;
  ::ImageFilter::sequence_of_long filter(
    in ::ImageFilter::sequence_of_long npixel,
    in long imgw,
    in long imgh
  );
};


 Generating Client Stubs and Server Skeletons
This is usually done by using the idl2java pre-processor. This automatic generation of stubs frees the developer from having to write those stubs, and frees them from the dependencies of a particular ORB implementation. Compile all these java files.


>%idl2java filter.idl



 Anatomy Of the Files Generated
ImageFilter.java It maps the filter.idl to the corresponding Java Interface.
ImageFilterHelper.java :: This provides the bind method, which is used by clients to locate objects of the ImageFilter class. This also contains mappings for IDL out parameters. (Java natively supports only in parameters).
ImageFilterHolder.java :: Support for out and inout parameter passing modes requires the use of additional "holder" classes. These classes are available for all of the basic IDL datatypes in the org.omg.CORBA package and are generated for all named user defined types except those defined by typedefs.
ImageFilterOperations.java :: This has a list of all the operations that the ImageFilter performs.
_ImageFilterImplBase.java :: Class which Java implementations extend for actual Object implementations.
_sk_ImageFilter.java :: This implements the CORBA Server-side skeleton for ImageFilter. It unmarshalls the arguments for the ImageFilter Object. In addition this is what is reponsible for the convergence of CORBA and Java Object models.
_st_ImageFilter.java :: This implements the client-side stub for the ImageFilter Object. This is the class which provides for marshalling of functions.
_tie_ImageFilter.java



 Object Implementation Server using BOA (or tie) approach The ORB uses this information to locate active objects or to request activation of objects on a particular server. This server is primarily responsible for
Initializing the ORB
Initialize the BOA
Create a new instance of the ObjectImpl
Export the newly created object to the ORB
Wait for incoming requests
// CoordinatorServer.java

class FilterServer
{ static public void main(String[] args)
  {
    try
    { // Initialize the ORB.
      org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init();

      // Initialize the BOA.
      org.omg.CORBA.BOA boa = orb.BOA_init();

      // Create the Convex Filter object.
      ConvexFilterImpl _convex =
                  new ConvexFilterImpl("Convex");
      // Export the newly created object.
            boa.obj_is_ready(_convex);
      
      System.out.println("Exported both " + _convex);
      // Ready to service requests.
      System.out.println("Scheduler waiting for requests");
      boa.impl_is_ready();
      }
      catch(org.omg.CORBA.SystemException e)
      { System.err.println(e);
      }
   }
}


 The Object Implementation
This is the class that inherits the functionality of both the CORBA and Java object models. The task is basically to implement the ImageFilter Interface.

import java.awt.*;
import java.applet.*;

public class ConvexFilterImpl extends _ImageFilterImplBase {
  /** Construct a persistently named object. */
  public ConvexFilterImpl(java.lang.String name) {
    super(name);
  }
  /** Construct a transient object. */
  public ConvexFilterImpl() {
    super();
  }

  public int[] filter(int[] npixel, int nimgw, int nimgh) {
    System.out.println("Filterng begins on the server-side....");
    int pixel[] = new int[nimgw * nimgh];
    int wpixel[] = new int[nimgw];
    for (int j=0; j < nimgh ; j++) {
      
      for (int i=0; i < nimgw ; i++) {
        int a = 10 - i%10 + i;
        a += nimgw*j;
        if (a < nimgw * nimgh) wpixel[i] = npixel[a];
        else wpixel[i] = npixel[nimgw*nimgh -1];
      }
      System.arraycopy(wpixel,0, pixel, j*nimgw, nimgw);
    }
    return pixel;    
  }
}



 Writing a client to access the ObjectImplementation
public void
  connect() {
    System.out.println("Binding to the Request Broker");
    // Initialize the ORB.
    org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init();
    long startTime = System.currentTimeMillis();
    // Bind to the Coordinator Object
    //contrast = filters.ImageFilterHelper.bind(orb,"Contrast");
*    long stopTime = System.currentTimeMillis();
          System.out.println("Avg Ping to bind = "
                         + ((stopTime - startTime)/1000f) + " msecs");
    System.out.println("Ready");
   }



  public void convex() {
    org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init();
    convex = ImageFilterHelper.bind(orb,"Convex");
    System.out.println("Convex started");
    long startTime = System.currentTimeMillis();
    npixels= convex.filter(npixels,nimgw,nimgh);
    long stopTime = System.currentTimeMillis();
    System.out.println("Avg Ping to complete operation = "
                       + ((stopTime - startTime)/1000f) + " msecs");
    System.out.println("Contrast completed");
    updateCanvas();

  }


Java RMI Applications

The Development Process for writing a RMI based applications comprises of the following steps. These steps that have been outlined are typical of most RMI applications. But there could be deviations from this general rule.
  1. Define the Java remote interface
  2. Write the Java remote object server
  3. Generating client stub and server skeleton using the rmic compiler
  4. The Java applet that remotely invokes the server's method.
  5. The HTML code for the web page that references the applet.



 Defining the Java remote Interface
Remote method invocations can fail in very different ways from local method invocations, due to network related communication problems and server problems. To indicate that it is a remote object, an object implements a remote interface, which has the following characteristics:
The remote interface must be public. Otherwise, a client will get an error when attempting to load a remote object that implements the remote interface.
The remote interface extends the interface java.rmi.Remote.
Each method must declare java.rmi.RemoteException in its throws clause, in addition to any application-specific exceptions.
Any remote object passed as an argument or return value (either directly or embedded within a local object) must be declared as the remote interface, not the implementation class.
Here is the interface definition for the RMIFilter. The interface contains just one method, filter, which returns an array of integers, to the client desiring the filter operation.

import java.rmi.*;

public interface RMIFilter extends Remote {

  public int[] filter(int[] pixel, int nimgw, int nimgh) 
       throws java.rmi.RemoteException;

}



 Write the Java remote object server
To write a remote object, one write a class that implements one or more remote interfaces. The implementation class needs to:
Specify the remote interface(s) being implemented, in this case the RMIFilter Interface.
Define the constructor for the remote object.
Provide implementations for the methods that can be invoked remotely. A class can define methods not specified in the remote interface, but those methods can only be invoked within the virtual machine running the service and cannot be invoked remotely.
Create and install a security manager.
Create one or more instances of a remote object.
Register at least one of the remote objects with the RMI remote object registry, for bootstrapping purposes.

The implementation class specifies the remote interface(s) it is implementing. Optionally, it can indicate the remote server that it is extending, which in this example is java.rmi.server.UnicastRemoteObject. As can be seen there is a call to the super() method. The super method call invokes the no-arg constructor of java.rmi.server.UnicastRemoteObject which "exports" the remote object by listening for incoming calls to the remote object on an anonymous port. The constructor must throw java.rmi.RemoteException, because RMI's attempt to export a remote object during construction might fail if communication resources are not available.

For bootstrapping, the RMI system provides a URL-based registry that allows a bind to a URL of the form rmi://host/objectname to the remote object, where objectname is a simple string name. Once the remote object is registered on the server, clients can look up the object by name, obtain a remote object reference, and then remotely invoke methods on the object. The code which implements this operation is Naming.rebind("rmi://tarkovsky.npac.syr.edu:6000/rmiFilter", h);, assuming ofcourse that the rmiregistry is started on port 6000 on tarkovsky.npac.syr.edu.
import java.rmi.*;
import java.rmi.server.*;
import java.net.*;

public class RMIFilterImpl extends UnicastRemoteObject implements RMIFilter {
  public RMIFilterImpl() throws RemoteException {
    super();
  }
     
  public int[] filter(int[] npixels, int nimgw, int nimgh)
       throws RemoteException {
	 System.out.println("Filterng begins on the server-side....");
	 int pixel[] = new int[nimgw * nimgh];
	 int wpixel[] = new int[nimgw];
	 for (int j=0; j < nimgh ; j++) {
	   
	   for (int i=0; i < nimgw ; i++) {
	     int a = 10 - i%10 + i;
	     a += nimgw*j;
	     if (a < nimgw * nimgh) wpixel[i] = npixel[a];
	     else wpixel[i] = npixel[nimgw*nimgh -1];
	   }
	   System.arraycopy(wpixel,0, pixel, j*nimgw, nimgw);
	 }
	 return pixel;    
  }

  public static void main(String args[]) {

    try {
      RMIFilterImpl h = new RMIFilterImpl();
      Naming.rebind("rmi://tarkovsky.npac.syr.edu:6000/rmiFilter", h);
      System.out.println("RMIFilter Server ready.");
    }
     catch (RemoteException re) {
      System.out.println("Exception in RMIFilterImpl.main: " + re);
    }
    catch (MalformedURLException e) {
      System.out.println("MalformedURLException in RMIFilterImpl.main: " + e);
    }

  }

}


  Generating client stub and server skeleton using the rmic compiler
% rmic -d $RMICLASSES_HOME/ RMIFilterImpl

The -d option indicates the root directory in which to place the compiled stub and skeleton files. The generated stub implements exactly the same set of remote interfaces as the remote object itself. This means that a client can use the Java language's built-in operators for casting and type checking. It also means that Java remote objects support true object-oriented polymorphism.



 The Java applet that remotely invokes the server's method.
The code snippet details the operation that preceed the remote invocation and the actual remote call. The first operation is to get a refernce to "rmiFilter", the object Reference is then narrowed to the actual remote Interface RMIFilter. This is then followed by a remote invocation of the method in question. These operation are embedded in a try-catch block.
public boolean
  action(Event event, Object obj) {
    System.out.println("CorbaImaging: action.");
    if ("smooth".equals(obj)) {
      try {
	Remote remoteObject = 
	  Naming.lookup("rmi://tarkovsky.npac.syr.edu:6000/rmiFilter");
	/*** Narrow the Object reference to a specific one */
	RMIFilter f;
	f = (RMIFilter) remoteObject;
	
	/** Make the invocation */
	try {
	  pixel = f.filter(pixel, imgw, imgh);
	  System.out.println("Filter Operation Complete");
	  img = pixelsToI(pixel, imgw, imgh);
	  viewer.image= pixelsToI(pixel,imgw,imgh);
	  viewer.repaint();
	  System.out.println("Image Calculated from Pixels");
	  repaint();
	}
	catch (java.rmi.RemoteException exc) {
	  System.out.println("Error in Invocation " + exc.toString());
	}
      }
      catch (Exception exc) {
	System.out.println("Error in lookup");
      }
      repaint();
      return true;
    }

Once the registry and server are running, the applet can be run. An applet is run by loading its web page into a browser or appletviewer. The HTML File is given below.
<applet code=ImagingClient.class width=400 height=500> <\applet>


JDCE - Java Distributed Collaborative Environment

The Web along with the Browser has enabled the dessimination of rich multimedia content to an unprecedented number of users. However, many fail to understand Web applications for what they are - Distributed Applications. CORBA was developed with the primary aim of building interoperable distributed solutions which work across multiple hardware and software platforms. RMI on the other hand extends Java naturally into the Distributed Object computing domain, introducing local/remote transparency for method invocations on Java objects. The intersection of these solutions catalyze the development of dynamic solutions and opens new interesting avenues for the standards based collaboratory infrastructures. Java Distributed Collaborative Environment is an attempt to explore these concepts and the feasibility (quantized in terms of high availability, scalability and fault tolerance) of such systems. In the sections that follow there is a detailed discussion about the scaffoldings that JDCE is built upon, the retrofitting process and feasability analysis.


 Features
A distributed-approach towards Collaborative Environments.
Support for IIOP- and RMI- based Transport Protocols. The environment provides for Collaboration between an RMI-Client and a CORBA-client
A Distributed Event and Exception Heirarchy.
Based on the CORBA Naming Service.



 Dynamics Of Collaboration

The Client initiates a bind to the sessionScheduler Object. Given that this is successful, in the event that there is a Distributed Directory service and the Active Object server is in place, the Client is now ready to invoke the IDL-defined operations defined for the System. Nevertheless, an invocation of any of these aforementioned operations should be preceeded by a successful reception of a remote handle to these objects. For a caller (client, peer, or applet) to be able to invoke a method on a remote object, that caller must first obtain a reference to the remote object. Most of the time, the reference will be obtained as a parameter to, or a return value from, another remote method call.
It starts with the createBahn(String PartyName, String _applicationServerName) throws jdceBahnException function which would return a true in the event that a new dataBahn Object has been instantiated or a jdceBahnException is raised to signify the prior existence of the desired Bahn. It is the Scheduler's job to signal the appropriate notification to the Clients and perform appropriate house-keeping to reflect new instances of dataBahn's.

The Client now has the option to decide wether he wishes to join an existing Bahn (party) or initiate the existence of a new one. In the latter case Step[1] is repeated as mentioned earlier. This operation also raises the jdceBahnException to signify the non-existence of the dataBahn. Once the process is over, the Client gets a handle to the dataBahn Object by invoking jdce.byteways.dataBahn getDataBahnHandle(String PartyName, String _applicationServerName) throws jdceBahnException .

Once Steps I and II are over and done with, the Client is in a Distributed Collaboration mode, and can invoke operations specified in IDL definitions for the dataBahn. These operations are preceeded by public int register(String _clientName, clientProxy _clientObjRef) throws jdceBahnException, jdceClientException , the registration process is a pre-requisite to switching to the Collaboration mode. Once the registration process is over and done with the DataBahn serves as a conduit for messages and the Client could invoke operations such as public boolean broadcastMessage(jdceMessage _message), public boolean whisperMessage(jdceMessage _message, String _clientName) throws jdceClientException, jdceBahnException etc.


This is just another demonstration of the complementary roles Java & CORBA play in a distributed environments. Java provides for easier distribution of CORBA-based applications with CORBA providing the where withal of a distributed infrastructure. In summary, CORBA offers both a potential candidate for universal wire protocol, IIOP, and a natural collaboratory framework based on shared CORBA objects and flexible message filtering mechanisms offered by the Event Service.



JDCE Widgets


 Session Scheduler
The Session Scheduler provides the basic house-keeping necessary for the JDCE Collaborative Environment. The scheduler maintains a registry of the all the applications and dataBahns that were spawned by the scheduler. Invocation of any of the aforementioned operations should be preceeded by the successful receipt of a handle to the sessionScheduler. It should be understood that Clients of remote objects interact with remote interfaces, never with the implementation classes of those interfaces. Nonremote arguments to, and results from, a remote method invocation are passed by copy rather than by reference. As can be seen, each method declares java.rmi.RemoteException in its throws clause, in addition to the jdce exceptions that would be described briefly. All the JDCE exceptions are checked exceptions hence client programmers who wish to invoke these methods would 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. In the RMI based environment, when a java.rmi.RemoteException is thrown during a remote method invocation, the client may have little or no information on the outcome of the call - whether a failure happened before, during, or after the call completed.

package jdce.scheduler;
import jdce.util.exception.*;

public interface RMISessionScheduler extends java.rmi.Remote {
  
  String[] listApplications() 
       throws java.rmi.RemoteException, jdceRMIBahnException;
 
  String[] listBahns(String _applicationServerName) 
       throws java.rmi.RemoteException, jdceRMIBahnException;

  boolean createBahn(String PartyName ,String _applicationServerName) 
       throws java.rmi.RemoteException, jdceRMIBahnException;
  
  boolean joinBahn(String PartyName ,String _applicationServerName) 
       throws java.rmi.RemoteException, jdceRMIBahnException;
  
  jdce.byteways.RMIDataBahn
  getDataBahnHandle(String PartyName,String _applicationServerName) 
       throws java.rmi.RemoteException, jdceRMIBahnException;
  
  boolean destroyBahn( String PartyName ,String _applicationServerName) 
       throws java.rmi.RemoteException, jdceRMIBahnException;    

}


 module scheduler {
    interface sessionScheduler {
      typedef sequence sequence_of_string;
      ::jdce::scheduler::sessionScheduler::sequence_of_string listApplications()
         raises(::jdce::util::exception::jdceBahnException);

      ::jdce::scheduler::sessionScheduler::sequence_of_string listBahns(in string arg0)
         raises(::jdce::util::exception::jdceBahnException);

      boolean createBahn(in string arg0, in string arg1)
         raises(::jdce::util::exception::jdceBahnException);

      boolean joinBahn(in string arg0, in string arg1)
         raises(::jdce::util::exception::jdceBahnException);

      ::jdce::byteways::dataBahn getDataBahnHandle(in string arg0, in string arg1)
         raises(::jdce::util::exception::jdceBahnException);

      boolean destroyBahn(in string arg0, in string arg1)
         raises(::jdce::util::exception::jdceBahnException);
    };
  };




Reverting back to the specifics of the session Scheduler, the points which need to be noted is that the scheduler maintains a list of all applications that have been registered with it. This information is then linked with all the DataBahns that have been created by the scheduler. The intersection of these two registries provides a listing of all the data Bahns that have been created for a specific application. This information is passed to the Client as an array of Strings . The client can then decide to either join (or create) a data Bahn. Besides this the scheduler provides operations for getting a remote reference to a dataBahn as also a method to detroy a specific Bahn.
 Data Bahn
DataBahns provide the basic abstraction of a communication channel, which support different message passing primitives besides providing for registration and deregistration from the communication channels. To put it briefly the DataBahn is essentially a conduit for message passing. Invocation of any of the operations listed in the DataBahn Interfaces should be preceeded by the register method being called. This registration results in the creation of a worker thread for the client to handle callbacks from the server-side. Besides this the thread is also add to the thread scheduler to reduce the average response time in message processing.

The figure above demonstrates the details of the BROADCAST and INFORM_OTHERS message primitives. In the former case the message is frist sent to the server and the server initiates callbacks on all the clients registered on the DataBahn. In this case the client which initiated the communication also receives a response from the server. In the latter case i.e. INFORM_OTHERS all the clients excluding the one which initiates the communication receives a response from the Server. The two modes are different in the terms of the response time from the Server, in the latter case the client could just perform the actions which would be performed in the case that the message was received from the server and still have the effect of BROADCAST with a much better response time on the Client which initiated the operation. It is up to the client what to do with the message. It may even choose to ignore the message, for example if such a message is unauthorized or out of context. Authorization checks and other security responsibilities are best handled by clients. If a client has buggy code, only that client is affected. A bug in the server affects all clients. The only thing the server may do is the initial check to see if the client has authority to connect to it.
An ideal implementation of group broadcast would use multicast sockets (java.net.MulticastSocket) to communicate efficiently with other group members. However, applets are not allowed to open multicast sockets, and even if they were, operation of a multicast socket through the Internet requires the underlying support of the Multicast Backbone (MBONE), which is not yet widely deployed. Moreover, multicast sockets only support unreliable datagrams, and would thus require designing a reliable protocol.





The figure above demonstrates the whisper primitive where a Client sends a message only to a specific client. The Client initiating the whisper gets a response which indicates the success or failure of the operation reflecting the autorizations/presence of the Client or the lack thereof, this is clearly reflected in the exceptions that would be thrown.

It should be noted that the RMIDataBahn and the CORBA-based DataBahn supports the same set of operations. The DataBahn also provides operations for expelling a certain client, listing the number/information of members registered to the DataBahn. The exceptions thrown in both the RMI/CORBA case are similar but for the additional RemoteException thrown in the RMI mode. The RMIDataBahn Interface detialing all these operation are given below, the IDL definition for the DataBahn has been omiited here for the sake of clarity. The complete IDL defintion would nevertheless be available in the appendix.

package jdce.byteways;

import jdce.util.message.*;
import jdce.util.exception.*;

public interface RMIDataBahn extends java.rmi.Remote {

 String getApplicationServerName() throws java.rmi.RemoteException;
  int numberOfMembers() throws java.rmi.RemoteException; 

  String[] getClientNames() throws java.rmi.RemoteException;
  boolean isEmpty() throws java.rmi.RemoteException;
  
  int register (String ClientName,
		jdce.client.RMIClientProxy clientObjRef) 
       throws java.rmi.RemoteException, 
    jdceRMIBahnException, jdceRMIClientException;
       
  boolean expelClient(String _sender, String _expelee)  
       throws java.rmi.RemoteException,
    jdceRMIBahnException, jdceRMIClientException;

  boolean deregister(String ClientName)  
       throws java.rmi.RemoteException,jdceRMIClientException;
  
  boolean broadcast(String Message) throws java.rmi.RemoteException;

  boolean broadcastMessage(jdce.util.message.jdceMessage Message) 
       throws java.rmi.RemoteException, jdceRMIBahnException;
  
  boolean inform(jdce.util.message.jdceMessage Message)
       throws java.rmi.RemoteException, jdceRMIBahnException;

  boolean whisper(String Message, String clientName) 
       throws java.rmi.RemoteException,
    jdceRMIClientException, jdceRMIBahnException;

  boolean whisperMessage(jdce.util.message.jdceMessage Message, 
			 String clientName) 
       throws java.rmi.RemoteException,
    jdceRMIClientException, jdceRMIBahnException;

}

 Client Proxy
The Client Proxy interface defines the appropriate methods which would be called by the DataBahn Object Implementation in reponse to the events taking place on it. This includes the dataReceive(java.lang.String Message) which would be called in case the message sent by any of the registered (on the DataBahn) clients is a String. The messageReceive(jdce.util.message.jdceMessage Message) is called in the case the messages are exchanged in the jdce.util.message.jdceMessage format, this particular message format is explained in detail in a later sub-section. The clientEvent(jdce.util.event.jdceEvent evt) is called in the case that a client has just registered to the DataBahn, or has been deregistered/expelled. In any case the jdce.util.event.jdceEvent object created by the DataBahn provides the relevant information.
package jdce.client;

public interface RMIClientProxy extends java.rmi.Remote {

  boolean clientEvent(jdce.util.event.jdceEvent evt) 
       throws java.rmi.RemoteException;
  
  boolean dataReceive(java.lang.String Message) 
       throws java.rmi.RemoteException;
  
  boolean messageReceive(jdce.util.message.jdceMessage Message) 
       throws java.rmi.RemoteException;
  
}



 Exception Hierarchy
Exceptions are the customary way in Java to indicate to a calling method that an abnormal condition has occurred. When a method encounters an abnormal condition (an exception condition) that it can't handle itself, it may throw an exception. Exceptions have several benefits. First, they allow you to separate error handling code from normal code. You can surround the code that you expect to execute 99.9% of the time with a try block, and then place error handling code in catch clauses -- code that you don't expect to get executed often, if ever. This arrangement has the nice benefit of making your "normal" code less cluttered. In general, one should throw an exception and and never throw errors. Error, a subclass of Throwable, is intended for drastic problems, such as OutOfMemoryError, which would be reported by the JVM itself. On occasion an error, such as java.awt.AWTError, could be thrown by the Java API. In your code, however, you should restrict yourself to throwing exceptions (subclasses of class Exception).

A checked exception is some subclass of Exception (or Exception itself), excluding class RuntimeException and its subclasses. Unchecked exceptions are RuntimeException and any of its subclasses. Throwable and any subclasses besides the Exception family, including Error and its subclasses, also are unchecked. But as one should be focusing on throwing exceptions only, the decision should be whether to throw a subclass of RuntimeException (an unchecked exception) or some other subclass of Exception (a checked exception).

If you throw a checked exception (and don't catch it), you will need to declare the exception in your method's throws clause. Client programmers who wish to call the method 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.




If you throw an unchecked exception, client programmers can decide whether to catch or disregard the exception, just as with checked exceptions. With an unchecked exception, however, the compiler doesn't force client programmers either to catch the exception or declare it in a throws clause. In fact, client programmers may not even know that the exception could be thrown. Either way, client programmers are less likely to think about what they should do in the event of an unchecked exception than they are in the case of an unchecked exception.
The JDCE Exceptions are all checked exceptions and hence client application writers need to be aware of the exceptions that would take place. Though these exceptions makes development of JDCE applications seem rather clumsy because it forces you to think about something you would rather ignore, the applications are ultimately much more solid and reliable.
module java {
  module lang {
    extensible struct Object;
  };
};
module jdce {
  module util {
    module exception {
      exception jdceBahnException {
        long type;
      };
      exception jdceClientException {
        long type;
      };
    };
  };
};

IDL Definition

class java.lang.Object
interface jdce.util.exception.jdceException.
class java.lang.Throwable (implements java.io.Serializable)
class java.lang.Exception
class org.omg.CORBA.UserException
class jdce.util.exception.jdceBahnException (implements java.io.Serializable, jdce.util.exception.jdceException)
class jdce.util.exception.jdceClientException (implements java.io.Serializable, jdce.util.exception.jdceException)
class jdce.util.exception.jdceRMIBahnException (implements java.io.Serializable, jdce.util.exception.jdceException)
class jdce.util.exception.jdceRMIClientException (implements java.io.Serializable, jdce.util.exception.jdceException)




The code below demonstrates the try-catch block employed by a client application to register itself to the dataBahn. The method register belongs to the dataBahn object, and it throws both a jdceBahnException and jdceClientException if it encounters an error. These errors are detailed shortly below.

try {
	 thisClient._chatBahn.register(thisClient.clientName,
					   (jdce.client.clientProxy)control);
	 System.out.println("Registration Succeeded");
       } catch (jdceBahnException e) {
	 System.out.println(e.typeToString(e.getType()));
	 System.out.println("Bahn Exception");
       } catch (jdceClientException e){
         System.out.println(e.typeToString(e.getType()));
	 System.out.println("Client Exception");

       }
If a Client exception has occured. The following exception types can occur:
NAME_IN_USE - a client with a similar name exists.
ALREADY_BOUND - The client & the obj Reference have been registered.
CLIENT_NOT_REGISTERED - The registration process failed.
NOT_BOUND : The client has not been bound to the Session Scheduler, Collaboration mode not yet activated for Client.
INVALID_OPERATION: Client not authorized for the particular operation.
UNKNOWN : Reason unknow to the JDCE Environment.


If a Bahn exception has occured. The following exception types could occur.
BAHN_CREATION_FAILED : The Bahn was not created successfully.
BAHN_EXISTS : The Bahn exists, i.e. there is Bahn for a given application under the same name.
BAHN_JOIN_FAILED : Join to the dataBahn failed.
NO_SUCH_BAHN: Reference to a non-existant dataBahn.
PERMISSION_DENIED: One of the operations on the dataBahn (expel, invite etc ) not completed due to insufficient permissions for the client which invoked the operation.
UNKNOWN : Reason unknow to the JDCE Environment.

 Client Events - A Reporting mechanism
A software event is a piece of data sent from an object, notifying the recipient object of a possibly interesting occurence. Basically any occurence can be modeled as an event and the relevant information regarding the event can be encapsulated within the event. To put it simply an event is self describing. Firing and reponsive handling of events are one of two ways that objects communicate with each other, besides invoking methods on each other. Both these techniques are in a sense one and the same. The client notification mechanism is available only to the valid registered clients on a dataBahn. The reporting mechanism is not available across dataBahns, i.e. a client on a Chat_Bahn cannot receive client activities on a WhiteBoard_Bahn.
module jdce {
  module util {
    module event {
      extensible struct jdceEvent {
        long type;
        string clientName;
      };
    };
  };
};

IDL Definition

java.lang.Object
jdce.util.event.jdceEvent implements java.io.Serializable


There are three types of client changes: -
CLIENT_JOIN - a client has joined the dataBahn.
CLIENT_LEAVE - a client has left the dataBahn.
CLIENT_EXPEL - a client has been expelled by the creator of the bahn.



 Messages
The jdceMessage format provides a clear representation of the Message Origins, the applicationSession it is intended for, the prioirity of the message, the transport protocol it uses to reach the sessionScheduler and the message Content, which could be any serializable Object. Arguments to, or return values from, remote methods can be of any Java type, including objects, as long as those objects implement the interface java.io.Serializable. Most of the core Java classes in java.lang and java.util implement the Serializable interface. The only widget in the Message format which could possibly need a serialization method implemented is the content.

java.lang.Object
jdce.util.message.jdceMessage implements java.io.Serializable
module java {
  module lang {
    extensible struct Object;
  };
};

module jdce {
   module util {
    module message {
      extensible struct jdceMessage {
        string sender;
        string applicationType;
        string messageType;
        string protocolType;
           ::java::lang::Object content;
      };
    };
   };
};

IDL Definition.
The Message Object Implementation consists of the following methods, which conform to the JavaBeans Design Patterns.
getApplicationType()
getBahnName()
getContent()
getProtocol()
getSender()
setApplicationType(String)
setBahnName(String)
setContent(Object)
setProtocolType(String)
setSender(String)


jdce.util.message.jdceMessage _mess = 
	    new jdce.util.message.jdceMessage();
     _mess.setSender(clientName);
     _mess.setApplicationType("Chat");
     _mess.setProtocol("IIOP");
     _mess.setBahnName(partyName+"Chat"+"Bahn");
    try {
	for (int i=0; i < 15; i++) {
	    _mess.setContent((Object)typeField.getText() + " Inform" +i);
	      _chatBahn.inform(_mess);
	  }
     } catch (jdceBahnException e) {}




 Message Queue
Active message handling requires that the system possess a message queue, which collects messages from other active clients and distributes them in first-in, first-out (FIFO) order to the worker threads responsible for invoking the callbacks. The jdceMessageQueue 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 messages 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 Worker threads consume messages which are available on the MessageQueue, while the Clients add messages (priority/otherwise) to the MessageQueue. One of the primary reasons for implementing the Message Queue as a Linked List was the faster addition and removal of messages from the MessageQueue. The messages in the Message queue are never processed out-of-order i.e. the element consumed is always the HEAD of the message Queue, though it must be noted that there is method available to remove a specific element from the List. Besides this the message queue also provides for reporting availability of data on the queue and provides for returning the queue Contents as a stream of bytes or an array of Strings. The queue also has a in-lined class the QueueEnumerator which provides an Enumeration of the QueueContents.




 Worker Threads
A thread, or a sequence of instructions being executed in a program, is a lightweight process that reduces overhead by sharing fundamental parts with other threads. Threads are lightweight so that there can be many of them present within a process. Using multiple threads provides concurrency within an application and improves performance. Applications can be structured efficiently with threads servicing several independent computations simultaneously. To maintain uniform sequencing of messages received in the Collaborative system, the thread pooling policy employed in the system is the thread-per-session policy. This ensures that messages are never handled out of sequencing. Priority messages are handled by the MessageQueue implementation which can add a priority message to the top of the messageQueue.

With the thread-per-session policy employed by JDCE, threading is driven by connections between the client(RMI or CORBA) and server processes. The thread-per-session policy allocates a new worker thread, everytime a new client registers itself with a dataBahn, to handle the call-backs from the server-side.. (With thread-per-session, there is only a combination thread-the reader/worker thread. The functionality is not split into two different threads like it is in thread pooling.) The worker thread handles all the requests received from a particular client. When the client disconnects from the server, the worker thread is destroyed.


Given below are the references contained in the Worker threads and their class-inheritances.

The RMIWorker Thread contains references to the corresponding RMIClient.
The CorbaWorker contains references to the CorbaClient.
class java.lang.Thread (implements java.lang.Runnable)
class jdce.util.message.jdceRMIWorker
class jdce.util.message.jdceWorker


Both the RMIWorker and CORBAWorker Threads are scheduled by the jdceThreadScheduler. The fact that the ThreadScheduler schedules both the RMI and CORBA threads facilitates collaboration involving RMI and CORBA Clients.

 The CORBA Naming Service
The Naming Service provides the ability to bind a name to an object relative toa 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. 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. Through the use of a "names library," name manipulation is simplified and names can be made representation-independent thus allowing their representation to evolve without requiring client changes. Application localization is facilitated by name syntax-independence and the provision of a name "kind" attribute.

Scalability and Fault tolerance Issues

The ideal system would be perfectly scalable and fail-proof. This, of course, is impossible pragmatically considering the non-utopian world that we live in. System developers have finite resources to devote to reliability and consumers would be willing to pay approximately the same for these features. Thus systems need to try and reasonably approximate the scaling/fault-tolerance issues.

Scaling: Specifically this addresses the issue of replication of Servers accross different participating hosts in a Collaborative environment, when the load (participating sessions) on a server crosses a certain threshold. The API supports the notion of groups within a certain session, and since the Object-Implementations handling the groups can be hosted on different machines, the problem of Scalability is addressed to a considerable extent.


Fault tolerance:This concerns the problem of migrating sessions to a different participating host should the machine hosting the server crash - this with minimal or little disruption.
  1. The ObjectServices agent which is a distributed directory service allows for migration of sessions to a different participating host in the case that a session terminates unexpectedly on one of the hosts
  2. The Events are persistently stored by the Event Channel to ensure that events are not lost on system failures.

Setting up JDCE for your desktop


 Pre-requisites
A CORBA-compliant Java Object Request Broker.
The CORBA Naming service.
The JDK 1.1.X Virtual Machine.


 Starting the servers & setting up JDCE
Starting the Active Object Server, the default port it binds to is 14000 (ports less than 1024 require administrative priveleges).
% osagent

Starting the Gatekeeper which acts as a HTTP-tunneler for Callbacks through firewalls, the default port it runs on is 15000
% gatekeeper


Starting up the RMIregistry on some port, (ports less than 1024 require administrative priveleges) say 7000. The RMI registry is a simple server-side bootstrap name server that allows remote clients to get a reference to a remote object. It is typically used only to locate the first remote object an application needs to talk to. That object in turn will provide application specific support for finding other objects.

% rmiregistry 7000


For security reasons, an application can bind or unbind only in the registry running on the same host. This prevents a client from removing or overwriting any of the entries in a server's remote registry. A lookup, however, can be done from any host. This requires every Client to start-up the rmiregistry on its host machine. In the case that the client and server are on the same machine, the rmiregistry needn't be started for the client. It is necessary to specify the port number only if a server creates a registry on a port other than the default 1099.

Starting the Naming Service, with the nameContext Root as JDCE. To use the Name Service, at least one Naming Factory must be started. The Factory object lives within a server process, and is used to create NamingContext objects. When the default Factory server is started, it creates no NamingContexts. When it is asked to create NamingContexts, all such NamingContext objects created by a given Factory are located within the same process as that Factory.

%java -DORBservices=CosNaming -DSVCnameroot=JDCE -DJDKrenameBug com.visigenic.vbroker.services.CosNaming.ExtFactory JDCE namingLog

The first step to creating a namespace is starting at least one Factory server. Here we start up a single Factory server process. The Factory will be given the logical name "JDCE". In addition, the name of a log file is specified (in this case, the locally created "namingLog" file will be used). This log will contain information allowing the Name Service to be shut down and then reDOWNLOADd upon restart to its state prior to shutdown. Here we have used the idea of connecting Contexts that live within distinct Name Servers, the rootContext in this case is JDCE. Now that a Context has been created, we can "publish" an Object's reference within that Context. Anyone can access this published object if they have both:
a reference to the NamingContext in which it is published.
the name within that NamingContext with which the Object's reference was originally bound.


Starting the main Object Server, which starts up both the RMI/CORBA sessionScheduler.The ORBservices System Property tells the ORB you wish your program to use the Name Service. The SVCnameroot parameter tells the ORB which root naming context should be returned by resolve_initial_references.. Now that a Context has been created, we can "publish" an Object's reference within that Context. Anyone can access this published object if they have both: a reference to the NamingContext in which it is published. the name within that NamingContext with which the Object's reference was originally bound.
%java -DORBservices=CosNaming -DSVCnameroot=JDCE jdce.impl.corba.sessionServer


 Applet-Tags for CORBA & RMI Clients.
The HTML file, for the JDCE CORBA-client applet. When using Communicator, you have two choices on how to program your applets. You may use the ORB embedded in Communicator (which matches VisiBroker for Java 2.5), or you may download the VisiBroker for Java 3.0 ORB on top of the existing version in Communicator. You should download the VisiBroker for Java 3.0 ORB if you are using features new to VisiBroker 3.0 such as interceptors, event handlers, or SSL.
To use the ORB runtime that comes with Communicator, you must run your servers and the GateKeeper in backward compatibility mode and add the following param tag to your applet tag in your HTML file. <param name=USE_ORB_LOCATOR value=true>
To use VisiBroker for Java 3.0 instead of Communicator's version of VisiBroker, add the following param tag to your applet tag in your HTML file. No special flags are required for the GateKeeper or servers. <param name=org.omg.CORBA.ORBClass
value=com.visigenic.vbroker.orb.ORB>
<applet code=demos.chat.ChatUser.class width=400 height=350>
<param name=org.omg.CORBA.ORBClass
       value=com.visigenic.vbroker.orb.ORB>
<param name=ORBservices value=CosNaming>
<param name=SVCnameroot value=JDCE>
</applet> 
The HTML file, for the JDCE RMI-client applet.
<applet code=demos.rmi.RMIChatUser.class 
width=400 height=350 serverHostname="jojo.npac.syr.edu" serverPort=7000>
</applet>

Developing JDCE Applications.

The goal of this section is to give a small demonstration of the techniques that are useful in building collaboration-aware applications grounds-up or to retrofit single user applications into multi-user applications. Of considerable significance is an understanding of the fact that Clients of remote objects interact with remote interfaces, never with the implementation classes of those interfaces. That aside, development of JDCE applications involves 3 basic steps in addition to the functionality provided by the application that you desire.
Getting a handle to the session Scheduler
Getting a reference to the DataBahn
Publishing the client Reference
Once these three steps have been completed successfully the client switched to collaboration mode with all other clients that have successfully registered with a certain DataBahn. Client are never in collaboration mode with client across DataBahn's though there is a roundabout way of doing the same. To keep things simple we assume that clients are always in intra-Bahn-collboration mode as opposed to inter-Bahn-Collaboration.

 Binding to the sessionScheduler (CORBA) Vs (RMI)
CORBA Binding Process.
The Steps involved are detailed below:
Obtaining the Initial Naming Context: The client obtains a reference to the initial naming context by invoking the org.omg.CORBA.ORB's resolve_initial_references.

     org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(this, null);
     org.omg.CORBA.Object nameServiceObj = orb.resolve_initial_references("NameService");
     org.omg.CosNaming.NamingContext nameService = org.omg.CosNaming.NamingContextHelper.narrow(nameServiceObj);

Creating the Composite name: Since we are looking for Scheduler, we need to first create the compound name "Collaboration", "Scheduler".

     NameComponent[] collabName = 
	     { new NameComponent("Collaboration", "Scheduler")};
Locate the Object with this Name: Inoke resolve on the NamingContext to obtain the object reference associated with the name created in the earlier step. Since the Name Service returns generic CORBA objects, it is necessary to narrow the generic object to a more derived class.

     jdce.scheduler.sessionScheduler _chatSession= 
	  jdce.scheduler.sessionSchedulerHelper.narrow(nameService.resolve(collabName));

    private void getSessionSchedulerHandle() {
      try {
	/* Initialize the ORB.*/
	org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(this, null);
	
	/* Get a reference to the Naming Service */
	org.omg.CORBA.Object nameServiceObj = 
	  orb.resolve_initial_references("NameService");
	/* Check to see if the operation involving getting a reference to the NameService was successful */
	if (nameServiceObj == null) {
	  System.out.println("Name Service Object = null");
	  return;
	}
	
	org.omg.CosNaming.NamingContext nameService =
	  org.omg.CosNaming.NamingContextHelper.narrow(nameServiceObj);

	if (nameService == null) {
	  System.out.println("nameService = null");
	  return;
	}
	
	NameComponent[] collabName = 
	{ new NameComponent("Collaboration", "Scheduler")};	
	_chatSession= 
	  jdce.scheduler.sessionSchedulerHelper.narrow(nameService.resolve(collabName));
      } catch(Exception e) {
	  System.out.println("Exception: " + e);
	}
      }

RMI Binding Process
The Client gets a reference to the "Scheduler" from the server's registry by constructing the URL rmi://jojo.npac.syr.edu:7000/Scheduler, where jojo.npac.syr.edu represents the HOSTNAME of the machine hosting the server, and 7000 represents the port the server listens to. This URL is used as a parameter to the java.rmi.Naming.lookup() method, this returns a generic Remote Object which is then cast to jdce.scheduler.RMISessionScheduler.

    private void getSessionSchedulerHandle() {
      try {
	remoteObject = 
	  Naming.lookup("rmi://jojo.npac.syr.edu:7000/Scheduler");
      } catch (java.lang.Exception exec) {
	System.out.println("Unable to lookup created Scheduler");
      }
      _chatSession = (jdce.scheduler.RMISessionScheduler) remoteObject;
      }


 Getting a handle to the Data Bahn (CORBA) Vs (RMI)
The CORBA DataBahn Handler

The following code snippet details the process involved in the creation/joining of a DataBahn. As can be seen the process of creating a DataBahn throws a jdceBahnException. The steps involved in Binding to the DataBahn Object are identical to that of the session Scheduler Object, but for a minor change in the NameComponent, which in this case would be a "Collaboration", DataBahn_Name. It should be understood nevertheless that getting a handle to the DataBahn can be achieved in two ways, the first technique is detailed in the code below, the second one involves invoking the getDataBahnHandle() on the session Scheduler Object. I have indicated the latter approach for the RMI Case.
public void getDataBahnHandle() {
      try {
	_chatSession.createBahn(partyName, "Chat");
	System.out.println("New Party created");
      } catch (jdceBahnException e) {
	System.out.println("Exception in creations" +e);
      } catch (Exception e) {
	e.printStackTrace();
      }
    
      long startTime = System.currentTimeMillis();
      try {
	// Initialize the ORB.
	org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(this, null);
	
	/* Get a reference to the Naming Service */
	org.omg.CORBA.Object nameServiceObj = 
	  orb.resolve_initial_references("NameService");
	
	if (nameServiceObj == null) {
	  System.out.println("Name Service Object = null");
	  return;
	}
	
	org.omg.CosNaming.NamingContext nameService =
	  org.omg.CosNaming.NamingContextHelper.narrow(nameServiceObj);
	if (nameService == null) {
	  System.out.println("nameService = null");
	  return;
	}
	
	NameComponent[] collabName = 
	{ new NameComponent("Collaboration", partyName+"Chat"+"Coordinator")};
	
	_chatBahn= 
	  jdce.byteways.dataBahnHelper.narrow(nameService.resolve(collabName));
      } catch(Exception e) {
	System.out.println("Exception: " + e);
      }
      long stopTime = System.currentTimeMillis();
      System.out.println("Avg Ping to invoke = "
			 + ((stopTime - startTime)/1000f) + " msecs");
    }


The RMI DataBahn Handler

The following code snippet details the process involved in the creation/joining of a DataBahn. As can be seen the process of creating a DataBahn throws a jdceRMIBahnException in addition to the usual java.rmi.RemoteException which is thrown for any remote method invocation. The technique in getting a handle to the DataBahn, involves the invocation of the getDataBahnHandle() method. The second approach which could have been used is the approach similar to the one used for getting a refernce to the session Scheduler only that in this case the constructed URL would have been rmi://jojo.npac.syr.edu:7000/DataBahn_Name
public void getDataBahnHandle() {
      try {
	_chatSession.createBahn(partyName, "Chat");
	System.out.println("New Party created");
      } catch (jdceRMIBahnException e) {
	System.out.println("Exception in creations" +e);
      } catch (Exception e) {
	e.printStackTrace();
      }
    
      //      long startTime = System.currentTimeMillis();
      
      try {
	_chatBahn = _chatSession.getDataBahnHandle(partyName, "Chat");
      }  catch (jdceRMIBahnException e) {
	System.out.println("Exception in creations" +e);
      } catch (Exception e) {
	e.printStackTrace();
      }
    }



 Publishing the Client Reference (CORBA) Vs (RMI)
Publishing the Client Reference (CORBA)
try {
       /* Initialize the ORB.  */
	org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(thisClient);
	/* Create the Client Implementation object. */
	ClientControlImpl control = new ClientControlImpl(thisClient);
	orb.connect(control);

       try {
	 thisClient._chatBahn.register(thisClient.clientName,(jdce.client.clientProxy)control);
	 System.out.println("Registration Succeeded");
       } catch (jdceBahnException e) {
	    System.out.println(e.typeToString(e.getType()));
       } catch (jdceClientException e){
            System.out.println("Registration Failed");
       }

  }  catch(org.omg.CORBA.SystemException e) {
       System.err.println(e);
     }


Publishing the Client Reference (RMI)
   try { 
	control = new RMIClientControlImpl(thisClient);
	identity= "rmi://hawaii.npac.syr.edu:7000/" + thisClient.clientName;
	Naming.rebind(identity, control);
      System.out.println("ClientControl Export done.");
    } catch (RemoteException re) {
      System.out.println("Exception in Client Impl.main: " + re);
    } catch (MalformedURLException e) {
      System.out.println("MalformedURLException CoordinatorImpl.main: " + e);
    }
    
   try {
        thisClient._chatBahn.register(thisClient.clientName, control);
	System.out.println("Registration Succeeded");
      } catch (jdceRMIBahnException e) {
	System.out.println(e.typeToString(e.getType()));
	System.out.println("Registration Failed");
      } catch (jdceRMIClientException e){}
        catch (RemoteException e) {System.out.println("Remote Exception"+ e.printStackTrace());}

 The Development Of Collaboration aware Code
In this context I choose the "HelloWorld"-equivalent of Collaboratory applications - CHAT. I intend to explore both the RMI and CORBA versions of this application, and as a proof-of-concept detail the collaboration involving RMI & IIOP Chat Clients. This Chat Application does not utilize IRC for communication, but employs the JDCE remote object sharing mechanism to achieve the same effect. The participants can log on to different interest groups and communicate within the group

CORBA-based Collaboration  The two files which are employed in building the demonstration Chat applets are
ChatUser.java
ClientControlImpl.java

RMI-based Collaboration  In this case the files involved are
RMIChatUser.java
RMIClientControlImpl.java


 The Retrofit Process
The Code below demonstrates the retrofitting of a single user application to a multi-user application. The applications that I have chosen is a TextEditing application. Of interest to us is the state/actions which need to shared. The single user application is hyperlinked here, and also provided is a listing of the GUI for the application. The screen dump of the application is available here