You are here:

GSMFavorites.com > Documents > Java > Samples

Java Samples (1)

This page contains a selection of samples written in Java:

SensitivePolygon

This class is an extension to java.awt.Polygon. It knows how to draw itself, how to change color on mouse entry/exit. It can act as a source of mouse events, accepting one or more java.awt.event.MouseListener event recipients. This class requires JDK 1.1 or later.

--- SensitivePolygon.java ---
import java.awt.*;
import java.awt.event.*;
import java.util.*;


public class SensitivePolygon 
    extends Polygon 
    implements MouseMotionListener, MouseListener
{
    boolean isActive;
    Vector listeners;
    protected Color fillColor;
    protected Color lineColor;
    protected Color fillColorInside;
    protected Color lineColorInside;

    protected Component canvas;
    private   Graphics  cacheGraphics;

    /**
     * Create this sensitive polygon, with 0 points.
     * and default colors.
     */
    public SensitivePolygon(Component myCanvas) {
  super();
  isActive = false;
  listeners = new Vector();
  fillColor = Color.cyan;
  lineColor = Color.gray;
  fillColorInside = Color.blue;
  lineColorInside = Color.black;

  canvas = myCanvas;
  cacheGraphics = null;

  canvas.addMouseListener(this);
  canvas.addMouseMotionListener(this);
    }

    protected Graphics getGraphics() {
  if (cacheGraphics == null) {
      if (canvas != null) {
    cacheGraphics = canvas.getGraphics();
      }
  }
  return cacheGraphics;
    }

    /**
     * Add a mouse listener to this sensitive polygon. 
     */
    public synchronized void addMouseListener(MouseListener m) {
  listeners.addElement(m);
    }

    public synchronized void removeMouseListener(MouseListener m) {
  listeners.removeElement(m);
    }



    // ************************************************************
    public void mouseClicked(MouseEvent e) { 
  if (isActive) notifyListeners(MouseEvent.MOUSE_CLICKED, e);
    }
    public void mousePressed(MouseEvent e) {
  if (isActive) notifyListeners(MouseEvent.MOUSE_PRESSED, e);
    }
    public void mouseReleased(MouseEvent e) {
  if (isActive) notifyListeners(MouseEvent.MOUSE_RELEASED, e);
    }
    public void mouseEntered(MouseEvent e) { 
  boolean prev = isActive;
  processPoint(e.getPoint()); 
  if (isActive && !prev) 
      notifyListeners(MouseEvent.MOUSE_ENTERED, e);
    }
    public void mouseExited(MouseEvent e) { 
  boolean prev = isActive;
  processPoint(e.getPoint()); 
  if (!isActive && prev) 
      notifyListeners(MouseEvent.MOUSE_EXITED, e);
    }
    public void mouseDragged(MouseEvent e) { 
  boolean prev = isActive;
  processPoint(e.getPoint()); 
  if (!isActive && prev) 
      notifyListeners(MouseEvent.MOUSE_EXITED, e);
  if (isActive && !prev) 
      notifyListeners(MouseEvent.MOUSE_ENTERED, e);
    }
    public void mouseMoved(MouseEvent e) { 
  boolean prev = isActive;
  processPoint(e.getPoint()); 
  if (!isActive && prev) 
      notifyListeners(MouseEvent.MOUSE_EXITED, e);
  if (isActive && !prev) 
      notifyListeners(MouseEvent.MOUSE_ENTERED, e);
    }

    public void paint(Graphics g) {
  if (g != null) {
      synchronized(g) {
    Color fi = ((isActive)?(fillColorInside):(fillColor));
    Color li = ((isActive)?(lineColorInside):(lineColor));
    if (fi != null) {
        g.setColor(fi);
        g.fillPolygon(this);
    }
    if (li != null) {
        g.setColor(li);
        g.drawPolygon(this);
    }
      }
  }
  return;
    }

    protected void processPoint(Point pt) {
  if (npoints < 3) {
      isActive = false;
      return;
  }
  if (contains(pt)) {
      if (!isActive) {
    // state change, possibly do redraw as activated
    isActive = true;
    paint(getGraphics());
      }
  }
  else {
      if (isActive) {
    // state change, possibly do redraw as at rest
    isActive = false;
    paint(getGraphics());
      }
  }
    }

    protected void notifyListeners(int id, MouseEvent evt) {
  MouseListener m;
  for(Enumeration e = listeners.elements(); e.hasMoreElements(); ) {
      m = (MouseListener)(e.nextElement());
      switch (id) {
      case MouseEvent.MOUSE_PRESSED:
    m.mousePressed(evt);
    break;
      case MouseEvent.MOUSE_RELEASED:
    m.mouseReleased(evt);
    break;
      case MouseEvent.MOUSE_ENTERED:
    m.mouseEntered(evt);
    break;
      case MouseEvent.MOUSE_EXITED:
    m.mouseExited(evt);
    break;
      case MouseEvent.MOUSE_CLICKED:
    m.mouseClicked(evt);
    break;
      default:
    break;
      }
  }
  return;
    }

    /**
     * Set the fill color for the polygon when it is at rest.
     */
    public void setFillColor(Color c) { fillColor = c; }

    /**
     * Get the fill color for the polygon when it is at rest.
     */
    public Color getFillColor() { return fillColor; }

    /**
     * Set the outline color for the polygon when it is at rest.
     */
    public void setLineColor(Color c) { lineColor = c; }

    /**
     * Get the outline color for the polygon when it is at rest.
     */
    public Color getLineColor() { return lineColor; }

    /**
     * Set the fill color for the polygon when it is activated.
     */
    public void setFillColorActive(Color c) { fillColorInside = c; }

    /**
     * Get the fill color for the polygon when it is activated.
     */
    public Color getFillColorActive() { return fillColorInside; }

    /**
     * Set the outline color for the polygon when it is activated.
     */
    public void setLineColorActive(Color c) { lineColorInside = c; }

    /**
     * Get the outline color for the polygon when it is activated.
     */
    public Color getLineColorActive() { return lineColorInside; }




    static SensitivePolygon sp1, sp2, sp3;

    public static void main(String [] args) {
  Frame f;
  Canvas c;

  f = new Frame("SensitivePolygon Test");
  c = new Canvas() {
    public void paint(Graphics g) {
        super.paint(g);
        sp1.paint(g);
        sp2.paint(g);
    }
      };
  c.setBackground(Color.pink);
  c.setSize(300,300);
  f.add(c);
  f.pack();
  f.addWindowListener(new WindowAdapter() {
    public void windowClosing(WindowEvent e) {
        System.exit(0);
    }
      });

  sp1 = new SensitivePolygon(c);
  sp1.addPoint(20,30);
  sp1.addPoint(60,35);
  sp1.addPoint(120,130);
  sp1.addPoint(20,133);
  sp1.addPoint(20,30);

  sp2 = new SensitivePolygon(c);
  sp2.addPoint(200,200);
  sp2.addPoint(260,200);
  sp2.addPoint(260,240);
  sp2.addPoint(200,240);
  sp2.addPoint(200,200);
  sp2.setFillColor(Color.red);
  sp2.setLineColor(Color.black);

  sp3 = new SensitivePolygon(c);
  sp3.addPoint(0,220);
  sp3.addPoint(100,220);
  sp3.addPoint(0,290);
  sp3.addPoint(0,220);
  sp3.setFillColor(null);
  sp3.setFillColorActive(null);
  sp3.setLineColor(Color.pink);
  sp3.setLineColorActive(Color.green);

  sp2.addMouseListener(new MouseAdapter() {
    public void mouseEntered(MouseEvent e) {
        System.out.println("sp2 entered");
    }
    public void mouseExited(MouseEvent e) {
        System.out.println("sp2 exited");
    }
    public void mousePressed(MouseEvent e) {
        System.out.println("sp2 pressed");
    }
    public void mouseReleased(MouseEvent e) {
        System.out.println("sp2 released");
    }
      });
  sp1.addMouseListener(new MouseAdapter() {
    public void mouseEntered(MouseEvent e) {
        System.out.println("sp1 entered");
    }
    public void mouseExited(MouseEvent e) {
        System.out.println("sp1 exited");
    }
    public void mousePressed(MouseEvent e) {
        System.out.println("sp1 pressed");
    }
    public void mouseReleased(MouseEvent e) {
        System.out.println("sp1 released");
    }
      });

  f.show();
    }
}

