the cajo project
Free, simple, powerful: Transparent Distributed Computing
Demonstrating the cajo framework's features and functions
The example package is a collection of four small classes demonstrating the use of the framework. It uses all the classes of the framework, except one, and that one will be described at the conclusion of the document, as well as why it was not part of the example.

Note: first exposure to this example, due to its use of so many library features; can be a little intense. It is highly recommended to review the short, tightly focused mini-examples, found at the project wiki first. (They were created as a result of developer feedback about the advanced nature of this example)

The four example classes are as follows:

TestItem An introductory server item
TestProxy An introductory server item proxy
Builder Configure and serialise the example proxy
Main To launch the example server application

A server need not use proxies; however, one is included in the example, for completeness of illustration.
Test Item
The TestItem class demonstrates the basic functionality of a server item. A server item has two primary components; a callable interface, and an optional processing thread. The processing thread, if defined, is launched automatically, following binding of the object with the ItemServer. A server item can also be purely event driven; i.e. only executing when its callable methods are being invoked; in this case it would not define a MainThread object. The callable interface to an item is simply its collection of publicly declared methods.

The thread in the example item performs the highly recommended practice of looping on its thread.isInterrupted() method. The item itself, or other parts of the application, can invoke a thread.interrupt() on the public thread member. This does not terminate the thread automatically, rather only flags it. This allows item's processing thread a mechanism to perform a safe and orderly shutdown. This is generally done when taking a server item offline. This technique has the added benefit that if the item's thread is waiting, it will wake it up, via the throwing of an InterruptedException

Since this is only an example item implementation, the main processing thread has basically nothing to do. So it simply puts itself to sleep, to be awoken should something interesting happen. When awoken, it sleeps for 500 milliseconds, to appear that it is doing something. Following that, it invokes the method "callback" on an item reference it gets from somewhere, (actually one of its own methods, described next) passing a string argument, and displaying the result. It then loops back up into sleep. That's all it does, until interrupted, if ever.

The interesting part happens in its public callback method. It is appropriately named, though it actually could be named anything. When it is invoked, it saves the reference to the presumably remote calling item, and wakes its main thread, to operate as described in the previous paragraph. It then prints the message provided by the invoking item, and returns a string indicating synchronous acknowlegement. Again, the critical point is; every public method an item declares will be invokable from remote items, no differently than if it was being interfaced by local objects. Note: this implementation also intentionally illustrates the importance of reentrancy consideration with regard to an item's public interface. If many items invoke this method simultaneously, only the last caller will get called back by the item's main thread. Making the example's callback method threadsafe is left as an excercise for the reader.

Lastly, the item implements the toString method, inherited from Object. This is also a highly recommended practice. In this case, it is used when monitoring the item, which is covered in the upcoming section on Main, and also greatly aids in debugging. Being public, note that the method is also remotely callable, to identify the object at the other end of the remote reference.
Test Proxy
The TestProxy class is a small proxy item illustrating many features of the framework. It is sent to a client, as the return from the TestItem's getProxy method, inherited from BaseItem. The proxy automatically inherits a remote reference to the TestItem. On arrival at the client, it is initialised (by the client) with the assignment of its remoteThis member with a reference to the proxy itself, remoted the context of the client VM. This initialisation, will cause the proxy's main thread to start, if it has one. As with server items; a proxy need not define a main thread, i.e. it can also be purely event driven.

The example also demonstrates the Internationalisation feature of proxies. When the proxy is initialised, it will load its string table, if defined, from a properties file, most closely matching the locale of the receiving VM. This allows the proxy's user interface to be in German on an Austrian machine, and Spanish on a Mexican one, for example. Of course, all of these translated string tables must be included. The properties file, and all other non-class resources are generally placed in a support directory. In this case it is called include. The reason for the separate directory, is to simplify the proxy's jar creation, as the build script can then include all the files in the directory blindly (i.e. *.*).

Since this is a graphical proxy example, it's initialisation invocation also returns a non-null graphical component that the client can display on its monitor. The purpose of the component is to provide a graphical user interface to a remote server item.

When the proxy's processing thread starts, it writes out an arrival notice to the client's user interface. Next, it invokes the method named callback on the reference to its server item. It passes its remote reference to itself, and a message string. It displays the value returned by the invocation as well. Following that, it exits its run method, causing its main processing thread to terminate.

