The Artima Developer Community
Sponsored Link

Jini Seminar
Jini's Runtime Infrastructure
Lecture Handout

Agenda


Jini is the Glue


The Runtime Infrastructure


Groups


Discovery, Join, Lookup


Discovery - Multicast Request Protocol


Discovery - Multicast Request Protocol


Discovery - Unicast Discovery Protocol


Discovery - The Unicast Discovery Protocol


Discovery - The Multicast Announcement Protocol


Discovery - The Multicast Announcement Protocol


A Discovery Example


Lookup Service Ping

 1 import net.jini.core.discovery.LookupLocator;
 2 import net.jini.core.lookup.ServiceRegistrar;
 3 import net.jini.core.lookup.ServiceID;
 4
 5 import java.io.*;
 6 import java.rmi.*;
 7 import java.rmi.server.*;
 8 import java.util.StringTokenizer;
 9
10 public class LSP
11 {
12     public static void main (String[] args) {
13
14         if (args.length == 0) {
15             System.out.println("LSP requires a lookup service URL as first arg.");
16             System.out.println("Example: \"LSP jini://localhost:2000\"");
17             System.exit(0);
18         }
19
20         String urlString = args[0];
21
22         try {
23             System.setSecurityManager (new RMISecurityManager());
24
25             // Instantiate a LookupLocator object set to perform
26             // unicast discovery on the lookup service indicated
27             // by the passed in host and port number. (If no port number
28             // is specified, the default port of 4160 will be used.)
29             LookupLocator lookupLocator = new LookupLocator(urlString);
30             String host = lookupLocator.getHost();
31             int port = lookupLocator.getPort();
32
33             System.out.println("Lookup Service: jini://" + host + ":" + port);
34
35             // Invoke getRegistrar() on the LookupLocator to cause it to
36             // perform unicast discovery on the lookup service indicated
37             // by the host and port number passed to the constructor.
38             // The result is a reference to the registar object sent from
39             // the lookup service.
40             ServiceRegistrar registrar = lookupLocator.getRegistrar();
41
42             // A lookup service is, after all, a service -- a service
43             // so proud of itself that it registers itself with itself. To
44             // get the ID it assigns to itself, call getServicerID() on
45             // the registrar object.
46             ServiceID id = registrar.getServiceID();
47
48             System.out.println ("Lookup Service ID: " + id.toString());
49         }
50         catch (Exception e) {
51               System.out.println("LSP Exception:" + e);
52         }
53     }
54 }

$ java -Djava.security.policy="policy.all" LSP jini://localhost

Lookup Service: jini://localhost:4160
Lookup Service ID: a1366531-5805-4f2e-8b40-e6b9b36f78fb

Lookup Service Find

 1 import net.jini.discovery.LookupDiscovery;
 2 import net.jini.core.discovery.LookupLocator;
 3 import net.jini.discovery.DiscoveryListener;
 4 import net.jini.discovery.DiscoveryEvent;
 5 import net.jini.core.lookup.ServiceRegistrar;
 6 import net.jini.core.lookup.ServiceID;
 7
 8 import java.io.*;
 9 import java.rmi.*;