DoubleHash

This class is a utility data structure that implements a 2-way associative mapping; it is essentially a hash table that allows look-up in both directions. DoubleMap is an interface which DoubleHash implements.

--- DoubleMap.java ---
import java.util.Enumeration;

/**
 * This simple interface specifies the methods for
 * data structures that implement an invertible mapping.
 */
public interface DoubleMap {
    public void insertXY(Object x, Object y);
    public Object getY(Object x);
    public Object getX(Object y);
    public boolean deleteXY(Object x, Object y);

    public Enumeration xElements();
    public Enumeration yElements();
}
--- DoubleHash.java ---
import java.util.*;

/**
 * This simple class is a quick-n-dirty implementation
 * of an invertible mapping.  It uses a pair of Hash
 * tables.
 */
public class DoubleHash implements DoubleMap, java.io.Serializable {
    private Hashtable xtab;
    private Hashtable ytab;

    public DoubleHash(int capacity) {
  xtab = new Hashtable(capacity);
  ytab = new Hashtable(capacity);
    }

    public DoubleHash() {
  this(17);
    }

    public synchronized void insertXY(Object x, Object y) {
  xtab.put(x,y);
  ytab.put(y,x);
    }

    public synchronized Object getY(Object x) {
  return xtab.get(x);
    }
    public synchronized Object getX(Object y) {
  return ytab.get(y);
    }

    public synchronized boolean deleteXY(Object x, Object y) {
  if (xtab.containsKey(x) &&
      ytab.containsKey(y) &&
      getY(x).equals(y) &&
      getX(y).equals(x))
      {
    xtab.remove(x);
    ytab.remove(y);
    return true;
      }
  else return false;
    }

    public Enumeration xElements() {
  return xtab.keys();
    }

    public Enumeration yElements() {
  return ytab.keys();
    }

    public static void main(String args[]) {
  DoubleHash dh = new DoubleHash();

  dh.insertXY("Foo","Bar");
  dh.insertXY("Here","There");
  dh.insertXY("Hello","World");
  dh.insertXY("Not","Now");
  dh.insertXY("vi","Emacs");

  Enumeration e1 = dh.xElements();
  for( ; e1.hasMoreElements(); ) {
      Object x = e1.nextElement();
      System.out.println("Map: " + x + " <--> " + dh.getY(x));
  }
    }
}

