JTree Examples

SimpleTree.java Basic tree built out of DefaultMutableTreeNodes. A DefualtMutableTreeNode is a starting point for a root node, in which children nodes can be added.

import java.awt.*;
import javax.swing.*;
import javax.swing.tree.*;

/** Example tree built out of DefaultMutableTreeNodes. 
 *
 */

public class SimpleTree extends JFrame {
  public static void main(String[] args) {
    new SimpleTree();
  }
 
  public SimpleTree() {
    super("Creating a Simple JTree");
    WindowUtilities.setNativeLookAndFeel();
    addWindowListener(new ExitListener());
    Container content = getContentPane();
    Object[] hierarchy =
      { "javax.swing",
        "javax.swing.border",
        "javax.swing.colorchooser",
        "javax.swing.event",
        "javax.swing.filechooser",
        new Object[] { "javax.swing.plaf",
                       "javax.swing.plaf.basic",
                       "javax.swing.plaf.metal",
                       "javax.swing.plaf.multi" },
        "javax.swing.table",
        new Object[] { "javax.swing.text",
                       new Object[] { "javax.swing.text.html",
                                     "javax.swing.text.html.parser" },
                       "javax.swing.text.rtf" },
        "javax.swing.tree",
        "javax.swing.undo" };
    DefaultMutableTreeNode root = processHierarchy(hierarchy);
    JTree tree = new JTree(root);
    content.add(new JScrollPane(tree), BorderLayout.CENTER);
    setSize(275, 300);
    setVisible(true);
  }

  /** Small routine that will make a node out of the first entry
   *  in the array, then make nodes out of subsequent entries
   *  and make them child nodes of the first one. The process 
   *  is repeated recursively for entries that are arrays.
   */

  private DefaultMutableTreeNode processHierarchy(
                                           Object[] hierarchy) {
    DefaultMutableTreeNode node =
      new DefaultMutableTreeNode(hierarchy[0]);
    DefaultMutableTreeNode child;
    for(int i=1; i 0) {
      try {
        n = Integer.parseInt(args[0]);
      } catch(NumberFormatException nfe) {
        System.out.println(
          "Can't parse number; using default of " + n);
      }
   }
    new DynamicTree(n);
  }
 
  public DynamicTree(int n) {
    super("Creating a Dynamic JTree");
    WindowUtilities.setNativeLookAndFeel();
    addWindowListener(new ExitListener());
    Container content = getContentPane();
    JTree tree = new JTree(new OutlineNode(1, n));
    content.add(new JScrollPane(tree), BorderLayout.CENTER);
    setSize(300, 475);
    setVisible(true);
  }
}


    * OutlineNode.java A simple tree node that builds its children.
import java.awt.*;
import javax.swing.*;
import javax.swing.tree.*;

/** Simple TreeNode that builds children on the fly.
 *  The key idea is that getChildCount is always called before
 *  any actual children are requested. That way, getChildCount 
 *  builds the children if they don't already exist.
 *  


 *  In this case, it just builds an "outline" tree. I.e.,
 *  if the root is current node is "x", the children are
 *  "x.0", "x.1", "x.2", and "x.3".
 * 


 *
 */

public class OutlineNode extends DefaultMutableTreeNode {
  private boolean areChildrenDefined = false;
  private int outlineNum;
  private int numChildren;

  public OutlineNode(int outlineNum, int numChildren) {
    this.outlineNum = outlineNum;
    this.numChildren = numChildren;
  }
  
  public boolean isLeaf() {
    return(false);
  }

  public int getChildCount() {
    if (!areChildrenDefined) {
      defineChildNodes();
    }
    return(super.getChildCount());
  }