10 import java.rmi.server.*;
11 import java.util.StringTokenizer;
12
13 // Lookup Service Find - Does discovery to find the nearby lookup
14 // services and prints out a list
15 public class LSF implements DiscoveryListener
16 {
17     public static void main (String[] args) {
18
19         try {
20             System.setSecurityManager (new RMISecurityManager());
21
22             LookupDiscovery ld = new LookupDiscovery(LookupDiscovery.NO_GROUPS);
23             ld.addDiscoveryListener(new LSF());
24             ld.setGroups(LookupDiscovery.ALL_GROUPS);
25
26             Thread.currentThread().sleep(1000000000L);
27         }
28         catch (Exception e) {
29               System.out.println("LSF Exception:" + e);
30         }
31     }
32
33     public void discovered(DiscoveryEvent de) {
34
35         try {
36             // Invoke getRegistrar() on the LookupLocator to cause it to
37             // perform unicast discovery on the lookup service indicated
38             // by the host and port number passed to the constructor.
39             // The result is a reference to the registar object sent from
40             // the lookup service.
41             ServiceRegistrar[] registrars = de.getRegistrars();
42
43             for (int i = 0; i < registrars.length; ++i) {
44                 // A lookup service is, after all, a service -- a service
45                 // so proud of itself that it registers itself with itself. To
46                 // get the ID it assigns to itself, call getServicerID() on
47                 // the registrar object.
48                 ServiceID id = registrars[i].getServiceID();
49
50                 LookupLocator lookupLocator = registrars[i].getLocator();
51                 String host = lookupLocator.getHost();
52                 int port = lookupLocator.getPort();
53
54                 System.out.println("Lookup Service: jini://" + host + ":"
55                     + port + ", " + id.toString());
56             }
57         }
58         catch (Exception e) {
59               System.out.println("LSF Exception:" + e);
60         }
61     }
62
63     public void discarded(DiscoveryEvent de) {
64     }
65 }


$ java -Djava.security.policy="policy.all" LSF

Lookup Service: jini://bvenners:4160, a1366531-5805-4f2e-8b40-e6b9b36f78fb


Join


The ServiceItem


A ServiceItem Diagram


The Join Process


The SummerService

 1 import net.jini.core.discovery.LookupLocator;
 2 import net.jini.core.lookup.ServiceRegistrar;
 3 import net.jini.core.lookup.ServiceID;
 4 import net.jini.core.lookup.ServiceTemplate;
 5 import net.jini.core.lookup.ServiceMatches;
 6 import net.jini.core.lookup.ServiceItem;
 7 import com.sun.jini.lookup.JoinManager;
 8 import com.sun.jini.lookup.ServiceIDListener;
 9 import net.jini.core.entry.Entry;
10 import net.jini.lookup.entry.Name;
11 import com.sun.jini.lease.LeaseRenewalManager;
12
13 import java.io.*;
14 import java.rmi.*;
15 import java.rmi.server.*;
16 import java.util.StringTokenizer;
17
18 public class SummerService extends UnicastRemoteObject
19     implements Summer, ServiceIDListener, Serializable
20 {
21     public SummerService() throws RemoteException {
22         super ();
23     }
24
25     public long sumString(String s) throws InvalidLongException,
26         RemoteException {
27
28         System.out.println("sumString(\"" + s + "\")");
29         long sum = 0;
30         StringTokenizer st = new StringTokenizer(s);
31         String token;
32         while (st.hasMoreTokens()) {
33             token = st.nextToken();
34             try {
35                 sum += Long.parseLong(token);
36             }
37             catch (NumberFormatException e) {
38                 throw new InvalidLongException(
39                     "Invalid number: " + token);
40             }
41         }
42
43         return sum;
44     }
45
46     public void serviceIDNotify (ServiceID idIn) {
47     }
48
49     public static void main (String[] args) {
50
51         try {
52             System.setSecurityManager(new RMISecurityManager());
53
54             Entry[] attributes = new Entry[1];
55             attributes[0] = new Name("SummerService");
56
57             SummerService summerService = new SummerService();
58
59             JoinManager joinManager = new JoinManager(summerService,
60                 attributes, summerService, new LeaseRenewalManager());
61         }
62         catch (Exception e) {
63             System.out.println("SummerService Exception:" + e);
64         }
65     }
66 }


$ java -Djava.security.policy=/sun/jini/bv/policy.all
    -Djava.rmi.server.codebase=http://localhost:8080/ SummerService




1 import java.rmi.*;
2
3 public interface Summer extends Remote {
4
5     long sumString(String s)
6         throws InvalidLongException,
7         RemoteException;
8 }


 1 public class InvalidLongException
 2     extends Exception {
 3
 4     private String message;
 5     InvalidLongException(String s) {
 6         message = s;
 7     }
 8     public String getMessage() {
 9         return message;
10     }
11 }