RightFormat

This class is an implementation of java.text.Format, it handles right-justified string fields. Use it in conjunction with NumberFormat and DateFormat for formatting tabular data.

--- RightFormat.java ---
import java.util.*;
import java.text.*;

public class RightFormat extends java.text.Format
{
    private int size;
    private char pad;

    public RightFormat(int fieldsize, char padchar) {
  if (fieldsize <= 1) 
      throw new IllegalArgumentException("fieldsize must be > 1");
  size = fieldsize;
  pad = padchar;
    }

    public RightFormat(int fieldsize) {
  this(fieldsize, ' ');
    }
  
    public StringBuffer format(Object obj, 
             StringBuffer toAppendTo, 
             FieldPosition pos)
    {
  String val;
  int ix;
  val = obj.toString();
  for(ix = size; ix > val.length(); ix--)
      toAppendTo.append(pad);
  toAppendTo.append(val);
  return toAppendTo;
    }

    
    public Object parseObject(String source, ParsePosition status) 
    {
  int start, end, ix;
  String ret = "";
  end = status.getIndex() + size;
  start = status.getIndex();
  for(ix = start; ix < end; ix++) {
      if (source.charAt(ix) != pad) break;
  }
  if (ix < end) {
      ret = source.substring(ix, end);
  }
  status.setIndex(end);
  return ret;
    }
}
--- TestRight.java ---
import java.text.*;

public class TestRight {
    public static void main(String args[]) {
  long f1 = 1;
  long f2 = 1;
  RightFormat rf = new RightFormat(20);

  System.out.println("Test of RightFormat(20) on Fibonacci numbers:");
  for(int ix = 0; ix < 32; ix++) {
      System.out.println(rf.format(Long.toString(f1)));
      System.out.println(rf.format(Long.toString(f2)));
      f1 = f1 + f2;
      f2 = f2 + f1;
  }
    }
}

ClockLabel

This extension to java.awt.Label provides a time-of-day clock. It is suitable for use in applications and applets, and may be used anywhere that a Label can be used.

--- ClockLabel.java ---
import java.awt.*;
import java.util.*;

class TickerThread extends Thread {
    ClockLabel c1;
    public TickerThread(ClockLabel c) {
  c1 = c;
    }
    public void run() {
  while(true) {
      try { sleep(2000); }
      catch (InterruptedException e) { break; }
      c1.updateTime();
  }
    }
}
  
/**
 * A Label subclass that offers a time-of-day clock
 * which updates every two seconds.  Use the startClock()
 * method to start keeping time, and stopClock() to stop
 * keeping time.
 */
public class ClockLabel extends Label {
    Thread ticker;

    public ClockLabel() {
  super("Clock", Label.CENTER);
  ticker = null;
    }
    public void startClock() {
  if (ticker == null) {
      ticker = new TickerThread(this);
      ticker.start();
  }
  updateTime();
    }
    public void stopClock() {
  ticker.interrupt();
  ticker = null;
    }
    public void updateTime() {
  Date now = new Date();
  String time = now.toString().substring(11,23);
  setText(time);
    }
    public static void main(String [] args) {
  Frame fr = new Frame("Clock test");
  Label l1 = new Label("THIS IS A LABEL!");
  ClockLabel c1 = new ClockLabel();
  c1.setBackground(Color.gray);
  System.out.println("Starting the clock");
  c1.startClock();
  fr.add(l1,"Center");
  fr.add(c1,"North");
  fr.pack();
  fr.show();
  try { Thread.sleep(10000); }
  catch (InterruptedException e) { }
  System.out.println("Stopping the clock");
  c1.stopClock();
  try { Thread.sleep(12000); }
  catch (InterruptedException e) { }
  System.out.println("Starting the clock again");
  c1.startClock();

    }
}

VectorSched

This class illustrates a solution to a peculiar subtype of constrained scheduling problem. Briefly, the class accepts a set of time- a set of courses to be scheduled in those time-slots, along with a set of constraints preventing certain pairs of classes from being scheduled at the same time. This solution uses mostly the java.util.Vector data structure, which was a condition imposed by the instructor of the person who originally asked me the question; certainly Vector is not ideal for supporting a program of this kind, but it works. This is an interesting example of implementing recursive search with backtracking in Java, a technique that is commonly used in teaching Lisp. The class TestVectorSched illustrates how to set up and invoke the scheduler.

--- VectorSched.java ---
import java.util.*;

public class VectorSched
{
    protected Vector courses;
    protected Vector times;
    protected Vector constraintPairs;
    protected Hashtable mySchedule;

    public VectorSched() {
  courses = new Vector();
  times = new Vector();
  // this should be done with a Hashtable or a HashMap
  constraintPairs = new Vector();
  mySchedule = new Hashtable();
    }
    
    public void addCourse(String c) {
  courses.addElement(c);
    }
    public void addTimeSlot(String t) {
  times.addElement(t);
    }
    public void addConstraint(String c1, String c2) {
  constraintPairs.addElement(c1 + "/" + c2);
  constraintPairs.addElement(c2 + "/" + c1);
    }

    protected boolean allowed(String c1, String c2) {
  return(constraintPairs.indexOf(c1 + "/" + c2) < 0);
    }

