Recipe 22.6 Program: NetWatch


Here's a program I put together while teaching Java courses for Learning Tree (http://www.learningtree.com). In one exercise, each student starts the RMI registry on his or her machine and uses Naming.rebind( ) (as in Recipe 22.3) to register with it. Some students come up with interesting variations on the theme of registering. This program contacts the RMI registry on each of a batch of machines and shows the instructor graphically which machines have RMI running and what is registered. A red flag shows machines that don't even have the registry program running; a black flag shows machines that are dead to the (networked) world.

This program also uses many ideas from elsewhere in the book. A Swing GUI (Chapter 14) is used. The layout is a GridLayout (discussed briefly in Recipe 14.2). A default list of machines to watch is loaded from a Properties object (Recipe 7.7). For each host, an RMIPanel is constructed. This class is both a JComponent (Recipe 14.13) and a thread (Chapter 24). As a JComponent, it can be run in a panel; as a thread, it can run independently and then sleep for 30 seconds (by default; settable in the properties file) so that it isn't continually hammering away at the RMI registry on all the machines (the network traffic could be awesome). This program combines all these elements and comes out looking like the display in Figure 22-3 (alas, we don't have color pages in this book).

Figure 22-3. NetWatch watching the class
figs/jcb2_2203.gif


Example 22-7 is the main class, NetWatch, which creates the JFrame and all the RMIPanels and puts them together.