The Lookup Process


Lookup Service Directory

 1 import net.jini.core.discovery.LookupLocator;
 2 import net.jini.core.lookup.ServiceRegistrar;
 3 import net.jini.core.lookup.ServiceID;
 4 import net.jini.core.lookup.ServiceTemplate;
 5 import net.jini.core.lookup.ServiceMatches;
 6 import net.jini.core.lookup.ServiceItem;
 7
 8 import java.io.*;
 9 import java.rmi.*;
10 import java.rmi.server.*;
11 import java.util.StringTokenizer;
12
13 public class LSD
14 {
15     public static void main (String[] args) {
16
17         if (args.length == 0) {
18             System.out.println("LSP requires a lookup service URL as first arg.");
19             System.out.println("Example: \"LSP jini://localhost:2000\"");
20             System.exit(0);
21         }
22
23         String urlString = args[0];
24
25         try {
26             System.setSecurityManager (new RMISecurityManager());
27
28             // Instantiate a LookupLocator object set to perform
29             // unicast discovery on the lookup service indicated
30             // by the passed in host and port number. (If no port number
31             // is specified, the default port of 4160 will be used.)
32             LookupLocator lookupLocator = new LookupLocator(urlString);
33             String host = lookupLocator.getHost();
34             int port = lookupLocator.getPort();
35
36             System.out.println();
37             System.out.println("Lookup Service: jini://" + host + ":" + port);
38
39             // Invoke getRegistrar() on the LookupLocator to cause it to
40             // perform unicast discovery on the lookup service indicated
41             // by the host and port number passed to the constructor.
42             // The result is a reference to the registar object sent from
43             // the lookup service.
44             ServiceRegistrar registrar = lookupLocator.getRegistrar();
45
46             // Create a ServiceTemplate object that will match all the
47             // services in the lookup service.
48             ServiceTemplate serviceTemplate = new ServiceTemplate(null, null,
49                 null);
50
51             // Do the lookup. This is bad LSD in a way, because it will
52             // only report at most 1000 services in the lookup service.
53             ServiceMatches matches = registrar.lookup(serviceTemplate, 1000);
54
55             System.out.println("Total Services: " + matches.totalMatches);
56             System.out.println();
57             for (int i = 0; i < matches.totalMatches; ++i) {
58
59                 ServiceItem item = matches.items[i];
60                 String typeName = item.service.getClass().getName();
61                 String idString = item.serviceID.toString();
62
63                 System.out.println(typeName + ": " + idString);
64             }
65             System.out.println();
66         }
67         catch (Exception e) {
68               System.out.println("LSD Exception: " + e);
69         }
70     }
71 }


$ java -Djava.security.policy="policy.all" LSD jini://localhost

Lookup Service: jini://localhost:4160
Total Services: 2

SummerService_Stub: f6731f98-9bf2-4434-814f-fee57deadaf4
com.sun.jini.reggie.RegistrarProxy: a1366531-5805-4f2e-8b40-e6b9b36f78fb


Using a Service


The SummerClient

 1 import net.jini.entry.*;
 2 import net.jini.core.lookup.*;
 3 import net.jini.core.entry.*;
 4 import net.jini.lookup.entry.*;
 5 import net.jini.core.discovery.*;
 6 import java.rmi.*;
 7 import java.io.*;
 8
 9 class SummerClient