    protected boolean allowed(String c1, Vector cx) {
  for(Enumeration e = cx.elements(); e.hasMoreElements(); ) {
      String c2 = (String)(e.nextElement());
      if (!allowed(c1,c2)) return false;
  }
  return true;
    }

    protected boolean scheduleOneCourse(int cNum, int tNum) {
  /* DEBUG
  System.out.println("Trying course " + cNum + " at time " + tNum);
  */
  if (tNum >= times.size()) return false;
  String t = (String)(times.elementAt(tNum));
  if (cNum >= courses.size()) return true;
  String c = (String)(courses.elementAt(cNum));

  Vector cx = (Vector)(mySchedule.get(t));
  if (cx == null) {
      cx = new Vector();
      mySchedule.put(t,cx);
  }
  if (allowed(c,cx)) {
      cx.addElement(c);
  }
  else return false;

  int nextc = cNum + 1;
  int nextt = (tNum + 1) % times.size();
  int ix;
  boolean gotit = false;
  
  // this approach will not always yield the most 
  // well spread-out schedule
  for(ix = 0; ix < times.size(); ix++) {
      gotit = scheduleOneCourse(nextc, nextt);
      if (gotit) break;
      else nextt = (nextt + 1) % times.size();
  }

  if (!gotit) {
      cx.removeElement(c);
      return false;
  }
  else {
      return true;
  }
    }

    public boolean schedule() {
  return scheduleOneCourse(0,0);
    }

    public String toString() {
  StringBuffer buf = new StringBuffer();
  for(Enumeration e = times.elements(); e.hasMoreElements(); ) {
      String t = (String)(e.nextElement());
      Vector cx = (Vector)(mySchedule.get(t));
      buf.append("Time ");
      buf.append(t);
      buf.append(":  ");
      if (cx != null && cx.size() > 0) {
    for(Enumeration e2 = cx.elements(); e2.hasMoreElements();){
        buf.append(e2.nextElement().toString());
        buf.append("  ");
    }
      }
      else buf.append("--free--");
      buf.append("\n");
  }
  return buf.toString();
    }
}
--- TestVectorSched.java ---
public class TestVectorSched
{


    public static void main(String [] args) {
  VectorSched vs1 = new VectorSched();

  vs1.addCourse("Chemistry 101");
  vs1.addCourse("Physics 101");
  vs1.addCourse("Math 103");
  vs1.addCourse("Math 104");
  vs1.addCourse("Chemistry 207");
  vs1.addCourse("Chemistry 252");
  vs1.addCourse("Physics 204");
  vs1.addCourse("Math 202");

  vs1.addTimeSlot("morning");
  vs1.addTimeSlot("afternoon");
  vs1.addTimeSlot("night");

  vs1.addConstraint("Chemistry 101","Physics 101");
  vs1.addConstraint("Math 104","Physics 204");
  vs1.addConstraint("Math 103","Chemistry 207");
  vs1.addConstraint("Math 202","Chemistry 252");
  vs1.addConstraint("Physics 204","Chemistry 252");
  vs1.addConstraint("Physics 101","Physics 204");
  vs1.addConstraint("Physics 204","Math 202");
  vs1.addConstraint("Physics 204","Math 103");

  boolean okay = vs1.schedule();
  if (okay) {
      System.out.println("Test schedule works!\n\n" + vs1);
  }
  else {
      System.out.println("Test schedule failed.");
  }
    }
}

Dayclient

These two classes show an extremely simple example of java.net socket programming. They implement the Unix 'daytime' protocol, an extremely simple protocol that consists entirely of the server sending its current local time and date to the client as an ASCII string. The server, to keep it very simple, does not use multiple threads. This code requires JDK 1.1 or later, but can easily be adapted to JDK 1.0.

--- Dayclient.java ---
import java.io.*;
import java.net.*;

/**
 * Tiny socket client for the Unix 'daytime' protocol.
 */

public class Dayclient
{
    public static void main(String[] args)
    {
  Socket csocket;
  BufferedReader   timestream;
  if (args.length < 1) {
      System.err.println("Please supply a host name or IP address");
      System.exit(0);
  }
  try
      {
    csocket = new Socket(args[0],13);
    timestream = new BufferedReader(new InputStreamReader(csocket.getInputStream()));
    String thetime = timestream.readLine();
    System.out.println("it is "+ thetime + " at " + args[0]);

       
    csocket.close();
          
      }

  catch(IOException e)
      { System.err.println(e);}

    }
}
--- Dayserver.java ---
import java.util.Date;
import java.io.*;
import java.net.*;

/**
 * Tiny socket server for the Unix 'daytime' protocol.
 */

public class Dayserver
{
    public static void main(String[] args)
    {
  ServerSocket      theserver;
  Socket      asocket;
  PrintWriter          p;
  BufferedReader   timestream;
  Socket csocket;
 
  try
      {
    theserver = new ServerSocket(13);
    try
        { 
      while(true)
          {  
        System.out.println("Waiting for customers...");
        asocket = theserver.accept();
        p =  new PrintWriter(asocket.getOutputStream()); 
        p.println(new Date());
          

        p.close();
        asocket.close();
        // csocket.close();
        // timestream.close();
          }
        }

    catch(IOException e)
        { theserver.close();
        System.err.println(e);}

      }

  catch(IOException e)
      { System.err.println(e);}
    }
}

