Developing Highly Distributed Applications with Jtrix

Jtrix is an open source Java platform for creating highly scalable,
distributed, and efficient Web services. This article describes Jtrix, compares it to other Java technologies, and illustrates how to write a Jtrix
application -- both a client, and the service it uses.
You can download Jtrix from the
Jtrix.org Web site or look it
up on Sourceforge.

What is Jtrix?

How can you write an application that is economical to run? To answer this question, you need several things. You cannot create everything yourself, so you'll
need to outsource some services: database, server farms, DNS server,
credit card authorization, etc. And of course, you should expect to pay for these services, so you and your service
providers need to measure usage accurately. If your application
is successful, you'll need to allocate more processing power and more
server space in various parts of the world. And you shouldn't have
to rewrite your application to cope with that.

Jtrix addresses these issues. It's about creating and using Web services
of any kind, and making applications distributed for reliability
and mobile so they can move to new locations.
Those roaming Jtrix programs are called netlets, and many netlets
will work together to provide a highly scaled, distributed service
or application. Each netlet will run on a node -- a Jtrix
runtime environment.

But Jtrix is also about making applications sensitive to resource usage and need. Applications should be able to grow and shrink as needed, so they don't cost a fortune to run before demand increases, or when it shrinks. In the Jtrix world, the same application will
cost 1,000 times less to run when there are 1,000 times
fewer users. If you ran a dot-com a few years ago, you'll appreciate the business need for such an architecture.

How Does Jtrix Compare to ...

Jtrix has been inspired by many technologies, most of them Java-based.
As befits a highly distributed system, Jtrix is very peer to peer.
But whereas JXTA is a P2P communications system, Jtrix doesn't
care how its communication works. A Jtrix application can use
JXTA if it likes, or it can use something else. We're actually
considering using JXTA in a couple of places; if it had been released
five months earlier, we might be using it already.

Another P2P touchstone is Gnutella. In fact, Gnutella would be
a good application for Jtrix, but this is only one possibility; Jtrix is
far more general and is intended for all kinds of Web services.

Jtrix's concept of accessing services is very close to Jini,
because when one netlet uses a service, it's provided by a second,
downloaded, netlet. That second netlet may be a simple proxy or carry
a lot of intelligence. But Jtrix is very strong on security, so neither
netlet can trust the other enough to let it run in its own class space.
The node ensures the two are separated from each other and itself.
So Jini is suited to a trusted Intranet environment, while Jtrix
is designed for the hostile world of the Internet.

Enterprise Java Beans are all about distributed systems, too.
The EJB concept of an application is very much the client/server,
three-tier architecture, whereas Jtrix applications are much more
P2P and don't enforce any heirarchy among netlets. Also, EJB
distributes objects, which again download into the client's class space;
Jtrix netlets are separated, as we've already said, and they are more
about delivering full services, not just single objects.

Actually, since EJB servers are much higher level than Jtrix,
an EJB server would be an excellent application to implement in Jtrix.
It would produce a very highly scalable and mobile application server
with all the high-level functionality of EJBs.

Jtrix Jargon

We've already met netlet and nodes. A netlet must
implement the INetlet interface. It is
described by an XML netlet descriptor, which tells
the node how to get the netlet's code, load it and initialize it.

We also know that any Jtrix application can provide or use a
service. A service connection is a two-way deal, and if
your netlet uses a service, then it must offer one in return, even if it has no function. The class NullService provides a do-nothing service for this purpose.

A service is accessed by means of a warrant, which is an
XML document. The warrant will have been issued by the service provider,
probably to you personally, so that when you use it they recognize
you. Then they can give you access to your "account" (your files, in the example of a data storage service), and bill you if needed.

To connect to a service, we say you bind to it. The node handles
all connection details. Once you've bound to a service, you can
access one of its facets, which is just any Java interface
it offers. Getting a facet is also called binding.

Any of these facet interfaces will implement the IRemote interface,
in much the same way that RMI has its Remote interface.
In Jtrix, all interfaces start with the letter I, just so we know what we're dealing with.

Hello, Jtrix World

Here's a "Hello, World" program in Jtrix. We're first
writing a client netlet which uses a Jtrix "Hello, World" service;
we'll write the service itself later.
The client takes a warrant, asks the node to bind the corresponding
service, binds the facet offered by the service (IHelloFacet),
and then gets the message contained within. This code and more is discussed
in the complete programmer's guide,
"How to Write Netlets."
All of the Jtrix JARs and tools needed are in the download bundle
on the site.

Now here's the netlet. Most of it is made up of trivial do-nothing implementations
of methods in the INetlet interface. The initialise()
method does all of the real work. (Note the British spelling!)
It binds to the service, gets the
facet, and uses it. It offers the NullService mentioned above
as its side of the two-way service connection.

To compile this, you need jtrix.jar and libjtrix.jar
on your classpath, and you can put both classes into hello1.jar.

However, this client netlet is useless without a "Hello, World" service. So let's write that next.

What is a Jtrix Service?

To recap, a Jtrix service is anything that offers features and
functionality to a netlet any time, anywhere. We'll get to
the "any time, anywhere" part in a moment, but first, here are some
examples of Jtrix services:

A "Hello, World" service. Provides a message to a netlet. We'll be
writing that here.

A hosting service. Provides a runtime environment for netlets and
an upload interface for remote access. Also
provides them with resources, such as disk space and networking.
By accessing several hosting services simultaneously you can ensure your
application is distributed and redundant.

A servlet engine service. Allows a consumer to upload a WAR file
of servlets and JSPs, and processes them as needed, returning HTML
pages.