  private void defineChildNodes() {
    // You must set the flag before defining children if you
    // use "add" for the new children. Otherwise, you get an 
    // infinite recursive loop since add results in a call 
    // to getChildCount. However, you could use "insert" in such 
    // a case.
    areChildrenDefined = true;
    for(int i=0; i
                                

Printing in Java 2

   *
          o PrintExample.java Demonstrates printing a Graphics2D object.

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.print.*;

/** An example of a printable window in Java 1.2. The key point
 *  here is that any component is printable in Java 1.2.
 *  However, you have to be careful to turn off double buffering
 *  globally (not just for the top-level window).
 *  See the PrintUtilities class for the printComponent method
 *  that lets you print an arbitrary component with a single
 *  function call.
 *
 */

public class PrintExample extends JFrame
                           implements ActionListener {
  public static void main(String[] args) {
    new PrintExample();
  }

  public PrintExample() {
    super("Printing Swing Components in JDK 1.2");
    WindowUtilities.setNativeLookAndFeel();
    addWindowListener(new ExitListener());
    Container content = getContentPane();
    JButton printButton = new JButton("Print");
    printButton.addActionListener(this);
    JPanel buttonPanel = new JPanel();
    buttonPanel.setBackground(Color.white);
    buttonPanel.add(printButton);
    content.add(buttonPanel, BorderLayout.SOUTH);
    DrawingPanel drawingPanel = new DrawingPanel();
    content.add(drawingPanel, BorderLayout.CENTER);
    pack();
    setVisible(true);
  }

  public void actionPerformed(ActionEvent event) {
    PrintUtilities.printComponent(this);
  }
}

 Uses the following classes:
                + PrintUtilities.java Simple utility class to support printing graphical windows in JDK 1.2.

import java.awt.*;
import javax.swing.*;
import java.awt.print.*;

/** A simple utility class that lets you very simply print
 *  an arbitrary component in JDK 1.2. Just pass the 
 *  component to PrintUtilities.printComponent. The 
 *  component you want to print doesn't need a print method 
 *  and doesn't have to implement any interface or do 
 *  anything special at all.
 *  


 *  If you are going to be printing many times, it is marginally
 *  more efficient to first do the following:
 *  

 *    PrintUtilities printHelper = 
 *      new PrintUtilities(theComponent);
 *  


 *  then later do printHelper.print(). But this is a very tiny
 *  difference, so in most cases just do the simpler
 *  PrintUtilities.printComponent(componentToBePrinted).
 *
 
 */

public class PrintUtilities implements Printable {
  protected Component componentToBePrinted;

  public static void printComponent(Component c) {
    new PrintUtilities(c).print();
  }
  
  public PrintUtilities(Component componentToBePrinted) {
    this.componentToBePrinted = componentToBePrinted;
  }
  
  public void print() {
    PrinterJob printJob = PrinterJob.getPrinterJob();
    printJob.setPrintable(this);
    if (printJob.printDialog())
      try {
        printJob.print();
      } catch(PrinterException pe) {
        System.out.println("Error printing: " + pe);
      }
  }

  // General print routine for JDK 1.2. Use PrintUtilities2
  // for printing in JDK 1.3.
  public int print(Graphics g, PageFormat pageFormat, 
                   int pageIndex) {
    if (pageIndex > 0) {
      return(NO_SUCH_PAGE);
    } else {
      Graphics2D g2d = (Graphics2D)g;
      g2d.translate(pageFormat.getImageableX(), 
                    pageFormat.getImageableY());
      disableDoubleBuffering(componentToBePrinted);
      componentToBePrinted.paint(g2d);
      enableDoubleBuffering(componentToBePrinted);
      return(PAGE_EXISTS);
    }
  }

  /** The speed and quality of printing suffers dramatically if
   *  any of the containers have double buffering turned on,
   *  so this turns it off globally.  This step is only 
   *  required in JDK 1.2.
   */
   
  public static void disableDoubleBuffering(Component c) {
    RepaintManager currentManager = 
                      RepaintManager.currentManager(c);
    currentManager.setDoubleBufferingEnabled(false);
  }

  /** Reenables double buffering globally. This step is only 
   *  required in JDK 1.2.
   */
  
  public static void enableDoubleBuffering(Component c) {
    RepaintManager currentManager = 
                      RepaintManager.currentManager(c);
    currentManager.setDoubleBufferingEnabled(true);
  }
}
//
                + DrawingPanel.java A basic JPanel containing a Java 2D drawing.

import java.awt.*;
import javax.swing.*;
import java.awt.geom.*;

/** A window with a custom paintComponent method. 
 *  Illustrates that you can make a general-purpose method
 *  that can print any component, regardless of whether
 *  that component performs custom drawing.
 *  See the PrintUtilities class for the printComponent method
 *  that lets you print an arbitrary component with a single
 *  function call.
 *
  */

public class DrawingPanel extends JPanel {
  private int fontSize = 90;
  private String message = "Java 2D";
  private int messageWidth;
  
  public DrawingPanel() {
    setBackground(Color.white);
    Font font = new Font("Serif", Font.PLAIN, fontSize);
    setFont(font);
    FontMetrics metrics = getFontMetrics(font);
    messageWidth = metrics.stringWidth(message);
    int width = messageWidth*5/3;
    int height = fontSize*3;
    setPreferredSize(new Dimension(width, height));
  }

  /** Draws a black string with a tall angled "shadow"
   *  of the string behind it.
   */

  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D)g;
    int x = messageWidth/10;
    int y = fontSize*5/2;
    g2d.translate(x, y);
    g2d.setPaint(Color.lightGray);
    AffineTransform origTransform = g2d.getTransform();
    g2d.shear(-0.95, 0);
    g2d.scale(1, 3);
    g2d.drawString(message, 0, 0);
    g2d.setTransform(origTransform);
    g2d.setPaint(Color.black);
    g2d.drawString(message, 0, 0);
  }
}

          o PrintUtilities2.java Simple utility class to support printing graphical windows in JDK 1.3 and later. Inherits from PrintUtilities.java.

import java.awt.*;
import javax.swing.*;
import java.awt.print.*;

/** A simple utility class for printing an arbitrary
 *  component in JDK 1.3. The class relies on the 
 *  fact that in JDK 1.3 the JComponent class overrides
 *  print (in Container) to automatically set a flag
 *  that disables double buffering before the component
 *  is painted. If the printing flag is set, paint calls 
 *  printComponent, printBorder, and printChildren.
 *
 *  To print a component, just pass the component to 
 *  PrintUtilities2.printComponent(componentToBePrinted). 
 *
  */

public class PrintUtilities2 extends PrintUtilities {

