|
 |
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.
|
|
 |
|
 |
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.
|
 |
|
 |
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.
|
 |
|
 |
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.
|
 |
|
 |
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.
|
 |
|
 |
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.
|
|