previous chapter table of contents next chapter

Getting It Running

To make use of these classes, we need to provide a server to get the service put onto the network, and we need some clients to make use of the service. This section will just look at a simple way of doing this, and later sections in this chapter will put in more structure.

The following is a simple server that follows the earlier examples of servers using RMI proxies (such as in Chapter 9), just substituting RCXPort for FileClassifier and using a JoinManager . It creates an RCXPortImpl object and registers it (or rather, the RMI proxy) with lookup services:

 package rcx.jini; import java.rmi.RMISecurityManager; import net.jini.discovery.LookupDiscovery; import net.jini.discovery.LookupDiscoveryManager; import net.jini.core.lookup.ServiceID; // import com.sun.jini.lease.LeaseRenewalManager; // import com.sun.jini.lookup.JoinManager; // import com.sun.jini.lookup.ServiceIDListener; import net.jini.lease.LeaseRenewalManager; import net.jini.lookup.JoinManager; import net.jini.lookup.ServiceIDListener; /**  * RCXServer.java  */ public class RCXServer implements ServiceIDListener {     protected RCXPortImpl impl;     protected LeaseRenewalManager leaseManager = new LeaseRenewalManager();     public static void main(String argv[]) {         new RCXServer();         // remember to keepalive     }     public RCXServer() {         try {             impl = new RCXPortImpl();         } catch(Exception e) {             System.err.println("New impl: " + e.toString());             System.exit(1);         }         // set RMI security manager         System.setSecurityManager(new RMISecurityManager());         // find, register, lease, etc         try {             LookupDiscoveryManager mgr =                 new LookupDiscoveryManager(LookupDiscovery.ALL_GROUPS,                                            null /* unicast locators */,                                            null /* DiscoveryListener */);             JoinManager joinMgr = new JoinManager(impl,                                                   null,                                                   this,                                                   mgr,                                                   new LeaseRenewalManager());         } catch(java.io.IOException e) {             e.printStackTrace();         }     }     public void serviceIDNotify(ServiceID serviceID) {         System.out.println("Got service ID " + serviceID.toString());     } } // RCXServer 

Why is this example simplistic as a service? Well, it doesn't contain any information to allow a client to distinguish one LEGO MINDSTORMS robot from another, so that if there are many robots on the network, then a client could ask the wrong one to do things!

An equally simplistic client that makes the RCX perform a few actions is given below. In addition to sending a set of commands to the RCX, the client must also listen for replies from the RCX. I have separated out this listener as an EventHandler for readability. The listener will act as a remote event listener, with its notify() method called from the server. This can be done by letting it run an RMI stub on the server, so I have subclassed it from UnicastRemoteObject .

This particular client is designed to drive a particular robot: the "RoverBot," described in the LEGO MINDSTORMS "Constructopedia" (the instruction manual that comes with each MINDSTORMS set), is pictured in Figure 17-2.

click to expand
Figure 17-2: RoverBot MINDSTORMS robot

The RoverBot has motors to drive tracks or wheels on either side. The client can send instructions to make the RoverBot move forward or backward, stop, or turn to the left or right. The set of commands (and their implementation as RCX instructions) depends on the robot, and on what you want to do with it.

