TotSP HOWTO: Jini Programming in Java
Submitted by kebernet on Wed, 05/16/2001 - 15:00
Tagged:
It has been a while since we had a good TotSP
original tutorial up
here, so lets take a look at my lasted little
project: Working with
Jini from Sun.
Getting started with Jini
If you are like me, and used to be a big reader of Wired magazine, you might remember when Bill Joy at Sun first announced Jini. It was going to be the saviour of the world. You frigde could talk to your PC and all that. Well, it has not taken off as explosively as Bill might have hoped, maybe because the Embedded Java market is just getting traction, but it is still very cool. Jini includes severa technologies for distrubuted computing envrionments. The first and foremost is its IPMulticast service announcement and registry system. This is what we are going to play with today. This is a system by which RMI objects ( or really, any kind of remote service front end object ) can be passed out to the network and found by any other machine on the network. Here we are going to use vanilla RMI Remote Stubs, but they could be EJB Home Stubs, or anything else you want.Environment
All examples here are given on my RedHat 7.1. Some massaging may be in order. You need to get:- normal">JDK 1.3.0 ( linux version is available at HREF="http://www.blackdown.org/">http://www.blackdown.org )
- JINI 1.1 Development Kit
grant{
java.security.AllPermission;
}
Next, you're going to need a log dirctory
somewhere. I don't care,
just pick one.
Ok, lets
look at the
services needed to make this happen:
- HTTP Server to serve you jar filesWe are just going to use the one that comes with the Jini distro. This is for the dynamic executable downloads, but we aren't covering that here yet.
- rmidThis comes with the JDK distribution. It is a service for your computer that can automatically create instance of server objects when something requests it. We won't use this directly, but Reggie needs it.
- ReggieThis is the Jini lookup registrar. You can run all of these on your network you like, but you need at least one. This guy holds the serialized "Service" objects, and assigns unique service Ids on the network.
Starting up your environment:
- HTTP:java -jar $JINI_HOME/lib/tools.jar -port 8080 -dir $JINI_HOME/lib/ -trees \verbose
- rmid:rmid -log $YOUR_LOG_DIR/rmid -J-Djava.security.policy=all.policy
- Reggie:java -jar -Djava.security.policy=all.policy $JINI_HOME/lib/reggie.jar http://[Host Where HTTP Runs]/reggie-dl.jar all.policy $YOUR_LOG_DIR/reggie totsp -Dnet.jini.discovery.inderface=[IP Address of adapter to muticast]
Troubleshooting:
On some Linux distros, IPMulticast may be in the kernel, but not on. To turn it on use: "ifconfig eth0 multicast on; route add -net 224.0.0.0 netmask 224.0.0.0 eth0". Also, make sure the machine names for your box all resolve properly.Checking your config:
The Jini distro comes with a handy tool for browsing you Jini network. You can lauch it by running:java - cp .:$JINI_HOME/lib/jini-examples.jar -Djava.security.policy=all.policy -Djava.rmi.server.codebase=http://[HTTP_Host]/jini-examples-dl.jar com.sun.jini.example.browser.Browser -admin One this loads, select your Reggie host from the "registrar" drop down, and you should see a service registered as net.jini.core.lookup.ServiceRegistrar. If you don't, something went horribly, horribly wrong.Code:
Next, our code. We are going to put together an RMI server object, that will register itself with Reggie, and a client that can fetch the remote stubs and call our one business method. Remember in your project, you will need to make sure everything passed around over the wire implements java.io.Serlializable. There are some tricks to serialization, but you should see the tutorials at java.sun.com for more info on this. First, our interface. This is the interface we will use when working with the remote objects:import java.rmi.Remote;
import java.rmi.RemoteException;
public interface HelloWorld extends Remote {
public String helloWorld() throws RemoteException;
}
Nothing too complicated there. Next, lets look at
our server object:
import java.rmi.*;
import java.rmi.server.*;
import net.jini.lookup.*;
import net.jini.lookup.entry.*;
import net.jini.core.entry.*;
import net.jini.discovery.*;
import net.jini.core.lookup.*;
import net.jini.lease.*;
import java.util.Calendar;
public class HelloWorldImpl extends
UnicastRemoteObject implements HelloWorld,
ServiceIDListener {
/* This will control the maximum number of
instances of HelloWorldImpl to create. */
static final int MAX_INSTANCES = 3;
/* This is an array containing the names of the
Jini groups to register with. */
static final String [] GROUPS = {
"cooper" };
/* This is a reference to the remote stub for
this object */
RemoteObject remote = null;
LookupDiscoveryManager ldm = null;
JoinManager jm = null;
LeaseRenewalManager lrm = null;
protected JoinManager myJM = null;
/* The number of instances active */
static int count = 0;
/* this instance number */
int id = 0;
/* this instances Jini service id */
String serviceId = "";
public HelloWorldImpl() throws RemoteException {
count++;
this.id=count;
System.out.println("Instance created:
"+id );
//This sets up the name for this service in
the Jini registry
Entry[] attributes = new Entry[1];
attributes[0] = new
Name("HelloWorld");
//This is where we actually register with
the Jini registry
try{
ldm = new LookupDiscoveryManager( GROUPS,
null /* not using UnicastLocators */,
null /* not using
DiscoveryListener */ );
jm = new JoinManager( this,
attributes,
this /* for the ServiceIDListener */,
ldm,
lrm );
}
catch(Exception e){
e.printStackTrace();
System.exit(1);
}
}
/* This is own only "business logic"
method. */
public String helloWorld() throws RemoteException {
return "Hello from "+id;
}
public static void main( String[] args ){
try{
if(System.getSecurityManager() == null ){
System.setSecurityManager( new
RMISecurityManager() );
}
for( int i = 0; i < MAX_INSTANCES ; i++ ){
HelloWorld server = new HelloWorldImpl();
//This is optional. It just binds the
instance to a "normal" RMIRegistry
service as well.
//Naming.rebind("HelloWorld-"+server.id,
server);
}
System.out.println("main() done.");
}
catch(Exception e){
e.printStackTrace();
}
}
/* This is the mehod required by
ServiceIDListener. This is how Reggie tells up
what our JINI service ID is. */
public void serviceIDNotify(ServiceID serviceId) {
System.out.println("instance " +
id + " has been assigned service ID: " +
serviceId.toString());
this.serviceId = serviceId.toString();
}
}
This is just a standard RMI server object with a
couple of important
differences. First in the ServiceIDListener
interface. This is just
an event listener that the Jini APIs will use to
tell us what our
Jini Service ID is when it get registered. Second
is the stuff in the
constructor. Once again, I wont go into the
details, but this
represents how we bind our Remote stub to the Jini
registries. Pay
attention to the GROUPS array. You can bind a
single service to as
many groups as you want. These are just little
organizers for your
Jini network. If you have a lot of registries,
groups can keep you
from having to search every registrar for the
service you need in
your client application.
Ok, so now that you have this stuff,
you can compile
it. Also, you will need to compile the stub
implementation for the
HelloWorldImpl class, if you haven't done this
before, its easy, just
run: "rmic
-v1.2 HelloWorldImpl"
after you javac'd it. The v1.2 switch just tells
rmic to use the JDK
1.2+ RMI framework. It is cleaner in that it
doesn't require
skeletons and all that trash. Everything is
handled through
reflection for those needs. After you have run
rmic, you can start
your "HelloWorld" service by running
"java
-Djava.security.policy=all.policy
HelloWorldImpl". Check
the Jini Browser. You should now see three items
registered called
"HelloWorld". Wasn't that fun.
Finally, we need a client to call
our service. Here's
some source:
import net.jini.discovery.*;
import net.jini.core.lookup.*;
import java.io.IOException;
import java.rmi.RemoteException;
import javax.rmi.*;
import java.rmi.RMISecurityManager;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.MarshalledObject;
import net.jini.core.event.*;
import net.jini.core.lease.*;
import net.jini.lease.LeaseRenewalManager;
import net.jini.lookup.entry.Name;
import net.jini.core.entry.Entry;
/* Normally you would have a discovery listener
implemented separate from
your main run thread... */
public class HelloWorldClient implements
DiscoveryListener {
protected ServiceRegistrar[] registrars;
static final int MAX_MATCHES = 5;
public HelloWorldClient() throws RemoteException{
if (System.getSecurityManager() == null) {
System.setSecurityManager(new
RMISecurityManager());
}
LookupDiscovery discover = null;
try {
discover = new
LookupDiscovery(LookupDiscovery.NO_GROUPS);
discover.addDiscoveryListener(this);
String[] groups = { "cooper" };
discover.setGroups(groups);
} catch(IOException e) {
System.err.println(e.toString());
e.printStackTrace();
System.exit(1);
}
}
public synchronized void
discovered(DiscoveryEvent evt) {
registrars = evt.getRegistrars();
doLookupWork();
}
private void doLookupWork() {
String[] groups;
String msg = null;
if(registrars.length > 0){
msg = "";
System.out.println("------------------------------------------");
System.out.println("Registrar: "
+ registrars[0].getServiceID());
try {
groups = registrars[0].getGroups();
if (groups.length > 0)
for (int o=0; o
msg += groups[o] + " "; }
System.out.println("Groups
Supported: " + msg); }
catch (Exception e){
e.printStackTrace(); System.exit(1);
} Entry [] attributes = new
Entry[1]; attributes[0] = new
Name("HelloWorld");
ServiceTemplate st = new ServiceTemplate( null,
null, attributes ); for(int i = 0; i <
registrars.length; i++ ){ try{
//If you only want a single instance of the
service, you can use // Object object =
registrars[i].lookup( st ); //Without the
max matches. ServiceMatches sm =
registrars[i].lookup( st, MAX_MATCHES );
for( int j=0; j < sm.items.length; j++ ){
Object object = sm.items[j].service;
System.out.println( object );
HelloWorld helloWorld = (HelloWorld)
PortableRemoteObject.narrow( object,
HelloWorld.class ); System.out.println(
helloWorld.helloWorld() ); } }
catch(Exception ee){
System.out.println("in lookup");
ee.printStackTrace(); }
} }// of if length > 0
}
public void discarded(DiscoveryEvent evt) {
}
public static void main( String[] args ){
try{
HelloWorldClient thisClient = new
HelloWorldClient();
synchronized( thisClient ){
thisClient.wait(0);
}
}
catch(Exception e){
e.printStackTrace();
System.exit(1);
}
}
}
Now here, what we do, is find all instanced of our
HelloWorld
service- remember, we started three, and call the
helloWorld() method
on them, so they say hi to us. Notice the
ServiceTemplate we search
for. This can be used to match many many Entry's
for a particular
service, though we are only using name here. Also,
see the difference
between registrar.lookup() with and without a
"max_matches".
Without a max-matches, it just returns a
"service" object
for an available service.
Notice the time delay between taking
down your
HelloWorldImpl service and it being removed from
the Jini registry.
Your client code should generally test a service
object it gets back
and make sure its Ok. Additionally, you can use the
LeaseRenewalManager from your service to control
the time delay, but
remember, short leases mean network chatter.
Thats it for this episode. Check the
Jini site at
java.sun.com for API docs and some lame tutorials.
I also recommend
the redbook, Professional Jini
by Sing Li from Wrox. The guy is wordy, but the
book convers all the
stuff you need to know in a moderately digestable
order.
jini @ java.sun.com 






Recent comments
22 weeks 1 day ago
22 weeks 1 day ago
24 weeks 5 days ago
25 weeks 3 days ago
25 weeks 3 days ago
25 weeks 3 days ago
30 weeks 7 hours ago
30 weeks 1 day ago
30 weeks 4 days ago
30 weeks 6 days ago