The aim of this tutorial is to take the IBookstore interface created in the first tutorial and publishing it to a server. The bookstore interface is:
public interface IBookstore
{
public boolean addBook(Book book);
public void removeBook(String isbn)
throws BookNotFoundException;
public Book[] findBooksByAuthor(String name);
public Book getBookByIsbn(String isbn)
throws BookNotFoundException;
public Book[] getAllBooks();
public void loadBooks( String filename )
throws IOException, TypeException;
public void saveBooks( String filename )
throws IOException, TypeException;
}
This interface has various data types that would not normally be easily moved between cliet and servers in a heterogenous environment. However, in the Argot tutorial we have already defined a Book and a Book[] (array) in Argot. This same code will be used by Colony to marshall the data between servers.
An important aspect of Colony and its use of Argot is that the client and server must match on their data type. If you were to modify the structure of a Book object as defined by Argot on the server without modifying the client, the Colony system will report an error. This data type agreement ensures only valid data is transfered between systems.
The above interface includes a new data type not yet modelled in Argot. The BookNotFoundException is added to our Argot bookstore dictionary. It is defined using the remote.exception.basic type which provides full server stack traces to the client. It's definition is:
bookNotFound: {
@remote.exception.basic["exception"]
};
remote.exception#bookNotFound:
meta.map( #remote.exception, #bookNotFound );
The second argot type is used to map the bookNotFoundException type to the abstract data type remote.exception. This is a powerful concept of Argot, which allows previously defined concepts to be extended. In this case the type is mapped to the network virtual machine's exception type.
The code for marshalling the exception has been added to the exception. It is similar to the code introduced in the Argot tutorial. The IOException and TypeException exceptions have not been mapped to Argot. This can be accomplished in the same was as above and has been left as an excercise for the reader.
Having created the missing Argot data types we are ready to publish the interface. No modifications to the Bookstore class or interface is required. This has been a design goal of the Colony system from the start.
To provide tight binding between the client and the server the interfaces are described in Argot.
bookstore: remote.interface();
bookstore.addbook: remote.method( #bookstore, "addBook",
[ remote.parameter( #book, "book" ) ],
[ remote.parameter( #bool, "success" ) ],
[ #bookNotFound ]
);
bookstore.removebook: remote.method( #bookstore, "removeBook",
[ remote.parameter( #u8ascii, "isbn" ) ],
[ ],
[ #bookNotFound ]
);
bookstore.findBooksByAuthor: remote.method( #bookstore, "findBooksByAuthor",
[ remote.parameter( #u8ascii, "name" ) ],
[ remote.parameter( #booklist, "booklist" ) ],
[ ]
);
bookstore.getBookByIsbn: remote.method( #bookstore, "getBookByIsbn",
[ remote.parameter( #u8ascii, "isbn" ) ],
[ remote.parameter( #book, "book" ) ],
[ #bookNotFound ]
);
bookstore.getAllBooks: remote.method( #bookstore, "getAllBooks",
[ ],
[ remote.parameter( #booklist, "allbooks" ) ],
[ ]
);
bookstore.loadbooks: remote.method( #bookstore, "loadBooks",
[ remote.parameter( #u8ascii, "filename" ) ],
[ ],
[ #bookNotFound ]
);
bookstore.saveBooks: remote.method( #bookstore, "saveBooks",
[ remote.parameter( #u8ascii, "filename" ) ],
[ ],
[ #bookNotFound ]
);
Each method is defined separately in Argot. This allows new methods to be added or old ones to be removed. A client performs a strong binding on individual methods, allowing for more flexability over time.
To build the server the Colony environment must be configured. The Colony environment is the glue that holds the various components of Colony together. It consists of a Container where we publish object, a Network virtual machine enviornment and communication links.
The first step is to configure the container. Colony allows different types of containers to be used. In this case the SystemRealm is an in memory container that uses a URL naming scheme.
// Configure container
TypeLibrary serverLibrary = configTypeLibrary();
SystemRealm realm = new SystemRealm("localhost");
RealmContainer serverContainer = new RealmContainer(realm);
The next is to create the ColonyEnvironment. The environment needs access to the container and the TypeSystemLibrary. The server connectivity is then added to the base ColonyEnvironment. In this case we are using a Socket as the transport layer and the NvmServer as the RPC communications sub-system. The NvmServer provides a Network Virtual Machine which is used to execute tasks between servers.
// Configure server
_server = new ColonyEnvironment(serverContainer,serverLibrary);
_socketServer = new SocketServer(SystemThreadPool.getThreadPool(),
new ServerSocket(500));
_socketServer.connect();
_server.addServer("nvm",
new NvmServer(
new CRL("crl://local/hostServer"),
_socketServer, null
));
Now that the environment is configured, we are ready to create the bookstore and add it to the Container. It will be published using the Colony Resource Locator as crl://host/bookstore
// Add bookstore.
_server.addObject(new CRL("crl://local/test"),
IBookstore.TYPENAME, new Bookstore(serverLibrary));
The server is now configured and the bookstore is ready to be accessed from a client. The client configuration is similar to the server.
The client also creates a ColonyEnvironment. In this case it uses a SimpleContainer. The SimpleContainer can be used to provide an index based locations. The NvmClient and SocketClient is connected on the client.
SimpleContainer clientContainer = new SimpleContainer( _library );
_client = new ColonyEnvironment(clientContainer,_library);
SocketClient pipeClient = new SocketClient(_host,500);
_client.addClient("localhost",
new NvmClient( pipeClient, null, null ));
A client is able to retrieve an interface to the server by calling the getFront method of the environment. The location must be a recognised location of the server.
_client.getFront(location);
The client and servers are both configured. It is possible to have a system act as both a client and server to other systems. This allows for concepts such as the Network Virtual Machine(VM) to move between multiple servers during a single request.
The Network VM instructions are defined using Colony. The nvm.instruction is an abstract data type. This allows users to extend and customise the Network VM to perform specific actions and instructions that we have not defined.
To test the bookstore, simply run ServerBookstore on one machine, then run ClientBookstore on the same machine, or another machine. The ClientBookstore requires the CRL as its argument. eg. ClientBookstore crl://localhost/bookstore
The Colony documentation is currently being developed. To start using Colony it is best to analyse the bookstore example provided and test cases supplied.