  public static void printComponent(Component c) {
    new PrintUtilities2(c).print();
  }
  
  public PrintUtilities2(Component componentToBePrinted) {
    super(componentToBePrinted);
  }
  
  // General print routine for JDK 1.3. Use PrintUtilities1
  // for printing in JDK 1.2.
  public int print(Graphics g, PageFormat pageFormat, 
                   int pageIndex) {
    if (pageIndex > 0) {
      return(NO_SUCH_PAGE);
    } else {
      Graphics2D g2d = (Graphics2D)g;
      g2d.translate(pageFormat.getImageableX(), 
                    pageFormat.getImageableY());
      componentToBePrinted.print(g2d);
      return(PAGE_EXISTS);
    }
  }
}

    * FileTransfer.java Demonstrates the proper technique for updating Swing components in a multithreaded program.

/** 

// Final version of FileTransfer. Modification of the 
// label is thread safe.

public class FileTransfer extends Thread {
  private String filename;
  private JLabel label;

  public FileTransfer(String filename, JLabel label) {
    this.filename = filename;
    this.label = label;
  }

  public void run() {
  
    try {
      // Place the runnable object to update the label
      // on the event queue. The invokeAndWait method
      // will block until the label is updated.
      SwingUtilities.invokeAndWait(
        new Runnable() {
          public void run() {
            label.setText("Transferring " + filename);
          }
        });
    } catch(InvocationTargetException ite) {
    } catch(InterruptedException ie) { }
       
    // Transfer file to server. Lengthy process.
    doTransfer(...);

    // Perform the final update to the label from
    // within the runnable object. Use invokeLater;
    // blocking is not necessary.
    SwingUtilities.invokeLater(
       new Runnable() {
         public void run() {
           label.setText("Transfer completed");
         }
       });
  }
}
    * WindowUtilities.java Utility class that simplifies creating a window and setting the look and feel.
    * ExitListener.java A WindowListener with support to close the window.

BetterCircleTest.java

**********************
BetterCircleTest.java
**********************
import java.awt.*;
import java.applet.Applet;

/** Position circles down the diagonal so that their borders
 *  just touch. Illustrates that Java 1.1 lightweight 
 *  components can be partially transparent.
 *
  */

public class BetterCircleTest extends Applet {
  public void init() {
    setBackground(Color.lightGray);
    setLayout(null);
    BetterCircle circle;
    int radius = getSize().width/6;
    int deltaX = round(2.0 * (double)radius / Math.sqrt(2.0));
    for (int x=radius; x<6*radius; x=x+deltaX) {
      circle = new BetterCircle(Color.black, radius);
      add(circle);
      circle.setCenter(x, x);
    }
  }

  private int round(double num) {
    return((int)Math.round(num));
  }
}
********************************
BetterCircle.java
********************************
import java.awt.*;

/** An improved variation of the Circle class that uses Java 1.1
 *  lightweight components instead of Canvas.
 *
  */

public class BetterCircle extends Component {
  private Dimension preferredDimension;
  private int width, height;
  
  public BetterCircle(Color foreground, int radius) {
    setForeground(foreground);
    width = 2*radius;
    height = 2*radius;
    preferredDimension = new Dimension(width, height);
    setSize(preferredDimension);
  }

  public void paint(Graphics g) {
    g.setColor(getForeground());
    g.fillOval(0, 0, width, height);
  }

  public void setCenter(int x, int y) {
    setLocation(x - width/2, y - height/2);
  }

  /** Report the original size as the preferred size.
   *  That way, the BetterCircle doesn't get
   *  shrunk by layout managers.
   */
  
  public Dimension getPreferredSize() {
    return(preferredDimension);
  }

  /** Report same thing for minimum size as
   *  preferred size.
   */
  
  public Dimension getMinimumSize() {
    return(preferredDimension);
  }
}
*******************************

RMI Example – Numerical Integration, a more realistic RMI example that sends an evaluatable object (function) from a client to a server for numerical integration.

Integral.java  Performs actual numerical integration of the function (evaluatable object).

/** A class to calculate summations and numeric integrals. The
 *  integral is calculated according to the midpoint rule.
 *
 *  Taken from Core Web Programming from
 *  Prentice Hall and Sun Microsystems Press,
 *  .
 *  © 2001 Marty Hall and Larry Brown;
 *  may be freely used or adapted.
 */

public class Integral {
  /** Returns the sum of f(x) from x=start to x=stop, where the
   *  function f is defined by the evaluate method of the
   *  Evaluatable object.
   */

  public static double sum(double start, double stop,
                           double stepSize,
                           Evaluatable evalObj) {
    double sum = 0.0, current = start;
    while (current <= stop) {
      sum += evalObj.evaluate(current);
      current += stepSize;
    }
    return(sum);
  }

  /** Returns an approximation of the integral of f(x) from
   *  start to stop, using the midpoint rule. The function f is
   *  defined by the evaluate method of the Evaluatable object.
   */