10 {
11     public static void main (String[] args) {
12
13
14         try {
15             System.setSecurityManager (new RMISecurityManager ());
16
17             // Perform unicast lookup on localhost
18             LookupLocator lookup = new LookupLocator("jini://localhost");
19
20             // Get the service registrar object for the lookup service
21             ServiceRegistrar registrar = lookup.getRegistrar();
22
23             // Search the lookup server to find the service that has the
24             // name attribute of "SummerService".
25             Entry[] attributes = new Entry[1];
26             attributes[0] = new Name("SummerService");
27             ServiceTemplate template = new ServiceTemplate(null, null,
28                 attributes);
29
30             // lookup() returns the service object for a service that matches
31             // the search criteria passed in as template
32             // Here, although I searched by Name attribute, I'm assuming that
33             // the object that comes back implements the Summer interface
34             Summer summer = (Summer) registrar.lookup(template);
35
36             LineNumberReader stdinReader = new LineNumberReader(
37                 new BufferedReader(new InputStreamReader(System.in)));
38
39             for (;;) {
40
41                 String userLine = stdinReader.readLine();
42
43                 if (userLine == null || userLine.length() == 0) {
44                     break;
45                 }
46
47                 String outString;
48                 try {
49                     long sum = summer.sumString(userLine);
50                     outString = Long.toString(sum);
51                 }
52                 catch(InvalidLongException e) {
53                     outString = e.getMessage();
54                 }
55                 System.out.println(outString);
56             }
57         }
58         catch (Exception e)
59         {
60           System.out.println("client: MyClient.main() exception: " + e);
61           e.printStackTrace();
62         }
63     }
64 }


$ java -Djava.security.policy=/sun/jini/bv/policy.all
    -Djava.rmi.server.codebase=http://localhost:8080/ SummerClient
1 1
2
2 2
4
3 3 3
9


The SummerClient2

import net.jini.entry.*;
import net.jini.lookup.*;
import net.jini.lookup.entry.*;
import net.jini.discovery.*;
import java.rmi.*;
import java.io.*;

class SummerClient2
{
    public static void main (String[] args) {

        try {
            System.setSecurityManager(new RMISecurityManager ());

            // Perform unicast lookup on localhost
            LookupLocator lookup = new LookupLocator("jini://localhost");

            // Get the service registrar object for the lookup service
            ServiceRegistrar registrar = lookup.getRegistrar();

            // Search the lookup server to find a service that implements
            // the Summer interface.
            Class[] types = new Class[1];
            types[0] = Summer.class;
            ServiceTemplate template = new ServiceTemplate(null, types, null);

            // lookup() returns the service object for a service that matches
            // the search criteria passed in as template
            // Here, because I searched by type, I'm certain that
            // the object that comes back implements the Summer interface.
            Summer summer = (Summer) registrar.lookup(template);

            LineNumberReader stdinReader = new LineNumberReader(
                new BufferedReader(new InputStreamReader(System.in)));

            for (;;) {

                String userLine = stdinReader.readLine();

                if (userLine == null || userLine.length() == 0) {
                    break;
                }

                String outString;
                try {
                    long sum = summer.sumString(userLine);
                    outString = Long.toString(sum);
                }
                catch(InvalidLongException e) {
                    outString = e.getMessage();
                }
                System.out.println(outString);
            }
        }
        catch (Exception e)
        {
          System.out.println("client: MyClient.main() exception: " + e);
          e.printStackTrace();
        }
    }
}


$ java -Djava.security.policy=/sun/jini/bv/policy.all
    -Djava.rmi.server.codebase=http://localhost:8080/ SummerClient2
1 1
2
3 -1
2
9999999 1
10000000

The Protocol is Private

Service object can:

Exercises