Example 22-7. NetWatch.java
public class NetWatch {     public static void main(String[] argv) {         Properties p = null;         NetFrame f = new NetFrame("Network Watcher", p);         try {             FileInputStream is = new FileInputStream("NetWatch.properties");             p = new Properties( );             p.load(is);             is.close( );         } catch (IOException e) {             JOptionPane.showMessageDialog(f,                 e.toString( ), "Properties error",                 JOptionPane.ERROR_MESSAGE);         }         // NOW CONSTRUCT PANELS, ONE FOR EACH HOST.         // If arguments, use them as hostnames.         if (argv.length!=0) {             for (int i=0; i<argv.length; i++) {                 f.addHost(argv[i], p);             }         // No arguments. Can we use properties?         } else if (p != null && p.size( ) > 0) {             String net = p.getProperty("netwatch.net");             int start = Integer.parseInt(p.getProperty("netwatch.start"));             int end = Integer.parseInt(p.getProperty("netwatch.end"));             for (int i=start; i<=end; i++) {                 f.addHost(net + "." + i, p);             }             for (int i=0; ; i++) {                 String nextHost = p.getProperty("nethost" + i);                 if (nextHost == null)                     break;                 f.addHost(nextHost, p);             }         }         // None of the above. Fall back to localhost         else {             f.addHost("localhost", p);         }         // All done. Pack the Frame and show it.         f.pack( );         // UtilGUI.centre(f);         f.setVisible(true);         f.addWindowListener(new WindowAdapter( ) {             public void windowClosing(WindowEvent e) {                 System.exit(0);             }         });     } }

The per-machine class, RMIPanel , is shown in Example 22-8. This class is instantiated once for each machine being monitored. Its run method loops, getting the list of registered objects from the given machine's RMI registry, and checks the contents to see if the expected string is present, setting the state to one of several integer values defined in the parent class NetPanel (EMPTY, DUBIOUS, FINE, etc.) based on what it finds. This state value is used to decide what color to paint this particular RMIPanel in the setState( ) method of the parent class NetPanel, which we have no reason to override.

Example 22-8. RMIPanel.java
/** Displays one machine's status, for RMI.  */ public class RMIPanel extends NetPanel implements Runnable {          public RMIPanel(String host, Properties p) {         super(host, p);     }     /** Keep the screen updated forever, unless stop( )ped. */     public void run( ) {         String thePort = props.getProperty("rmiwatch.port", "");         String theURL = "rmi://" + hostName + ":" + thePort;         while (!done) {             try {                 String[] names = Naming.list(theURL);                 ta.setText("");                 for (int i=0; i<names.length; i++) {                     ta.append(i + ": " + names[i] + "\n");                 }                 // If we didn't get an exception, host is up.                 String expect = props.getProperty("rmiwatch.expect");                 String fullText = ta.getText( );                 if (fullText.length( ) == 0) {                     ta.setText("(nothing registered!)");                     setState(EMPTY);                 } else if (expect != null && fullText.indexOf(expect)==-1) {                     setState(DUBIOUS);                 } else setState(FINE);             } catch (java.rmi.ConnectIOException e) {                 setState(DOWN);                 ta.setText("Net error: " + e.detail.getClass( ));             } catch (java.rmi.ConnectException e) {                 setState(NOREG);                 ta.setText("RMI error: " + e.getClass( ).getName( ) + "\n" +                     "  " + e.detail.getClass( ));                 // System.err.println(hostName + ":" + e);             } catch (RemoteException e) {                 setState(NOREG);                 ta.setText("RMI error: " + e.getClass( ).getName( ) + "\n" +                     "  " + e.detail.getClass( ));             } catch (MalformedURLException e) {                 setState(DOWN);                 ta.setText("Invalid host: " + e.toString( ));             } finally {                 // sleep( ) in "finally" so common "down" states don't bypass.                 // Randomize time so we don't make net load bursty.                 try {                     Thread.sleep((int)(sleepTime * MSEC * 2 * Math.random( )));                 } catch (InterruptedException e) {                     /*CANTHAPPEN*/                 }             }         }     } }

The last part is NetPanel, shown in Example 22-9. Notice the state variable definitions, and the setState( ) method that calls setBackground( ) to set the correct color given the state.

Example 22-9. NetPanel.java
/** Displays one machine's status.  * Part of the NetWatch program: watch the network  * on a bunch of machines (i.e., in a classroom or lab).  * <P>Each non-abstract subclass just needs to implement run( ),  * which must, in a while (!done) loop:  * <UL><LI>Try to contact the host  * <LI>call setState( ); (argument below)  * <LI>call ta.setText( );  * <LI>Thread.sleep(sleepTime * MSEC);  * </UL>  */ public abstract class NetPanel extends JPanel implements Runnable {     /** The name of this host */     protected String hostName;     /** The text area to display a list of stuff */     protected JTextArea ta;     /** Properties, passed in to constructor */     protected Properties props;     /** Default sleep time, in seconds. */     protected static int DEFAULT_SLEEP = 30;     /** Sleep time, in seconds. */     protected int sleepTime = DEFAULT_SLEEP;     /** Conversion */     protected int MSEC = 1000;     /** The constant-width font, shared by all instances. */     protected static Font cwFont;     /** The states */     /** The state for: has "expect"ed name registered. */     protected final static int FINE = 1;      /** The state for: does not have expected name registered. */     protected final static int DUBIOUS = 2;     /** The state for: Server has nothing registered. */     protected final static int EMPTY = 3;     /** The state for: host is up but not running RMI */     protected final static int NOREG = 4;     /** The state for: host unreachable, not responding, ECONN, etc. */     protected final static int DOWN = 5;     /** The color for when a machine is FINE */     protected static final Color COLOR_FINE = Color.green;     /** The color for when a machine is DUBIOUS */     protected static final Color COLOR_DUBIOUS = Color.yellow;     /** The color for when a machine is EMPTY */     protected static final Color COLOR_EMPTY = Color.white;     /** The color for when a machine has NOREG */     protected static final Color COLOR_NOREG = Color.red;     /** The color for when a machine is NOREG */     protected static final Color COLOR_DOWN = Color.black;     /** State of the monitored host's RMI registry, up or down.      * Initially set 0, which isn't one of the named states, to      * force the background color to be set on the first transition.      */     protected int state = 0;          public NetPanel(String host, Properties p) {         hostName = host;         props = p;         String s = props.getProperty("rmiwatch.sleep");         if (s != null)             sleepTime = Integer.parseInt(s);         // System.out.println("Sleep time now " + sleepTime);         // Maybe get font name and size from props?         if (cwFont == null)             cwFont = new Font("lucidasansTypewriter", Font.PLAIN, 10);         // Gooey gooey stuff.         ta = new JTextArea(2, 26);         ta.setEditable(false);         ta.setFont(cwFont);         add(BorderLayout.CENTER, ta);         setBorder(BorderFactory.createTitledBorder(hostName));         // Sparks. Ignition!         new Thread(this).start( );     }     boolean done = false;     /** Stop this Thread */     public void stop( ) {         done = true;     }     /** Record the new state of the current machine.      * If this machine has changed state, set its color      * @param newState - one of the five valid states in the introduction.      */     protected void setState(int newState) {         if (state /*already*/ == newState)             return;        // nothing to do.         switch(newState) {             case FINE:        // Server has "expect"ed name registered.                 ta.setBackground(COLOR_FINE);                 ta.setForeground(Color.black);                 break;             case DUBIOUS:    // Server does not have expected name registered.                 ta.setBackground(COLOR_DUBIOUS);                 ta.setForeground(Color.black);                 break;             case EMPTY:        // Server has nothing registered.                 ta.setBackground(COLOR_EMPTY);                 ta.setForeground(Color.black);                 break;             case NOREG:        // host is up but not running RMI                 ta.setBackground(COLOR_NOREG);                 ta.setForeground(Color.white);                 break;             case DOWN:        // host unreachable, not responding, ECONN, etc.                 ta.setBackground(COLOR_DOWN);                 ta.setForeground(Color.white);                 break;             default:                 throw new IllegalStateException("setState("+state+") invalid");             }         state = newState;     } }

See Also

The term distributed computing covers a lot of terrain. Here I've shown only the basics of RMI. For more on RMI, see Java Distributed Computing by Jim Farley (O'Reilly). Jim's book also offers some information on CORBA. It is possible to use RMI to access CORBA objects, or vice versa, using a mechanism called RMI-IIOP. See http://java.sun.com/products/rmi-iiop/.

The newest and potentially most important distributed mechanism for large-scale computing projects is Enterprise JavaBeans, part of the Java 2 Enterprise Edition (J2EE). See the O'Reilly book Enterprise JavaBeans by Richard Monson-Haefel.

You can also think of servlets and JSPs as a kind of distributed computing, used primarily as the gateway into these other distributed object mechanisms.



Java Cookbook
Java Cookbook, Second Edition
ISBN: 0596007019
EAN: 2147483647
Year: 2003
Pages: 409
Authors: Ian F Darwin

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