BinCat

The BinCat class reads raw data bytes and prints them in binary representation. This small class illustrates some simple concepts in bit manipulation and I/O streams in Java. Note that the output handling is far less efficient than it might be, in order to keep the code simple.

--- BinCat.java ---
import java.io.*;

/**
 * BinCat is a simple class for reading bytes and 
 * writting them back out in binary representation.
 */
public class BinCat {
    BufferedInputStream brIn;
    PrintStream    psOut;

    public static int BYTES_PER_LINE = 4;

    public BinCat() {
  this(System.in,System.out);
    }

    public BinCat(InputStream in, OutputStream out) {
  brIn = new BufferedInputStream(in);
  if (out instanceof PrintStream)
      psOut = (PrintStream)out;
  else
      psOut = new PrintStream(out);
    }

  

    public void doit() {
  int ch, cv, bit, cnt;
  try {
      for(cnt = 0, ch = brIn.read(); ch >= 0; ch = brIn.read()) {
    cv = ((int)ch & 0x00ff);
    for(bit = 7; bit >= 0; bit--) {
        if ((cv & (2 << bit)) > 0)
      psOut.print("1");
        else
      psOut.print("0");
    }
    cnt++;
    if ((cnt % BYTES_PER_LINE) == 0) 
        psOut.println("");
      }
  } catch (IOException e) { }
  return;
    }

    /**
     * Test main for BinCat 
     */
    public static void main(String args[]) {
  BinCat kitty;
  kitty = new BinCat();
  kitty.doit();
  System.exit(0);
    }
}

BigFib

The BigFib class computes and prints Fibonacci numbers. This small class illustrates the use of the java.math.BigInteger class in Java. This class includes a self-test, which accepts an integer from the command line and prints that many Fibonnaci numbers. This class requires JDK 1.1 or later.

--- BigFib.java ---
import java.math.BigInteger;
import java.io.*;

/**
 * BigFib is a simple class for computing Fibonacci
 * numbers, using the Java multi-precision integer
 * class java.math.BigInteger.
 */
public class BigFib {
    BigInteger last;
    BigInteger next;
    int n;

    /**
     * Create a new BigFib object, initialized to 0 on
     * the Fibonnacci sequence.
     */
    public BigFib () {
  n = 0;
  last = new BigInteger("0");
  next = new BigInteger("1");
    }
 
    /**
     * Compute c more Fibonnacci numbers, returning the
     * last one.  Ideally, c should be even and >0.
     * If you want to print the numbers too, pass printTo
     * as non-null.
     */
    public BigInteger getFib(int c, PrintStream printTo) {
  BigInteger tmp;
  for( ; c > 0; c -= 2) {
      last = last.add(next);  n++;
      if (printTo != null) printTo.println(" " + n + "\t" + last);
      next = next.add(last);  n++;
      if (printTo != null) printTo.println(" " + n + "\t" + next);
  }
  if (c == 0) return next;
  else return last;
    }

    /**
     * Default limit for self-test.
     */
    public static final int defaultLimit = 100;

    /**
     * Self-test code, accepts an integer from the
     * command line, or uses the default limit.
     */
    public static void main(String args[]) {
   BigInteger answer;

   BigFib fib = new BigFib();
   
   System.out.println("\t\t      Fibonacci sequence!");
   System.out.println("");
 
   System.out.println();
   int limit = 100;
   if (args.length > 0) {
       try { limit = Integer.parseInt(args[0]); }
       catch (NumberFormatException nfe) { 
     System.err.println("Bad number, using default " + limit);
       }
       if (limit < 1) {
     limit = defaultLimit;
     System.err.println("Limit too low, using default " + limit);
       }
   }

   answer = fib.getFib(limit, System.out);
    }
}

DualServer

This small class, and its inner classes, illustrate the use of Sockets and Datagram sockets. This class was written in response to an email question, where the questioner asked if it was possible for a single application to provide service on both TCP and UDP sockets. Of course, it is. This application provides the 'echo' service on both TCP and UDP port 7. You can test the TCP part with telnet; for testing the UDP part, use the provided DatagramTest class.

--- DualServer.java ---
import java.net.*;
import java.io.*;

/**
 * This class, and its several inner classes, provide a simple
 * echo server for TCP and UDP. 
 */
public class DualServer
{    
    protected Thread tcpThread;
    protected Thread udpThread;

    /**
     * Default port on which to provide TCP and UDP
     * echo services.
     * This is not final, so a caller could change it
     * to provide echo services on a different port.
     */
    public static int ECHO_PORT = 7;

    /** 
     * Create a DualServer object to offer echo service
     * on TCP and UDP ports on the default IP address.
     */
    public DualServer() {
  try {
      tcpThread = new StreamEchoService(ECHO_PORT);
  } catch (IOException ie) {
      System.err.println("Couldn't start TCP echo service: " + ie);
  }
  try {
      udpThread = new DatagramEchoService(ECHO_PORT);
  } catch (IOException ie) {
      System.err.println("Couldn't start UDP echo service: " + ie);
  }
    }

    /**
     * Start up this echo service.
     */
    public void start() {
  tcpThread.start();
  udpThread.start();
  return;
    }
  

    static class DatagramEchoService extends Thread
    {
  DatagramSocket ds;

