The following are couple of simple tips, which have proven themselves very helpful in multiple cajo project developments.
Construction: After defining the public service interfaces, subclass cajo.sdk.AbstractService into MockService(s), providing simple/stub implementations of the methods. This will provide a fully demonstrable system, in literally minutes. Next, subclass the MockService(s) into ActualService(s), implementing functionality incrementally, with an eye toward always being able to demonstrate the system.
Testing: For a distributed system, more important than unit tests; develop test service objects, or scripts of functional test scenarios. An interactive scripting shell essentially creates a Command Line Interface (CLI) to the system, which is highly useful for integration testing.
Pass by value: When an object is passed into, or returned from a remote method invocation, it arrives by value, meaning an exact bitwise copy is created. Any changes to these objects have no affect on the original object instance. To enable this, the object class must implement the marker interface java.io.Serializable. This is the default behaviour because in most cases, this is precisely what is desired. It is important to remember this.
Note: this is the opposite of how objects are passed in Java all-local designs. (rather, this is the way C++ does it)
Pass by reference: To create a remote reference to an object, wrap it in a gnu.cajo.invoke.Remote object thus:
new Remote(object);This will cause all holders of the reference to manipulate the same object instance. Often this is precisely what is needed. (locally, this is the way Java does it)
Note: if this remote reference object is created uniquely for a client, also call the clientScope method thus:
new Remote(object).clientScope();This gives the remote reference only the lifetime needed by the client. Otherwise the reference will exist for the lifetime of the server. (i.e. server-scoped references are the default)
Collections of References: To pass or return a collection or array of references, it is recommended to use TransparentItemProxies, as they are serialisable, and can be used identically, both locally and remotely. It can be accomplished thus:
collection.add(TransparentItemProxy.proxy(object));This will add a TransparentItemProxy to the collection, implementing all of the supplied object's interfaces. If strong typing is not necessary, a collection of gnu.cajo.invoke.Remote objects can be used, in either client or server scope, as illustrated above.
Using Interfaces: Your applications will become increasingly flexible and powerful the more you use Interfaces, rather than Objects, for non-primitive arguments, and return types. All non-serialisable argument and return objects are transparently converted into TransparentItemProxy references, implementing all of the remote object's interfaces. (This is implicit client-scoped pass by reference)