  public static double integrate(double start, double stop,
                                 int numSteps,
                                 Evaluatable evalObj) {
    double stepSize = (stop - start) / (double)numSteps;
    start = start + stepSize / 2.0;
    return(stepSize * sum(start, stop, stepSize, evalObj));
  }
}



Evaluatable.java  An interface for evaluating functions. Requires the Evaluatable  object to implement the evaluate method. 

/** An interface for evaluating functions y = f(x) at a specific
 *  value. Both x and y are double-precision floating-point
 *  numbers.
 *
 *  Taken from Core Web Programming from
 *  Prentice Hall and Sun Microsystems Press,
 *  .
 *  © 2001 Marty Hall and Larry Brown;
 *  may be freely used or adapted.
 */

public interface Evaluatable {
  public double evaluate(double value);
}


RemoteIntegral.java  Establishes the methods in the remote object available to the client. 

import java.rmi.*;

/** Interface for remote numeric integration object.
 *
 *  Taken from Core Web Programming from
 *  Prentice Hall and Sun Microsystems Press,
 *  .
 *  © 2001 Marty Hall and Larry Brown;
 *  may be freely used or adapted.
 */

public interface RemoteIntegral extends Remote {

  public double sum(double start, double stop, double stepSize,
                    Evaluatable evalObj)
    throws RemoteException;

  public double integrate(double start, double stop,
                          int numSteps, Evaluatable evalObj)
    throws RemoteException;
}


RemoteIntegralClient.java  The client that sends an Evaluatable object to the remote server for integration. 

import java.rmi.*;
import java.net.*;
import java.io.*;

/** This class calculates a variety of numerical integration
 *  values, printing the results of successively more accurate
 *  approximations. The actual computation is performed on a
 *  remote machine whose hostname is specified as a command-
 *  line argument.
 *
 *  Taken from Core Web Programming from
 *  Prentice Hall and Sun Microsystems Press,
 *  .
 *  © 2001 Marty Hall and Larry Brown;
 *  may be freely used or adapted.
 */

public class RemoteIntegralClient {
  public static void main(String[] args) {
    try {
      String host = (args.length > 0) ? args[0] : "localhost";
      RemoteIntegral remoteIntegral =
        (RemoteIntegral)Naming.lookup("rmi://" + host +
                                      "/RemoteIntegral");
      for(int steps=10; steps<=10000; steps*=10) {
        System.out.println
          ("Approximated with " + steps + " steps:" +
           "\n  Integral from 0 to pi of sin(x)=" +
           remoteIntegral.integrate(0.0, Math.PI,
                                    steps, new Sin()) +
           "\n  Integral from pi/2 to pi of cos(x)=" +
           remoteIntegral.integrate(Math.PI/2.0, Math.PI,
                                    steps, new Cos()) +
           "\n  Integral from 0 to 5 of x^2=" +
           remoteIntegral.integrate(0.0, 5.0, steps,
                                    new Quadratic()));
      }
      System.out.println
        ("`Correct' answer using Math library:" +
         "\n  Integral from 0 to pi of sin(x)=" +
         (-Math.cos(Math.PI) - -Math.cos(0.0)) +
         "\n  Integral from pi/2 to pi of cos(x)=" +
         (Math.sin(Math.PI) - Math.sin(Math.PI/2.0)) +
         "\n  Integral from 0 to 5 of x^2=" +
         (Math.pow(5.0, 3.0) / 3.0));
    } catch(RemoteException re) {
      System.out.println("RemoteException: " + re);
    } catch(NotBoundException nbe) {
      System.out.println("NotBoundException: " + nbe);
    } catch(MalformedURLException mfe) {
      System.out.println("MalformedURLException: " + mfe);
    }
  }
}


Sin.java  Evaluatable version of sin(x).
import java.io.Serializable;

/** An evaluatable version of sin(x).
 *
 *  Taken from Core Web Programming from
 *  Prentice Hall and Sun Microsystems Press,
 *  .
 *  © 2001 Marty Hall and Larry Brown;
 *  may be freely used or adapted.
 */

class Sin implements Evaluatable, Serializable {
  public double evaluate(double val) {
    return(Math.sin(val));
  }

  public String toString() {
    return("Sin");
  }
}

Cos.java  Evaluatable version of cos(x). 

import java.io.Serializable;

/** An evaluatable version of cos(x).
 *
 *  Taken from Core Web Programming from
 *  Prentice Hall and Sun Microsystems Press,
 *  .
 *  © 2001 Marty Hall and Larry Brown;
 *  may be freely used or adapted.
 */

class Cos implements Evaluatable, Serializable {
  public double evaluate(double val) {
    return(Math.cos(val));
  }

  public String toString() {
    return("Cosine");
  }
}


Quadratic.java  Evaluatable version of x2. 


import java.io.Serializable;

/** An evaluatable version of x^2.
 *
 *  Taken from Core Web Programming from
 *  Prentice Hall and Sun Microsystems Press,
 *  .
 *  © 2001 Marty Hall and Larry Brown;
 *  may be freely used or adapted.
 */

class Quadratic implements Evaluatable, Serializable {
  public double evaluate(double val) {
    return(val * val);
  }