  DatagramEchoService(int port) 
    throws IOException 
  {
      super("datagram service");
      ds = new DatagramSocket(port);
  }
  private static final int LEN = 65530;
  public void run() {
      DatagramPacket dp;
      dp = new DatagramPacket(new byte[LEN], LEN);
      while (true) {
    try {
        dp.setLength(LEN);
        ds.receive(dp);
        ds.send(dp);
    }
    catch (IOException e) {
        System.err.println("Exception on UDP service: " + e);
    }
      }
  }
    }

    static class StreamEchoServer extends Thread {
  private Socket s;

  public StreamEchoServer(Socket cs) {
      super("server");
      s = cs;
  }
  public void run() {
      InputStream is = null;
      OutputStream os = null;
      try {
    is = s.getInputStream();
    os = s.getOutputStream();
    byte [] buf = new byte[1024];
    int cc;
    do {
        cc = is.read(buf);
        if (cc > 0) os.write(buf, 0, cc);
    } while (cc >= 0);
      }
      catch (IOException ie) { }
      finally {
    try { is.close(); } catch (IOException ie) { }
    try { os.close(); } catch (IOException ie) { }
    try { s.close(); } catch (IOException ie) { }
      }
  }
    }

    static class StreamEchoService extends Thread
    {
  ServerSocket ss;

  StreamEchoService(int port) 
    throws IOException
  {
      super("stream service");
      ss = new ServerSocket(port);
  }

  public void run() {
      Socket cs;
      while(true) {
    try {
        cs = ss.accept();
        (new StreamEchoServer(cs)).start();
    }
    catch (IOException ie) { break; }
      }
  }
    }

    /**
     * Test main - test out the echo server on its
     * default port, or on a port specified by args[0].
     */
    public static void main(String args[]) {
  if (args.length > 0) {
      try {
    int prt = Integer.parseInt(args[0]);
    if (prt > 0 && prt < 65535)
        ECHO_PORT = prt;
      } 
      catch (Exception e) { }
  }
  System.out.println("Starting echo service on port " + ECHO_PORT);
  DualServer ds = new DualServer();
  ds.start();
  return;
    }
}
--- DatagramTest.java ---
import java.net.*;
import java.io.*;

/**
 * This small class simply provides a usable main that
 * can be used to test some kinds of datagram servers.
 * Basically, this program expects to get a host name
 * and port number on the command line.  If the port
 * number is not supplied, it defaults to 7.  The
 * program reads lines from standard input, and packages
 * up each line as a datagram packet.  After sending a
 * packet, it waits for and prints the response.  This
 * program exits on end-of-file.
 */
public class DatagramTest 
{
    public static void main(String args[]) {
  if (args.length < 1) {
      System.err.println("Usage: java DatagramTest host [port] <file");
      System.exit(0);
  }

  String host = args[0];
  int port = 7;
  if (args.length > 1) {
      try {
    port = Integer.parseInt(args[1]);
      } catch (NumberFormatException nfe) { }
  }
  
  BufferedReader br;
  br = new BufferedReader(new InputStreamReader(System.in));

  InetAddress addr = null;
  try {
      addr = InetAddress.getByName(host);
  }
  catch (UnknownHostException uhe) {
      System.err.println("No such host: " + host);
      System.exit(0);
  }

  /*
   * The approach used here, send then immediately
   * receive, will usually work, but is not totally
   * reliable.  In a very fast network, or with loopback,
   * it is possible for the response to arrive before
   * Java manages to crawl from send to receive.
   */
  DatagramSocket ds = null;
  DatagramPacket rec, send;
  String line;
  rec = new DatagramPacket(new byte[65530], 65530);
  try {
      ds = new DatagramSocket();
      while((line = br.readLine()) != null) {
    byte [] buf = line.getBytes();
    if (buf.length > 0) {
        send = new DatagramPacket(buf, buf.length, addr, port);
        rec.setLength(65530);
        ds.send(send);
        ds.receive(rec);
        line = new String(rec.getData(), 0, rec.getLength());
        System.out.println(line);
    }
      }
  }
  catch (IOException ie) {
      System.err.println("IO exception in datagram test: " + ie);
  }
  finally {
      if (ds != null) try {
    ds.close();
      } catch (Exception e) { }
  }
    }
}

HMAC Utility

This application illustrates very very simple use of the Java Cryptography Extension (JCE), as well a way to obtain simple text data off the clipboard. These classes require JDK 1.2 (Java 2) and a JSA-compliant crypto library, like Sun's JCE 1.2.

--- hmac.java ---
import java.io.*;
import java.util.*;
import java.security.*;
import java.security.interfaces.*;
import java.security.spec.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import javax.crypto.interfaces.*;
import java.awt.Toolkit;
import java.awt.datatransfer.*;