The proxy has a public method named callback. When called, in this case by the TestProxy, it will display the incoming text argument, and return a synchronous text acknowlegement of its own. Just as with server items; all of a proxy's public methods can be called by remote items, or proxies, having a reference to the proxy.
Builder
The Builder class serves two purposes:

First it serves to replace all the code which would otherwise go into the proxy's constructor. Why do this? Because all of the construction code, which can be quite sizeable if the proxy is elaborate, can be left out of the proxy's jar file. This reduces the proxy jar size, and also adds the additional security that the proxy becomes much more difficult to reverse-engineer, if such protection is important to you.

Note: while the builder technique works very well for AWT user interfaces, due to security restrictions; many Swing components cannot be deserialised in an Applet/WebStart sandbox. The code must then move back into the proxy constuctor. An example of this approach can be found here.

The second function of the Builder class is to instantiate the proxy, then serialise its image to disc. This serialised object will be included in the proxy jar file, and referenced through a ProxyLoader in the TestItem's runtime. This is the most elaborate way to use a ProxyLoader. It can also be used to invoke a proxy's no-arg constructor, to create a new instance of the proxy, on its arrival at the host VM. In that case, all of the construction code would have to be passed to the client VM. Use of a ProxyLoader is optional, but it is a highly recommended optimisation, as it prevents having to load proxies into the server JVM runtime.

The actual mechanics of what is going on inside the builder is not so important. It is basically configuring graphical components, and putting them into the graphical user interface member object container. The proxy will return this graphical container to the hosting client as a result of its initialisation invocation. It also defines the keys of the string table, also loaded during initialisation. It references a ProxyLoader, this is a special requirement. The proxy will need to use the ProxyLoader class file on its arrival at the host, however, it doesn't need to use one at compile time. Without this apparently unused reference, the proxy would suffer a ClassNotFoundException at the host, as ProxyLoader class would not be in the proxy jar file, as it would have not been compiled.
Main
The Main class illustrates how to make a server application. A server is simply an application which makes one or more items available for remote invocation. The Main class first configures its network settings, then makes the test item accessible. As explained in the launching turorial, the application can take up to five parameters, in order, from most likely to need changing, to least likely, and where order and precedence matters. The network configuration parameters are as follows:
  • the port number on which to serve the proxy's codebase
    (default = 80)
  • the port number on which to communicate with the item
    (default = 1099)
  • the external server name or address, if using NAT
    (default = same as local)
  • the local host network interface, if multiple
    (default = all interfaces)
  • the outside port number to communicate with the item
    (default = same as local)
The server also does a few additional actions, to illustrate the operation of remaining parts of the framework. It multicasts a remote reference to itself to announce its startup. It uses a MonitorItem, to log data about the remote invocations to its item to the system console. It even listens for other item announcements; sending the announcers a remote reference the test proxy, invoked on their setProxy method, if they have one. Finally it finishes up by listing its configuration information. This can be useful if the server is told to use any anonymous TCP ports (i.e. port = 0), the info will contain the actual port numbers chosen by the operating system at startup.
Conclusion
The example illustrates a very common paradigm of the cajo framework:
String -> remote reference -> local proxy -> GUI
1. A URL defines a remote object reference; either at another server, or serialised to disc.

2. The URL is deserialised into the local runtime, as a reference to the remote object.

3. A local proxy object is requested from the remote reference.

4. A GUI is requested from the proxy, to be the View, to its Controller functionality.

This allows the provision of sophisticated visual modules, which can further be composed to yield even richer functionality. The components are neatly modularised by server. A single server may serve multiple graphical interfaces. These interfaces can also be viewed with an ordinary web browser, or via Web Start.

Note: The ZippedProxy class is the only utility class not used in the example. This is bacause the example demonstrates indirectly referencing a proxy, through a ProxyLoader. This is preferred when the server item does not need to configure a proxy before sending it. This can save a lot of space in the server item's runtime, especially if the proxy is very large, or if a single VM is serving many proxies.

In cases, when a proxy must be loaded into the server's VM; presumably for some runtime dependent configuration, it is highly recommended to use a ZippedProxy. It compresses the serialised image of the proxy as it is sent to the hosting VM. This is done to reduce the amount of data, and transmission time, required to send the proxy. If the proxy image is large, the network uplink is slow, or the cost per byte sent is high, this technique makes tremendous sense. Its use is recommended for all proxies loaded into the server, as a general paradigm.


Once you understand the basics; the advances begin to emerge.
© 2004 John Catherino, GNU FDL