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.
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.
All
examples here are given
on my RedHat 7.1. Some massaging may be in order.
You need to get:
I just
installed each of
these in /opt on my box.
Next, you
are going to need
to create a Java Security Policy file. I won't go
into detail about
how this works ( check the Java Security book from
O'Reilly ), but
you need this written out to a file ( all.policy
):
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:
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
Chatter
1 day 2 hours ago
1 day 3 hours ago
1 day 13 hours ago
1 day 17 hours ago
2 days 8 hours ago
4 days 2 hours ago
4 days 17 hours ago
1 week 10 hours ago
1 week 1 day ago
3 weeks 1 day ago