blob: ce9b0f1ed52ad432e2a4dc2851f0a49ebbeeaf7c [file] [log] [blame] [view]
Title: Getting Started With River
license: https://www.apache.org/licenses/LICENSE-2.0
### Getting Started With River
This document is going to explain how you can use the in-built "simple" services that come with River. More specifically:
- a Lookup Service, the "reggie" implementation
- a JavaSpace, the "outrigger" implementation
- a Transaction Service, the "mahalo" implementation
The instructions assume that you're building from source as checked out from the SVN trunk. Currently this is
necessary because the code snippets below use methods and classes which, at time of writing, haven't made it into
the latest binary release yet. Having said that, the code you will need in the binary release isn't to far removed
from what you'll see below, so you can progress with the binary release if you want to and are happy odifying the code.
If you are going to use the latest release then you will still need to download (from the SVN trunk) some of the
Windows BAT files mentioned below. *nix sh scripts of those same batch files will appear shortly.
<div class="panel panel-default">
<div class="panel-heading">Environment Setup</div>
<div class="panel-body">
The following instructions all assume that you have checked out River to some directory which is throughout referred
to as `$RIVER_HOME`. Further, you have changed directory into `$RIVER_HOME/examples/hello`.
<div class="alert alert-info">
Run all scripts from the `hello` directory
</div>
- Change directory to $RIVER_HOME
- Use Ant to build River, i.e. `ant all.build`
#### Running Code Which Uses River Services
Since River uses dynamic code downloading, we need to grant various permissions to our JVM to allow that. In the
interest of simplicity, we are going to grant everything every permission. In the real world, this would obviously
not be recommended.
To grant these permissions we need to create a policy file:
grant {
permission java.security.AllPermission;
};
Create the above file and save it somewhere that it can be easily referenced as a command line argument to some Java
you're going to write - such as the working directory that you will run the code from.
Further, your programs which will use River services will need the following JVM arguments.
-Djava.security.policy=path/to/policy.all
-Djava.rmi.server.RMIClassLoaderSpi=net.jini.loader.pref.PreferredClassProvider
Also, before doing anything with any River code you need to set an appropriate security manager. This needs to be
done only once per program.
System.setSecurityManager(new RMISecurityManager());
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">Starting the HTTP server</div>
<div class="panel-body">
#### What? Wait, why do I need to do that?
When services get marshalled for sending over the wire, the first part of their stream is the codebase URL. This URL
tells the downloading JVM where to load the supporting JARs from. Often (although not always) in the River/Jini world
this code base harks back to some HTTP server. There is a simple HTPP server packaged inside River which can be used
for this. That's what we're going to start.
See [3.2 How codebase is used in Java RMI](http://download.oracle.com/javase/1.5.0/docs/guide/rmi/codebase.html) for
more details.
<div class="alert alert-info">
- Change to directory to `$RIVER_HOME/examples/hello/` <br/>
- Execute the script; `scripts/httpd.bat` <br/>
</div>
#### Testing it
To test that the HTTP server is running correctly use wget or your web browser on the following URL
- http://localhost:8080/reggie-dl.jar
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">Starting a Service Registrar (Lookup Service)</div>
<div class="panel-body">
##### What? Wait, why do I need to do that?
Typically, in an environment which uses River/Jini services, a Lookup Service will be used. This Lookup Service is
then used by your code to find River/Jini services. Lookup Services always know the current state of the subnet or
federated space.
Broadly speaking (although not 100% accurately) you need a Lookup Service in order to be able to find other services to use.
<div class="alert alert-info">
- Change to directory to `$RIVER_HOME/examples/hello/` <br/>
- Execute the script; `scripts/jrmp-reggie.bat` <br/>
</div>
##### Testing it
There are two ways to find our Lookup Service. Remember that the interface which fulfills the role of a Lookup Service
is `ServiceRegistrar`.
##### Unicast
If we know where our Lookup Service is running, we can use unicast to connect straight to it.
:::java
LookupLocator ll = new LookupLocator("jini://localhost:4160");
StreamServiceRegistrar sr = ll.getStreamRegistrar();
System.out.println("Service Registrar: " + sr.getServiceID());
Assuming you don't get a `NullPointerException` and you do get a service ID written out, then your Lookup Service is
running fine.
The `LookupLocator` takes a String representing a "jini URL". This jini URL is made up from the Strings "`jini://`" a
hostname and (optionally) "`:`" and a port number. 4160 is the default port and is specified in the Lookup Service
configuration file. The scripts in the {{examples/hello}} directory will use the default port unless you have changed
it. See [DJ.5.5 Address and Port Mappings for TCP and Multicast UDP](/release-doc/2.2.3/specs/html/discovery-spec.html)
for more details.
##### Multicast
If we know only that "some lookup services are on the subnet somewhere" then we can use multicast to find them.
DiscoveryListenerManagement dlm = new LookupDiscovery(LookupDiscovery.ALL_GROUPS);
LeaseRenewalManager lrm = new LeaseRenewalManager();
ServiceDiscoveryManager sdm = new ServiceDiscoveryManager(dlm, lrm);
Thread.sleep(500); //need to wait a little bit for the Lookup Service to generate the events to the sdm
ServiceTemplate srTemplate = new ServiceTemplate(null, new Class[] { ServiceRegistrar.class }, null);
ServiceItem[] sis = sdm.lookup(srTemplate, 10, null);
for (ServiceItem si : sis) {
System.out.println("Service Registrar: "+si.serviceID);
}
dlm.terminate();
This approach is slightly different. It is relying the `ServiceDiscoveryManager` to listen to the UDP multicast
packets announcing the presence of a Lookup Service. The same rules apply as for unicast on deciding whether or
not your Lookup Service is running.
This approach can be modified if you know which hosts on the subnet _might_ be running lookup services. You can
define and pass this list to the `LookupDiscovery` constructor.
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">Starting a Java Space</div>
<div class="panel-body">
##### What? Wait, why do I need to do that?
Finding a Lookup Service is only useful if there are some other services on the network which you want to use, so
now we're going to start a Java Space, and find that. Using the Java Space is outside the scope of this document,
although the "how" is relatively straightforward.
<div class="alert alert-info">
- Change to directory to `$RIVER_HOME/examples/hello/` <br/>
- Execute the script; `scripts/jrmp-outrigger-group` <br/>
</div>
##### Testing it
To find any kind of service we must first create a template.
This is an instance of `ServiceTemplate` which describes the kind of thing we're
looking for.
As the Jini specification says, nulls and empty arrays as wildcard characters for
"any value".
So the following code is a template which will match any service which implements the `JavaSpace` interface regardless of the rest of it's characteristics.
ServiceTemplate template = new ServiceTemplate(null, new Class[) { JavaSpace.class }, new Entry[0]());
Using the unicast and a `ServiceRegistrar` we find the Java Space like this;
ServiceMatches sms = sr.lookup(template, 10);
if (0 < sms.items.length) {
JavaSpace space = (JavaSpace) sms.items[0].service;
// do something with the space
}
else {
System.out.println("No Java Space found.");
}
Using the `ServiceDiscoveryManager` is similar;
ServiceItem si = sdm.lookup(template, null);
if (null != si) {
JavaSpace space = (JavaSpace) sms.service;
// do something with the space
}
else {
System.out.println("No Java Space found.");
}
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">Starting a Transaction Service</div>
<div class="panel-body">
##### What? Wait, why do I need to do that?
Because you'd like to find something that will give you a nice distributed transaction.
<div class="alert alert-info">
- Change to directory to `$RIVER_HOME/examples/hello/` <br/>
- Execute the script; `scripts/jrmp-mahalo-group` <br/>
</div>
##### Testing it
Testing it is done in the same way as for the Java Space. However, the constructor of the `ServiceTemplate` changes.
ServiceTemplate template = new ServiceTemplate(null, new Class[) { TransactionManager.class }, new Entry[0](0.html));
</div>
</div>