  public String toString() {
    return("Quadratic");
  }
}

RemoteIntegralImpl.java  The remote object which provides a concrete implementation of the RemoteIntegral interface. 

import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;

/** The actual implementation of the RemoteIntegral interface.
 *
 *  Taken from Core Web Programming from
 *  Prentice Hall and Sun Microsystems Press,
 *  .
 *  © 2001 Marty Hall and Larry Brown;
 *  may be freely used or adapted.
 */

public class RemoteIntegralImpl extends UnicastRemoteObject
                                implements RemoteIntegral {

  /** Constructor must throw RemoteException. */

  public RemoteIntegralImpl() throws RemoteException {}

  /** Returns the sum of f(x) from x=start to x=stop, where the
   *  function f is defined by the evaluate method of the
   *  Evaluatable object.
   */

  public double sum(double start, double stop, double stepSize,
                    Evaluatable evalObj) {
    return(Integral.sum(start, stop, stepSize, evalObj));
  }

  /** Returns an approximation of the integral of f(x) from
   *  start to stop, using the midpoint rule. The function f is
   *  defined by the evaluate method of the Evaluatable object.
   * @see #sum
   */

  public double integrate(double start, double stop, int numSteps,
                          Evaluatable evalObj) {
    return(Integral.integrate(start, stop, numSteps, evalObj));
  }
}



RemoteIntegralServer.java  Creates an instance of RemoteIntegralImpl on the remote server and binds the object in the registry for lookup by the client. 

import java.rmi.*;
import java.net.*;

/** Creates a RemoteIntegralImpl object and registers it under
 *  the name 'RemoteIntegral' so that remote clients can connect
 *  to it for numeric integration results. The idea is to place
 *  this server on a workstation with very fast floating-point
 *  capabilities, while slower interfaces can run on smaller
 *  computers but still use the integration routines.
 *
 *  Taken from Core Web Programming from
 *  Prentice Hall and Sun Microsystems Press,
 *  .
 *  © 2001 Marty Hall and Larry Brown;
 *  may be freely used or adapted.
 */

public class RemoteIntegralServer {
  public static void main(String[] args) {
    try {
      RemoteIntegralImpl integral =  new RemoteIntegralImpl();
      Naming.rebind("rmi:///RemoteIntegral", integral);
    } catch(RemoteException re) {
      System.out.println("RemoteException: " + re);
    } catch(MalformedURLException mfe) {
      System.out.println("MalformedURLException: " + mfe);
    }
  }
}


RemoteIntegralClient2.java  An enterprise version of the client that imposes a security manager to support the Java 2 RMI 1.2 stub protocol. 

import java.rmi.*;
import java.net.*;
import java.io.*;

/** This class is a Java 2 version of RemoteIntegralClient
 *  that imposes a SecurityManager to allow the client to
 *  connect to a remote machine for loading stub files and
 *  performing numerical integration through a remote
 *  object.
 *
 *  Taken from Core Web Programming from
 *  Prentice Hall and Sun Microsystems Press,
 *  .
 *  © 2001 Marty Hall and Larry Brown;
 *  may be freely used or adapted.
 */

public class RemoteIntegralClient2 {
  public static void main(String[] args) {
    try {
      System.setSecurityManager(new RMISecurityManager());
      String host =
        (args.length > 0) ? args[0] : "localhost";
      RemoteIntegral remoteIntegral =
        (RemoteIntegral)Naming.lookup("rmi://" + host +
                                      "/RemoteIntegral");
      for(int steps=10; steps<=10000; steps*=10) {
        System.out.println
          ("Approximated with " + steps + " steps:" +
           "\n  Integral from 0 to pi of sin(x)=" +
           remoteIntegral.integrate(0.0, Math.PI,
                                    steps, new Sin()) +
           "\n  Integral from pi/2 to pi of cos(x)=" +
           remoteIntegral.integrate(Math.PI/2.0, Math.PI,
                                    steps, new Cos()) +
           "\n  Integral from 0 to 5 of x^2=" +
           remoteIntegral.integrate(0.0, 5.0, steps,
                                    new Quadratic()));
      }
      System.out.println
        ("`Correct' answer using Math library:" +
         "\n  Integral from 0 to pi of sin(x)=" +
         (-Math.cos(Math.PI) - -Math.cos(0.0)) +
         "\n  Integral from pi/2 to pi of cos(x)=" +
         (Math.sin(Math.PI) - Math.sin(Math.PI/2.0)) +
         "\n  Integral from 0 to 5 of x^2=" +
         (Math.pow(5.0, 3.0) / 3.0));
    } catch(RemoteException re) {
      System.out.println("RemoteException: " + re);
    } catch(NotBoundException nbe) {
      System.out.println("NotBoundException: " + nbe);
    } catch(MalformedURLException mfe) {
      System.out.println("MalformedURLException: " + mfe);
    }
  }
}

rmiclient.policy  Policy file for the client. Grants permissions for the client to connect to the RMI server and Web server. 

//  Taken from Core Web Programming from
//  Prentice Hall and Sun Microsystems Press,
//  .
//  © 2001 Marty Hall and Larry Brown;
//  may be freely used or adapted.

grant {
  // rmihost - RMI registry and the server
  // webhost - HTTP server for stub classes
  permission java.net.SocketPermission 
    "rmihost:1024-65535", "connect";
  permission java.net.SocketPermission 
    "webhost:80", "connect";
};

A JPanel that displays six radio buttons with labels.

A JPanel that displays six radio buttons with labels.

import java.awt.*;
import javax.swing.*;

/** A JPanel that displays six JRadioButtons. 
 *
 *.
 */

public class SixChoicePanel extends JPanel {
  public SixChoicePanel(String title, String[] buttonLabels) {
    super(new GridLayout(3, 2));
    setBackground(Color.lightGray);
    setBorder(BorderFactory.createTitledBorder(title));
    ButtonGroup group = new ButtonGroup();
    JRadioButton option;
    int halfLength = buttonLabels.length/2;  // Assumes even length
    for(int i=0; i

ThreadedEchoServer.java A multithreaded version of EchoServer, where each client request is serviced on a separate thread. Requires the following classes

import java.net.*;
import java.io.*;

/** A multithreaded variation of EchoServer.
 *
 *  Taken from Core Web Programming from
 *  Prentice Hall and Sun Microsystems Press,
 *  .
 *  © 2001 Marty Hall and Larry Brown;
 *  may be freely used or adapted.
 */

public class ThreadedEchoServer extends EchoServer
                                implements Runnable {
  public static void main(String[] args) {
    int port = 8088;
    if (args.length > 0) {
      try {
        port = Integer.parseInt(args[0]);
      } catch(NumberFormatException nfe) {}
    }
    ThreadedEchoServer echoServer =
      new ThreadedEchoServer(port, 0);
    echoServer.serverName = "Threaded EchoServer";
  }

  public ThreadedEchoServer(int port, int connections) {
    super(port, connections);
  }

  /** The new version of handleConnection starts a thread. This
   *  new thread will call back to the old version of
   *  handleConnection, resulting in the same server behavior
   *  in a multithreaded version. The thread stores the Socket
   *  instance since run doesn't take any arguments, and since
   *  storing the socket in an instance variable risks having
   *  it overwritten if the next thread starts before the run
   *  method gets a chance to copy the socket reference.
   */

  public void handleConnection(Socket server) {
    Connection connectionThread = new Connection(this, server);
    connectionThread.start();
  }

  public void run() {
    Connection currentThread =
      (Connection)Thread.currentThread();
    try {
      super.handleConnection(currentThread.getSocket());
    } catch(IOException ioe) {
      System.out.println("IOException: " + ioe);
      ioe.printStackTrace();
    }
  }
}

/** This is just a Thread with a field to store a Socket object.
 *  Used as a thread-safe means to pass the Socket from
 *  handleConnection to run.
 */

class Connection extends Thread {
  private Socket serverSocket;

  public Connection(Runnable serverObject,
                    Socket serverSocket) {
    super(serverObject);
    this.serverSocket = serverSocket;
  }

  public Socket getSocket() {
    return serverSocket;
  }
}



EchoServer.java  Creates a Web page showing all data sent from the client (browser). 


import java.net.*;
import java.io.*;
import java.util.StringTokenizer;

/** A simple HTTP server that generates a Web page showing all
 *  of the data that it received from the Web client (usually
 *  a browser). To use this server, start it on the system of
 *  your choice, supplying a port number if you want something
 *  other than port 8088. Call this system server.com. Next,
 *  start a Web browser on the same or a different system, and
 *  connect to http://server.com:8088/whatever. The resultant
 *  Web page will show the data that your browser sent. For 
 *  debugging in servlet or CGI programming, specify 
 *  http://server.com:8088/whatever as the ACTION of your HTML
 *  form. You can send GET or POST data; either way, the
 *  resultant page will show what your browser sent.
 *
 *  Taken from Core Web Programming from 
 *  Prentice Hall and Sun Microsystems Press,
 *  © 2001 Marty Hall and Larry Brown;
 *  may be freely used or adapted. 
 */

public class EchoServer extends NetworkServer {
  protected int maxRequestLines = 50;
  protected String serverName = "EchoServer";

  /** Supply a port number as a command-line
   *  argument. Otherwise, use port 8088.
   */
  
  public static void main(String[] args) {
    int port = 8088;
    if (args.length > 0) {
      try {
        port = Integer.parseInt(args[0]);
      } catch(NumberFormatException nfe) {}
    }
    new EchoServer(port, 0);
  }

  public EchoServer(int port, int maxConnections) {
    super(port, maxConnections);
    listen();
  }

  /** Overrides the NetworkServer handleConnection method to 
   *  read each line of data received, save it into an array
   *  of strings, then send it back embedded inside a PRE 
   *  element in an HTML page.
   */
  
  public void handleConnection(Socket server)
      throws IOException{
    System.out.println
        (serverName + ": got connection from " +
         server.getInetAddress().getHostName());
    BufferedReader in = SocketUtil.getReader(server);
    PrintWriter out = SocketUtil.getWriter(server);
    String[] inputLines = new String[maxRequestLines];
    int i;
    for (i=0; i\n" +
       "\n" +
       "\n" +
       "  \n" +
       "\n" +
       "\n" +
       "\n" +
       "
" + serverName +
         " Results
\n" +
       "Here is the request line and request headers\n" +
       "sent by your browser:\n" +
       "

");
  }

  // Print bottom of a standard Web page.
  
  private void printTrailer(PrintWriter out) {
    out.println
      ("

\n" +
       "\n" +
       "\n");
  }

  // Normal Web page requests use GET, so this server can simply
  // read a line at a time. However, HTML forms can also use 
  // POST, in which case we have to determine the number of POST
  // bytes that are sent so we know how much extra data to read
  // after the standard HTTP headers.
  
  private boolean usingPost(String[] inputs) {
    return(inputs[0].toUpperCase().startsWith("POST"));
  }

  private void readPostData(String[] inputs, int i,
                            BufferedReader in)
      throws IOException {
    int contentLength = contentLength(inputs);
    char[] postData = new char[contentLength];
    in.read(postData, 0, contentLength);
    inputs[++i] = new String(postData, 0, contentLength);
  }

  // Given a line that starts with Content-Length,
  // this returns the integer value specified.
  
  private int contentLength(String[] inputs) {
    String input;
    for (int i=0; iOverride this method in servers
   *  you write.
   *  


   *  This generic version simply reports the host that made
   *  the connection, shows the first line the client sent,
   *  and sends a single line in response.
   */

  protected void handleConnection(Socket server)
      throws IOException{
    BufferedReader in = SocketUtil.getReader(server);
    PrintWriter out = SocketUtil.getWriter(server);
    System.out.println
      ("Generic Network Server: got connection from " +
       server.getInetAddress().getHostName() + "\n" +
       "with first line '" + in.readLine() + "'");
    out.println("Generic Network Server");
    server.close();
  }

  /** Gets the max connections server will handle before
   *  exiting. A value of 0 indicates that server should run
   *  until explicitly killed.
   */

  public int getMaxConnections() {
    return(maxConnections);
  }

  /** Sets max connections. A value of 0 indicates that server
   *  should run indefinitely (until explicitly killed).
   */

  public void setMaxConnections(int maxConnections) {
    this.maxConnections = maxConnections;
  }

  /** Gets port on which server is listening. */

  public int getPort() {
    return(port);
  }

  /** Sets port. You can only do before "connect" is
   *  called. That usually happens in the constructor.
   */

  protected void setPort(int port) {
    this.port = port;
  }
}


SocketUtil.java  Simplifies the creation of a PrintWriter and BufferedReader.

import java.net.*;
import java.io.*;

/** A shorthand way to create BufferedReaders and
 *  PrintWriters associated with a Socket.
 *
 *  Taken from Core Web Programming from 
 *  Prentice Hall and Sun Microsystems Press,
 *  © 2001 Marty Hall and Larry Brown;
 *  may be freely used or adapted. 
 */

public class SocketUtil {
  /** Make a BufferedReader to get incoming data. */

  public static BufferedReader getReader(Socket s)
      throws IOException {
    return(new BufferedReader(
       new InputStreamReader(s.getInputStream())));
  }

  /** Make a PrintWriter to send outgoing data.
   *  This PrintWriter will automatically flush stream
   *  when println is called.
   */

  public static PrintWriter getWriter(Socket s)
      throws IOException {
    // Second argument of true means autoflush.
    return(new PrintWriter(s.getOutputStream(), true));
  }
}

Implementing a Server : Network Server

NetworkServerTest.java  Establishes a network Server that listens for client requests on the port specified (command-line argument). Uses the following classes:

 

/** Taken from Core Web Programming from
 *  Prentice Hall and Sun Microsystems Press,
 *  .
 *  © 2001 Marty Hall and Larry Brown;
 *  may be freely used or adapted.
 */


public class NetworkServerTest {
  public static void main(String[] args) {
    int port = 8088;
    if (args.length > 0) {
      port = Integer.parseInt(args[0]);
    }
    NetworkServer nwServer = new NetworkServer(port, 1);
    nwServer.listen();
  }
}


# NetworkServer.java  A starting point for network servers. 

import java.net.*;
import java.io.*;

/** A starting point for network servers. You'll need to
 *  override handleConnection, but in many cases listen can
 *  remain unchanged. NetworkServer uses SocketUtil to simplify
 *  the creation of the PrintWriter and BufferedReader.
 *
 *  Taken from Core Web Programming from
 *  Prentice Hall and Sun Microsystems Press,
 *  .
 *  © 2001 Marty Hall and Larry Brown;
 *  may be freely used or adapted.
 */

public class NetworkServer {
  private int port, maxConnections;

  /** Build a server on specified port. It will continue to
   *  accept connections, passing each to handleConnection until
   *  an explicit exit command is sent (e.g., System.exit) or
   *  the maximum number of connections is reached. Specify
   *  0 for maxConnections if you want the server to run
   *  indefinitely.
   */

  public NetworkServer(int port, int maxConnections) {
    setPort(port);
    setMaxConnections(maxConnections);
  }

  /** Monitor a port for connections. Each time one is
   *  established, pass resulting Socket to handleConnection.
   */

  public void listen() {
    int i=0;
    try {
      ServerSocket listener = new ServerSocket(port);
      Socket server;
      while((i++ < maxConnections) || (maxConnections == 0)) {
        server = listener.accept();
        handleConnection(server);
      }
    } catch (IOException ioe) {
      System.out.println("IOException: " + ioe);
      ioe.printStackTrace();
    }
  }

  /** This is the method that provides the behavior to the
   *  server, since it determines what is done with the
   *  resulting socket. Override this method in servers
   *  you write.
   *  


   *  This generic version simply reports the host that made
   *  the connection, shows the first line the client sent,
   *  and sends a single line in response.
   */

  protected void handleConnection(Socket server)
      throws IOException{
    BufferedReader in = SocketUtil.getReader(server);
    PrintWriter out = SocketUtil.getWriter(server);
    System.out.println
      ("Generic Network Server: got connection from " +
       server.getInetAddress().getHostName() + "\n" +
       "with first line '" + in.readLine() + "'");
    out.println("Generic Network Server");
    server.close();
  }

  /** Gets the max connections server will handle before
   *  exiting. A value of 0 indicates that server should run
   *  until explicitly killed.
   */

  public int getMaxConnections() {
    return(maxConnections);
  }

  /** Sets max connections. A value of 0 indicates that server
   *  should run indefinitely (until explicitly killed).
   */

  public void setMaxConnections(int maxConnections) {
    this.maxConnections = maxConnections;
  }

  /** Gets port on which server is listening. */

  public int getPort() {
    return(port);
  }

  /** Sets port. You can only do before "connect" is
   *  called. That usually happens in the constructor.
   */

  protected void setPort(int port) {
    this.port = port;
  }
}

SocketUtil.java  Simplifies the creation of a PrintWriter and BufferedReader.


import java.net.*;
import java.io.*;

/** A shorthand way to create BufferedReaders and
 *  PrintWriters associated with a Socket.
 *
 *  Taken from Core Web Programming from 
 *  Prentice Hall and Sun Microsystems Press,
 *  © 2001 Marty Hall and Larry Brown;
 *  may be freely used or adapted. 
 */

public class SocketUtil {
  /** Make a BufferedReader to get incoming data. */

  public static BufferedReader getReader(Socket s)
      throws IOException {
    return(new BufferedReader(
       new InputStreamReader(s.getInputStream())));
  }

  /** Make a PrintWriter to send outgoing data.
   *  This PrintWriter will automatically flush stream
   *  when println is called.
   */

  public static PrintWriter getWriter(Socket s)
      throws IOException {
    // Second argument of true means autoflush.
    return(new PrintWriter(s.getOutputStream(), true));
  }
}

UrlTest.java Demonstrates the ease in which the various components of an URL can be determined (host, port, protocol, etc.)

জা
import java.net.*;

/** Read a URL from the command line, then print
 *  the various components.
 *
 *  Taken from Core Web Programming from
 *  Prentice Hall and Sun Microsystems Press,
 *  .
 *  © 2001 Marty Hall and Larry Brown;
 *  may be freely used or adapted.
 */

public class UrlTest {
  public static void main(String[] args) {
    if (args.length == 1) {
      try {
        URL url = new URL(args[0]);
        System.out.println
          ("URL: " + url.toExternalForm() + "\n" +
           "  File:      " + url.getFile() + "\n" +
           "  Host:      " + url.getHost() + "\n" +
           "  Port:      " + url.getPort() + "\n" +
           "  Protocol:  " + url.getProtocol() + "\n" +
           "  Reference: " + url.getRef());
      } catch(MalformedURLException mue) {
        System.out.println("Bad URL.");
      }
    } else
      System.out.println("Usage: UrlTest ");
  }
}

Counter2Test.java Driver class that creates three threaded objects (Counter2) that count from 0 to 4.

/** Try out a few instances of the Counter2 class. 

Driver class that creates three threaded objects (Counter2) that count from 0 to 4. In this case, 
the driver does not start the threads, as each thread is automatically started in Counter2's 
constructor. Uses the following class:

Counter2Test.java
Counter2.java
**************************    
public class Counter2Test {
  public static void main(String[] args) {
    Counter2 c1 = new Counter2(5);
    Counter2 c2 = new Counter2(5);
    Counter2 c3 = new Counter2(5);
  }
}

* Counter2.java A Runnable  that counts to a specified value and sleeps a random number of seconds 
in between counts. Here, the thread is started automatically when the object is instantiated.
/** A Runnable that counts up to a specified
 *  limit with random pauses in between each count.
 
public class Counter2 implements Runnable {
  private static int totalNum = 0;
  private int currentNum, loopLimit;

  public Counter2(int loopLimit) {
    this.loopLimit = loopLimit;
    currentNum = totalNum++;
    Thread t = new Thread(this);
    t.start();
  }

  private void pause(double seconds) {
    try { Thread.sleep(Math.round(1000.0*seconds)); }
    catch(InterruptedException ie) {}
  }
  
  public void run() {
    for(int i=0; i

Template illustrating the first approach for creating a class with thread behavior.

** Taken from Core Web Programming from 
 *  Prentice Hall and Sun Microsystems Press,
  *  © 2001 Marty Hall and Larry Brown;
 *  may be freely used or adapted.
 */

public class ThreadClass extends Thread {
 public void run() {
   // Thread behavior here.
  }
}