Here is the client code:

 package client; import rcx.jini.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.rmi.RMISecurityManager; import net.jini.discovery.LookupDiscovery; import net.jini.discovery.DiscoveryListener; import net.jini.discovery.DiscoveryEvent; import net.jini.core.lookup.ServiceRegistrar; import net.jini.core.lookup.ServiceTemplate; import net.jini.core.event.RemoteEventListener; import net.jini.core.event.RemoteEvent; import net.jini.core.event.UnknownEventException; import java.rmi.server.UnicastRemoteObject; import java.rmi.RemoteException; /**  * TestRCX.java  */ public class TestRCX implements DiscoveryListener {     public static final int STOPPED = 1;     public static final int FORWARDS = 2;     public static final int BACKWARDS = 4;     protected int state = STOPPED;     public static void main(String argv[]) {         new TestRCX();         // stay around long enough to receive replies         try {             Thread.currentThread().sleep(10000L);         } catch(java.lang.InterruptedException e) {             // do nothing         }     }     public TestRCX() {         System.setSecurityManager(new RMISecurityManager());         LookupDiscovery discover = null;         try {             discover = new LookupDiscovery(LookupDiscovery.ALL_GROUPS);         } catch(Exception e) {             System.err.println(e.toString());             System.exit(1);         }         discover.addDiscoveryListener(this);     }     public void discovered(DiscoveryEvent evt) {         ServiceRegistrar[] registrars = evt.getRegistrars();         Class [] classes = new Class[] {RCXPortInterface.class};         RCXPortInterface port = null;         ServiceTemplate template = new ServiceTemplate(null, classes,                                                        null);           for (int n = 0; n < registrars.length; n++) {             System.out.println("Service found");             ServiceRegistrar registrar = registrars[n];             try {                 port = (RCXPortInterface) registrar.lookup(template);             } catch(java.rmi.RemoteException e) {                 e.printStackTrace();                 System.exit(2);             }             if (port == null) {                 System.out.println("port null");                 continue;             }             // add an EventHandler as an RCX Port listener             try {                 port.addListener(new EventHandler(port));             } catch(Exception e) {                 e.printStackTrace();             }         }     }     public void discarded(DiscoveryEvent evt) {         // empty     }     class EventHandler extends UnicastRemoteObject                        implements RemoteEventListener, ActionListener {         protected RCXPortInterface port = null;     JFrame frame;     JTextArea text;     public EventHandler(RCXPortInterface port) throws RemoteException {         super() ;         this.port = port;         frame = new JFrame("LEGO MINDSTORMS");         Container content = frame.getContentPane();         JLabel label = new JLabel(new ImageIcon("images/MINDSTORMS.ps"));         JPanel pane = new JPanel();         pane.setLayout(new GridLayout(2, 3));         content.add(label, "North");         content.add(pane, "Center");         JButton btn = new JButton("Forward");         pane.add(btn);         btn.addActionListener(this);         btn = new JButton("Stop");         pane.add(btn);         btn.addActionListener(this);         btn = new JButton("Back");         pane.add(btn);         btn.addActionListener(this);         btn = new JButton("Left");         pane.add(btn);         btn.addActionListener(this);         label = new JLabel("");         pane.add(label);         btn = new JButton("Right");         pane.add(btn);         btn.addActionListener(this);         frame.pack();         frame.setVisible(true);     }     public void sendCommand(String comm) {         byte[] command;         try {             command = port.parseString(comm);             if (! port.write(command)) {                 System.err.println("command failed");             }         } catch(RemoteException e) {             e.printStackTrace();         }     }     public void forwards() {         sendCommand("e1 85");         sendCommand("21 85");         state = FORWARDS;     }     public void backwards() {         sendCommand("e1 45");         sendCommand("21 85");         state = BACKWARDS;     }     public void stop() {         sendCommand("21 45");         state = STOPPED;     }       public void restoreState() {         if (state == FORWARDS)             forwards();         else if (state == BACKWARDS)             backwards();         else             stop();     }     public void actionPerformed(ActionEvent evt) {         String name = evt.getActionCommand();         if (name.equals("Forward")) {             forwards();         } else if (name.equals("Stop")) {             stop();         } else if (name.equals("Back")) {             backwards();         } else if (name.equals("Left")) {             sendCommand("e1 84");             sendCommand("21 84");             sendCommand("21 41");             try {                 Thread.sleep(100);             } catch(InterruptedException e) {             }             restoreState();         } else if (name.equals("Right")) {             sendCommand("e1 81");             sendCommand("21 81");             sendCommand("21 44");             try {                 Thread.sleep(100);             } catch(InterruptedException e) {             }             restoreState();         }     }     public void notify(RemoteEvent evt) throws UnknownEventException,                                              java.rmi.RemoteException {         // System.out.println(evt.toString());         long id = evt.getID();         long seqNo = evt.getSequenceNumber();         if (id == RCXPortInterface.MESSAGE_EVENT) {             byte[] message = port.getMessage(seqNo);             StringBuffer sbuffer = new StringBuffer();             for(int n = 0; n < message.length; n++) {                 int newbyte = (int) message[n];                 if (newbyte < 0) {                     newbyte += 256;                 }                 sbuffer.append(Integer.toHexString(newbyte) + " ");             }             System.out.println("MESSAGE: " + sbuffer.toString());         } else if (id == RCXPortInterface.ERROR_EVENT) {             System.out.println("ERROR: " + port.getError(seqNo));         } else {                 throw new UnknownEventException("Unknown message " + evt.getID());               }           }     } } // TestRCX 

Why is this a simplistic client ? It tries to find all robots on the local network, and creates a top-level window for each of them. If a robot has registered with, say, half-a- dozen service locators, and the client finds all of these, then it will create six top-level windows , one for each copy of the same robot. Some smarts are needed here, such as using the ClientLookupManager of Chapter 15.


A Programmer[ap]s Guide to Jini Technology
A Programmer[ap]s Guide to Jini Technology
ISBN: 1893115801
Year: 2000
Pages: 189

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net