A DNS service. Acts as a distributed DNS server and allows a consumer
to update their own DNS information, manage subdomains, etc.

An HTTP service. Listens for incoming HTTP requests and handles them
appropriately. It can use the servlet engine service to outsource JSP
requests. And it can use the DNS service, so it can update
the location of a site if one server fails and it starts a replacement
elsewhere.

In fact, all of these services have already been created, with the servlet service being a Jtrix wrapper around the Tomcat servlet engine. You can download them from the site.

The "any time, anywhere" part of a service is a central principle of Jtrix. Jtrix aims to provide services that are always available to anyone who has the rights to access them. It recognizes the fact that servers are never 100% reliable, so Jtrix services tend to be distributed and redundant.

What Makes Up a Service?

There are really only two necessary parts to a Jtrix service.
The first is a warrant -- an XML document that allows the
holder access to a service. The client netlet presents the warrant
to its node, which then puts it in touch with the service.

When the node is given a warrant
it downloads a new netlet, the access point netlet -- the second required part of a Jtrix service. The client netlet
talks to the access point netlet, which then fulfills the service, most likely by proxying requests back to a central server.

An access point netlet is a bit like an RMI stub, but there are key differences. For one thing, the access point netlet represents the entire service, not a single object. For another, it never runs in the same class space as the client code, thus ensuring security and version safety.

We might think that a server would be an essential part of
a Jtrix service, but this is not so. An access point netlet doesn't
have to proxy requests back to a server; it could deal with them
itself.

Possibilities For a "Hello, World" Service

Now we know what a service consists of, here are some ideas of how
we might construct a "Hello, World" service:

A single-server version. An access point proxies the getMessage()
call back to a central server, which provides the message and
is returned to the client. Of course, the server is a single point
of failure, so we would do better with...

A multi-server version. As above, but with many servers. More robust,
but manual intervention is required when one of the servers dies.
An improvement would be...

A self-distributing multi-server version. As before, but this time,
when a server dies, the other servers notice and restart a replacement.
Since the location of the servers change over time, each access point
needs to be updated with the latest list. And if all of this is too
complicated we could opt for...

A standalone access-point. The access point itself provides the
message. There are no servers and no proxying. Very simple, but of
course it doesn't make for a very managable system.

For the sake of simplicity, we'll implement the last option only.

Writing a Service

To implement our access point netlet, we first need to have the facet that provides the message. That's IHelloFacet, shown above.

Then the code of our access point netlet implements the INetlet
interface, just like the client. Here's the code, which we'll discuss later:

The first few methods are how this netlet communicates with the node. It doesn't do much, but initialization does save a reference to the node for the future.

We can see that the service comes out of the bindService() method,
which creates a new HelloService object, defined further on. Notice that it provides one facet to the client netlet, which
is called by the bindFacet() method.

This code is discussed in much more detail in the document
"How to Write Netlets." You should be
see, however, that writing a service in Jtrix is not necessarily
a difficult thing, at least when the service is simple. Also,
the service binding is a two-way connection (each provides an IService to
the other), which can be useful if the client needs to offer facilities to the service.

Preparing the Example

To compile the code, we need jtrix.jar on our classpath,
which contains all of org.jtrix.base. Then we can bundle all of the classes into a single JAR, which we'll call helloserver.jar. Make sure the JAR containsthe following: HelloServer.class, HelloServer$HelloFacet.class, HelloServer$HelloService.class, and IHelloFacet.class.

Next, we need to create a warrant, which every service needs. A warrant tells the node how to access the service by telling it about
the access point netlet. But first we need to create a netlet descriptor, which describes an access point netlet.
Our current directory contains the hello1.jar file from our client
code:

This warrant gives access to our service to any netlet
that holds it. If you examine the warrant, you'll see it's very large
because it actually contains all of the necessary JARs. In more realistic
examples, you can upload the JARs to a Web server and supply jtrixmaker
with their URLs. This makes warrants much easier to manage.

Now let's go back to our client netlet. That took a warrant as
a parameter and used it to connect to the service. Therefore we
need to create a descriptor for the client netlet and include this
warrant as a parameter. Here's how we do it, putting it in the file
hello1-client.xml:

We hit Control-C to stop the node, which would otherwise
carry on waiting for more service requests.
The jnode command starts a Jtrix node, and the integer that follows is just some arbitrary identifier. This helps when we run node clusters. The -netlet-stdioM option says that standard I/O from the netlets should be output, which is useful for debugging. Finally we name the netlet descriptor.

The output is from three sources, which don't appear in sync. We
get the node's output ("Bootstrap starting," etc.), the service netlet's
output (labelled 211.0.2) and the client netlet's output (labelled 211.0.1). This shows that the client netlet triggers the service and can then output the message. This is a complete Jtrix client and service!

Where to From Here?

We've seen just a little of what goes into a Jtrix client and service. There is much more we could talk about, such as proxying
and self-redundancy. Jtrix doesn't impose these things on developers,
nor does it even impose communication standards. It allows an
environment for secure distributed systems, and complete freedom: we
can use anything from SOAP to much lighter-weight protocols. It's up
to the application.

A self-redundant multi-server version of the "Hello, World" service
has been produced. It was written using a Jtrix framework
called Beatrix, which has also allowed us to write the HTTP server, servlet engine, and DNS that we mentioned originally. The self-redundant multi-server "Hello, World" service required us to write only seven classes within Beatrix.

Conclusion

This introduction has shown how to write a Jtrix client and server,
albeit briefly. For much more detail on Jtrix, see
http://www.jtrix.org
and in particular the document
"How to Write Netlets," from which this information is taken.
I hope this brief glimpse whets your appetite for developing high-availability, distributed systems with Jtrix.