In the RuntimeInfa/ex2 directory, write a Jini chat client. The chat client will participate with other chat clients by reading and writing entries to a JavaSpace. While you are developing your chat client, you should make certain that you are actually using your own JavaSpace for testing, the one that is registered with "YOUR_NAME_HERE". (In the rest of the exercises, I'll call your "YOUR_NAME_HERE" space your "test space." If you end up messing inadvertently with someone else's JavaSpace, you will likely interfere with their work in ways that won't leave them very happy with you. Ultimately, once you get your program debugged, you can switch to using a shared JavaSpace and actually chat with others in the class through the shared space.

Problem 1.

Write a Java application named ChatWriter, whose main() method merely creates an ChatWriter instance and invokes its run() method. The run() method should be an instance method that takes no parameters and returns void. run() will take strings from the standard input and post them as messages to a chat room in the JavaSpace. As a first step, just make ChatWriter's run() method read lines from the standard input and echo each line back to the standard output. If the user types in a blank line (just hits return), ChatWriter should exit. (Feel free to borrow code from previous SummerClient programs, which also read lines from the standard input.)

Problem 2.

Modify ChatWriter so that it gets a JavaSpace proxy for your test space from a Jini lookup service. Use multicast discovery to find lookup services. Each time you find a lookup service, query it for your test space. Right at the beginning of your main() method, before you start looking for the JavaSpace, print out a message to the standard output that says:

Looking for the space.
Once you find the appropriate space, print a message to the standard output that says:
Found the space!

To do multicast discovery, you can use a LookupDiscovery object:

String[] groups = new String[] {""};
LookupDiscovery lookupDisc = new LookupDiscovery(groups);
lookupDisc.addDiscoveryListener(new SpaceFinder());
You'll need to define a DiscoveryListener whose discovered() method will look for the test JavaSpace in any discovered lookup services. To query the lookup service for the test space, you'll need to use both the JavaSpace class and a Name entry with the value "YOUR_NAME_HERE", as in:
// Look up the JavaSpace by type and name
// Matching service object must be an instance of JavaSpace
Class[] types = new Class[1];
types[0] = JavaSpace.class;

// Matching service must contain a name entry with the value spaceName
Entry[] entries = new Entry[1];
entries[0] = new Name(spaceName);

// Perform the lookup
ServiceTemplate tmpl = new ServiceTemplate(null, types, entries);
JavaSpace someSpace = null;
try {
    someSpace = (JavaSpace) registrar.lookup(tmpl);
}
catch (RemoteException e) {
    e.printStackTrace(System.out);
    return false;
}

Once your test space has been located in a lookup service, the discovery listener should stop caring about newly discovered lookup services.

Problem 3.

Modify ChatWriter so that posts each message read from the standard input to the JavaSpace. For the time being, place filler values in the author, position, and chatRoom fields, as in:

// Create a new ChatMessage and post it to the space
ChatMessage msgEntry = new ChatMessage("DefaultRoom", "GenericUser", new Long(0), userLine);
try {
    space.write(msgEntry, null, MESSAGE_LEASE_LENGTH);
}
catch (TransactionException e) {
    e.printStackTrace(System.out);
}
Write the entry into the space with a lease of about 5 minutes, so that after 5 minutes, the message will be automatically purged from the space:
// Determines length of the lease that is requested for all messages
// posted to chat rooms. This lease is never renewed, so after this
// amount of time, the chat message is kicked out of the room.
private static final int MESSAGE_LEASE_LENGTH = 5000 * 60;

Problem 4.

Save ChatWriter.java as ChatReader.java, and change all ChatWriters to ChatReaders. Leave in everything but the forever loop in which lines are read from the standard input. ChatReader should do discovery and look for the appropriate test JavaSpace. However, when the JavaSpace is discovered, ChatReader will loop forever taking ChatMessage entries from the space. Print out the author, a colon, a space, and the the content of every ChatMessage taken from the space. Something like:

for (;;) {

    // Create a new ChatMessage template
    ChatMessage msgTemplate = new ChatMessage("DefaultRoom", "GenericUser", new Long(0), null);
    try {
        ChatMessage msg = (ChatMessage) space.take(msgTemplate, null, Long.MAX_VALUE);
        System.out.println(msg.author + ": " + msg.content);
    }
    catch (UnusableEntryException e) {
        e.printStackTrace(System.out);
    }
    catch (TransactionException e) {
        e.printStackTrace(System.out);
    }
    catch (InterruptedException e) {
        e.printStackTrace(System.out);
    }
}

Test your program by posting messages to the space with one or more ChatWriters, and reading those messages via the ChatReader.


Sponsored Links

Copyright © 1996-2014 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us