/**
 * hmac - a little utility to compute HMACs on data;
 * the data and key may be obtained from files, from
 * the command line, or from the clipboard.  Note that
 * this little program is really only suitable for
 * files of very modest length, because it attempts
 * to load the entire file into a byte array.
 * 

* This utility accepts command-line options, and * prints HMAC values in hex. *

* For more information */ public class hmac { private File keyFile; private String keyString; private byte [] keyBytes; private File dataFile; private String dataString; private byte [] dataBytes; protected Clipboard clip; protected boolean verbose = false; protected boolean noHex = false; protected boolean reverse = false; protected String alg = DEFAULT_ALG; public static final int MIN_LENGTH = 8; public static final int BUF_LENGTH = 256; public static final String DEFAULT_ALG = "HMacMD5"; /** * Send a message to the user, with an exception. */ public static final void message(String s, Exception e) { System.err.println("hmac: " + s); if (e != null) { System.err.println("\texception was: " + e); e.printStackTrace(System.err); } } /** * Send a message to the user, no exception. */ public static final void message(String s) { message(s,null); } /** * Return true if the input argument character is * a digit, a space, or A-F. */ public static final boolean isHexStringChar(char c) { return (Character.isDigit(c) || Character.isWhitespace(c) || (("0123456789abcdefABCDEF".indexOf(c)) >= 0)); } /** * Return true if the argument string seems to be a * Hex data string, like "a0 13 2f ". Whitespace is * ignored. */ public static final boolean isHex(String sampleData) { for(int i = 0; i < sampleData.length(); i++) { if (!isHexStringChar(sampleData.charAt(i))) return false; } return true; } /** * Return true if the argument byte array seems to be a * Hex data string, like "a0 13 2f ". Only check as far * as a supplied length; if it seems to be hex for that * many (ascii) bytes, then return true. */ public static final boolean isHex(byte [] sampleData, int len) { for(int i = 0; i < len; i++) { if (!isHexStringChar((char)(sampleData[i]))) return false; } return true; } static final String hexDigitChars = "0123456789abcdef"; /** * Convert a hex string into an array of bytes. * The hex string can be all digits, or 1-octet * groups separated by blanks, or any mix thereof. * * @param str String to be converted */ public static final byte [] hexToByteArray(String str, boolean rev) { StringBuffer acc = new StringBuffer(str.length() + 1); int cx, rp, ff, val; char [] s = new char[str.length()]; str.toLowerCase().getChars(0, str.length(), s, 0); for(cx = str.length() - 1, ff = 0; cx >= 0; cx--) { if (hexDigitChars.indexOf(s[cx]) >= 0) { acc.append(s[cx]); ff++; } else { if ((ff % 2) > 0) acc.append('0'); ff = 0; } } if ((ff % 2) > 0) acc.append('0'); //System.out.println("Intermediate SB value is '" + acc.toString() + "'"); byte [] ret = new byte[acc.length() / 2]; for(cx = 0, rp = ret.length - 1; cx < acc.length(); cx++, rp--) { val = hexDigitChars.indexOf(acc.charAt(cx)); cx++; val += 16 * hexDigitChars.indexOf(acc.charAt(cx)); ret[rp] = (byte)val; } if (rev) { byte tmp; int fx, bx; for(fx = 0, bx = ret.length - 1; fx < (ret.length / 2); fx++, bx--) { tmp = ret[bx]; ret[bx] = ret[fx]; ret[fx] = tmp; } } return ret; } /** * Convert a byte array to a hex string of the format * "1f 30 b7". */ public static final String byteArrayToHex(byte [] a) { int hn, ln, cx; StringBuffer buf = new StringBuffer(a.length * 2); for(cx = 0; cx < a.length; cx++) { hn = ((int)(a[cx]) & 0x00ff) / 16; ln = ((int)(a[cx]) & 0x000f); buf.append(hexDigitChars.charAt(hn)); buf.append(hexDigitChars.charAt(ln)); buf.append(' '); } return buf.toString(); } /** * Accept a file name, and read that file as a string or * as raw data (read first N bytes to check it out). * If the file can't be read, then return null. If * we can't read at least minValidLength bytes, then * we declare that the file is invalid and return null. * All the real work is done in readDataStream. * * @see readDataStream */ public byte [] readDataFile(File f, int minValidLength) { InputStream fr = null; byte [] buf = null; int cc; try { if (f.getName().equals("-")) { fr = System.in; } else { fr = new FileInputStream(f); } } catch (IOException ie) { message("Could not read file " + f, ie); return null; } if (verbose) message("Reading file data from " + f); return readDataStream(fr, minValidLength); } public byte[] readDataStream(InputStream is, int minValidLength) { int cc; byte [] buf = new byte[BUF_LENGTH]; is = new BufferedInputStream(is); try { cc = is.read(buf, 0, minValidLength); if (cc < minValidLength) return null; } catch (IOException ie) { message("Could not read initial data", ie); try { is.close(); } catch (Exception e) { } return null; } boolean ishex = (noHex)?(false):(isHex(buf, cc)); ByteArrayOutputStream baos = new ByteArrayOutputStream(); baos.write(buf, 0, cc); while (cc > 0) { try { cc = is.read(buf); if (cc > 0) baos.write(buf, 0, cc); } catch (IOException ie) { message("Error read stream data", ie); try { is.close(); } catch (Exception e) { } return null; } } try { is.close(); } catch (IOException ie2) { } byte [] result; result = baos.toByteArray(); if (verbose) message("Read " + result.length + " bytes"); if (ishex) { result = hexToByteArray(new String(result), reverse); } return result; } /** * Read hex data from the clipboard and process it into * a byte array. */ public byte [] readDataClipboard() { byte [] result = null; try { if (clip == null) { clip = Toolkit.getDefaultToolkit().getSystemClipboard(); } Transferable contents; contents = clip.getContents(null); if (contents != null) { StringReader sr; sr = (StringReader)(contents.getTransferData(DataFlavor.plainTextFlavor)); StringBuffer sb = new StringBuffer(); char [] buf = new char[BUF_LENGTH]; int cc; do { cc = sr.read(buf, 0, BUF_LENGTH); if (cc > 0) sb.append(buf, 0, cc); } while(cc > 0); String s = sb.toString(); if (verbose) message("Got clipboard data: " + s); result = s.getBytes(); boolean ishex = (noHex)?(false):(isHex(result, 16)); if (ishex) { result = hexToByteArray(s, reverse); } } } catch (Exception te) { message("Transfer clipboard problem", te); } return result; } String [] usageLines = { "java hmac [options]", "", "where options are the following:", "\t-k keydata key data as a hex string", "\t-kc get key data as hex string from the clipboard", "\t-kf file get key data from specified file", "\t-d data data to hash as a hex string", "\t-dc get data to hash as hex string from the clipboard", "\t-df file get data to hash from specified file", "\t-a alg use specified HMAC algorithm, {HMacMD5, HMacSHA1}", "\t (default is HMacMD5)", "\t-r interpret hex strings in reverse", "\t (as strings rather than numbers)", "\t-B treat ALL files as binary data", "\t-v print verbose messages", "", "If a file name is given as '-' then read standard input. If no -d", "options are given, then we read standard input.", "", "Options are interpreted in the order given, including -r and -B;", "use them with care.", "", "For files and standard input, the program will inspect", "the data and decide whether it seems to", "be binary data or hex data, unless -B is given.", "", "Here are some example command lines:", " java hmac -kc -df capture1", " java hmac -k 1f031b78a0993d42 -df - -a HMacSHA1 <myfile.dat", "", "For more information, contact Neal Ziring.", }; protected void usage() { for(int i = 0; i < usageLines.length; i++) { System.out.println(usageLines[i]); } } /** * Process the command line options for this hmac * object. The command-line syntax is documented in * the usage array; run the program with no command-line * arguments, and it will print the usage message. */ protected void processCommandLine(String [] args) { int i; String data = null; if (args.length == 0) { usage(); System.exit(0); } try { for(i = 0; i < args.length; i++) { if (args[i].equalsIgnoreCase("-k")) { data = args[++i]; if (isHex(data.getBytes(),4)) { if (verbose) message("Treating key bytes as hex."); keyBytes = hexToByteArray(data, reverse); } else { if (verbose) message("Treating key bytes as ASCII."); keyBytes = data.getBytes(); } } else if (args[i].equalsIgnoreCase("-kc")) { keyBytes = readDataClipboard(); if (keyBytes == null) { message("Clipboard is empty. No key data."); System.exit(0); } } else if (args[i].equalsIgnoreCase("-kf")) { keyFile = new File(args[++i]); keyBytes = readDataFile(keyFile, MIN_LENGTH); if (keyBytes == null) { message("No key bytes available."); System.exit(0); } } else if (args[i].equalsIgnoreCase("-d")) { data = args[++i]; if (isHex(data.getBytes(),4)) { if (verbose) message("Treating data bytes as hex."); dataBytes = hexToByteArray(data, reverse); } else { if (verbose) message("Treating data bytes as ASCII."); dataBytes = data.getBytes(); } } else if (args[i].equalsIgnoreCase("-dc")) { dataBytes = readDataClipboard(); if (dataBytes == null) { message("Clipboard is empty. No data available to hash."); System.exit(0); } } else if (args[i].equalsIgnoreCase("-df")) { dataFile = new File(args[++i]); dataBytes = readDataFile(dataFile, MIN_LENGTH); if (dataBytes == null) { message("No data bytes available from file"); System.exit(0); } } else if (args[i].equalsIgnoreCase("-a")) { alg = args[++i]; if (verbose) message("Set algorithm to " + alg); } else if (args[i].equalsIgnoreCase("-B")) { noHex = true; } else if (args[i].equalsIgnoreCase("-v")) { verbose = true; } else if (args[i].equalsIgnoreCase("-r")) { reverse = true; if (verbose) message("Hex strings will be interpreted in reverse"); } else { message("Bad option: " + args[i]); usage(); System.exit(0); } } } catch (Exception e) { message("Problem processing options", e); usage(); System.exit(0); } } /** * compute the MAC from the member arrays * keyBytes and the dataBytes. Return the MAC. */ public byte[] computeMac() { Mac hm = null; byte [] result = null; if (verbose) { message("Key data: " + byteArrayToHex(keyBytes)); message("Hash data: " + byteArrayToHex(dataBytes)); message("Algorithm: " + alg); } try { hm = Mac.getInstance(alg); Key k1 = new SecretKeySpec(keyBytes, 0, keyBytes.length, alg); hm.init(k1); result = hm.doFinal(dataBytes); } catch (Exception e) { message("Bad algorithm or crypto library problem", e); } return result; } public static void main(String args[]) { hmac h1 = new hmac(); try { Provider sp = new com.sun.crypto.provider.SunJCE(); Security.addProvider(sp); } catch (Exception e) { message("Problem loading crypto provider", e); System.exit(0); } h1.processCommandLine(args); byte [] hmac = h1.computeMac(); message("Result: " + byteArrayToHex(hmac)); System.exit(0); } }