You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-dev@axis.apache.org by st...@apache.org on 2003/01/25 20:12:54 UTC

cvs commit: xml-axis/java/src/org/apache/axis/utils tcpmon.properties tcpmon.java

stevel      2003/01/25 11:12:54

  Modified:    java/src/org/apache/axis/utils tcpmon.properties tcpmon.java
  Log:
  Changes to tcpmon, a mixture of functionality, usability and code layout
   -user specifiable delay of X milliseconds every  bytes, lets you simulate restricted bandwidth links for better client testing
  -hostname and numeric text edit boxes are charset-restricted; you can't put a char like $ or % in a hostname box, or anything other than 0-9 in a number
  -explicit import of classes, bracing around all if statements &c.
  
  Revision  Changes    Path
  1.5       +7 -0      xml-axis/java/src/org/apache/axis/utils/tcpmon.properties
  
  Index: tcpmon.properties
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/utils/tcpmon.properties,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- tcpmon.properties	30 May 2002 23:46:02 -0000	1.4
  +++ tcpmon.properties	25 Jan 2003 19:12:54 -0000	1.5
  @@ -51,3 +51,10 @@
   
   # NOTE:  in xmlFormat00, do not translate "XML"
   xmlFormat00=XML Format
  +
  +#NOTE: this is a SimpleDateFormat format string to declare the layout of date
  +#and time in the message log. It does need i18n, but not 'translation', per se.
  +dateformat00=yyyy-MM-dd HH:mm:ss
  +delay00=Simulate Slow Connection
  +delay01=Bytes per Pause
  +delay02=Delay in Milliseconds
  \ No newline at end of file
  
  
  
  1.46      +680 -149  xml-axis/java/src/org/apache/axis/utils/tcpmon.java
  
  Index: tcpmon.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/utils/tcpmon.java,v
  retrieving revision 1.45
  retrieving revision 1.46
  diff -u -r1.45 -r1.46
  --- tcpmon.java	17 Jan 2003 04:40:09 -0000	1.45
  +++ tcpmon.java	25 Jan 2003 19:12:54 -0000	1.46
  @@ -2,7 +2,7 @@
    * The Apache Software License, Version 1.1
    *
    *
  - * Copyright (c) 2001 The Apache Software Foundation.  All rights
  + * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
    * reserved.
    *
    * Redistribution and use in source and binary forms, with or without
  @@ -10,7 +10,7 @@
    * are met:
    *
    * 1. Redistributions of source code must retain the above copyright
  - *    notice, this list of conditions and the following disclaimer. 
  + *    notice, this list of conditions and the following disclaimer.
    *
    * 2. Redistributions in binary form must reproduce the above copyright
    *    notice, this list of conditions and the following disclaimer in
  @@ -18,7 +18,7 @@
    *    distribution.
    *
    * 3. The end-user documentation included with the redistribution,
  - *    if any, must include the following acknowledgment:  
  + *    if any, must include the following acknowledgment:
    *       "This product includes software developed by the
    *        Apache Software Foundation (http://www.apache.org/)."
    *    Alternately, this acknowledgment may appear in the software itself,
  @@ -26,7 +26,7 @@
    *
    * 4. The names "Axis" and "Apache Software Foundation" must
    *    not be used to endorse or promote products derived from this
  - *    software without prior written permission. For written 
  + *    software without prior written permission. For written
    *    permission, please contact apache@apache.org.
    *
    * 5. Products derived from this software may not be called "Apache",
  @@ -55,7 +55,26 @@
   package org.apache.axis.utils ;
   
   
  -import javax.swing.*;
  +import javax.swing.BorderFactory;
  +import javax.swing.Box;
  +import javax.swing.BoxLayout;
  +import javax.swing.ButtonGroup;
  +import javax.swing.JButton;
  +import javax.swing.JCheckBox;
  +import javax.swing.JFileChooser;
  +import javax.swing.JFrame;
  +import javax.swing.JLabel;
  +import javax.swing.JPanel;
  +import javax.swing.JRadioButton;
  +import javax.swing.JScrollPane;
  +import javax.swing.JSplitPane;
  +import javax.swing.JTabbedPane;
  +import javax.swing.JTable;
  +import javax.swing.JTextArea;
  +import javax.swing.JTextField;
  +import javax.swing.ListSelectionModel;
  +import javax.swing.SwingConstants;
  +import javax.swing.UIManager;
   import javax.swing.border.TitledBorder;
   import javax.swing.event.ChangeEvent;
   import javax.swing.event.ListSelectionEvent;
  @@ -64,7 +83,16 @@
   import javax.swing.table.DefaultTableModel;
   import javax.swing.table.TableColumn;
   import javax.swing.table.TableModel;
  -import java.awt.*;
  +import javax.swing.text.AttributeSet;
  +import javax.swing.text.BadLocationException;
  +import javax.swing.text.Document;
  +import javax.swing.text.PlainDocument;
  +import java.awt.BorderLayout;
  +import java.awt.Color;
  +import java.awt.Component;
  +import java.awt.Dimension;
  +import java.awt.GridBagConstraints;
  +import java.awt.GridBagLayout;
   import java.awt.event.ActionEvent;
   import java.awt.event.ActionListener;
   import java.awt.event.WindowEvent;
  @@ -87,26 +115,41 @@
   
   
   /**
  + * TCP monitor to log http messages and responses, both SOAP and plain HTTP.
    * @author Doug Davis (dug@us.ibm.com)
  + * @author Steve Loughran
    */
   
   public class tcpmon extends JFrame {
       private JTabbedPane  notebook = null ;
   
  -    private static int STATE_COLUMN    = 0 ;
  -    private static int TIME_COLUMN     = 1 ;
  -    private static int INHOST_COLUMN   = 2 ;
  -    private static int OUTHOST_COLUMN  = 3 ;
  -    private static int REQ_COLUMN      = 4 ;
  +    private static final int STATE_COLUMN    = 0 ;
  +    private static final int TIME_COLUMN     = 1 ;
  +    private static final int INHOST_COLUMN   = 2 ;
  +    private static final int OUTHOST_COLUMN  = 3 ;
  +    private static final int REQ_COLUMN      = 4 ;
   
  +
  +    private static final String DEFAULT_HOST="127.0.0.1";
  +    private static final int    DEFAULT_PORT=8080;
  +
  +    /**
  +     * this is the admin page
  +     */
       class AdminPage extends JPanel {
           public JRadioButton  listenerButton, proxyButton ;
           public JLabel        hostLabel, tportLabel;
  -        public JTextField    port, host, tport ;
  +        public NumberField  port;
  +        public HostnameField host;
  +        public NumberField  tport ;
           public JTabbedPane   noteb ;
           public JCheckBox     HTTPProxyBox ;
  -        public JTextField    HTTPProxyHost, HTTPProxyPort ;
  +        public HostnameField    HTTPProxyHost;
  +        public NumberField HTTPProxyPort ;
           public JLabel        HTTPProxyHostLabel, HTTPProxyPortLabel ;
  +        public JLabel        delayTimeLabel, delayBytesLabel;
  +        public NumberField delayTime, delayBytes;
  +        public JCheckBox     delayBox;
   
           public AdminPage( JTabbedPane notebook, String name ) {
               JPanel     mainPane  = null ;
  @@ -137,7 +180,7 @@
   
               c.anchor    = GridBagConstraints.WEST ;
               c.gridwidth = GridBagConstraints.REMAINDER ;
  -            tmpPanel.add( port = new JTextField(4), c );
  +            tmpPanel.add( port = new NumberField(4), c );
   
               mainPane.add( tmpPanel, c );
   
  @@ -182,7 +225,9 @@
   
               c.anchor    = GridBagConstraints.WEST ;
               c.gridwidth = GridBagConstraints.REMAINDER ;
  -            mainPane.add( host = new JTextField(30), c );
  +            host = new HostnameField(30);
  +            mainPane.add( host, c );
  +            host.setText(DEFAULT_HOST);
   
               c.anchor    = GridBagConstraints.WEST ;
               c.gridwidth = 1 ;
  @@ -191,7 +236,9 @@
   
               c.anchor    = GridBagConstraints.WEST ;
               c.gridwidth = GridBagConstraints.REMAINDER ;
  -            mainPane.add( tport = new JTextField(4), c );
  +            tport = new NumberField(4);
  +            mainPane.add( tport, c );
  +            tport.setValue(DEFAULT_PORT);
   
               // Act as proxy section
               ///////////////////////////////////////////////////////////////////
  @@ -246,7 +293,7 @@
   
               c.anchor    = GridBagConstraints.WEST ;
               c.gridwidth = GridBagConstraints.REMAINDER ;
  -            opts.add( HTTPProxyHost = new JTextField(30), c );
  +            opts.add( HTTPProxyHost = new HostnameField(30), c );
               HTTPProxyHost.setEnabled( false );
   
               c.anchor    = GridBagConstraints.WEST ;
  @@ -256,7 +303,7 @@
   
               c.anchor    = GridBagConstraints.WEST ;
               c.gridwidth = GridBagConstraints.REMAINDER ;
  -            opts.add( HTTPProxyPort = new JTextField(4), c );
  +            opts.add( HTTPProxyPort = new NumberField(4), c );
               HTTPProxyPort.setEnabled( false );
   
               HTTPProxyBox.addActionListener( new ActionListener() {
  @@ -271,15 +318,15 @@
                               HTTPProxyPortLabel.setForeground( color );
                           }
                       }
  -                    ;
                   }
               );
   
               // Set default proxy values...
               String tmp = System.getProperty( "http.proxyHost" );
   
  -            if ( tmp != null && tmp.equals("") )
  +            if ( tmp != null && tmp.equals("") ) {
                   tmp = null ;
  +            }
   
               HTTPProxyBox.setSelected( tmp != null );
               HTTPProxyHost.setEnabled( tmp != null );
  @@ -291,11 +338,61 @@
                   HTTPProxyBox.setSelected( true );
                   HTTPProxyHost.setText( tmp );
                   tmp = System.getProperty( "http.proxyPort" );
  -                if ( tmp != null && tmp.equals("") ) tmp = null ;
  -                if ( tmp == null ) tmp = "80" ;
  +                if ( tmp != null && tmp.equals("") ) {
  +                    tmp = null ;
  +                }
  +                if ( tmp == null ) {
  +                    tmp = "80" ;
  +                }
                   HTTPProxyPort.setText( tmp );
               }
   
  +            //add byte delay fields
  +            opts.add(Box.createRigidArea(new Dimension(1, 10)), c);
  +            c.anchor = GridBagConstraints.WEST;
  +            c.gridwidth = GridBagConstraints.REMAINDER;
  +            final String delaySupport = getMessage("delay00", "Simulate Slow Connection");
  +            opts.add(delayBox = new JCheckBox(delaySupport), c);
  +
  +            //bytes per pause
  +            c.anchor = GridBagConstraints.WEST;
  +            c.gridwidth = 1;
  +            delayBytesLabel=new JLabel(getMessage("delay01",  "Bytes per Pause"));
  +            opts.add(delayBytesLabel, c);
  +            delayBytesLabel.setForeground(Color.gray);
  +            c.anchor = GridBagConstraints.WEST;
  +            c.gridwidth = GridBagConstraints.REMAINDER;
  +            opts.add(delayBytes = new NumberField(6), c);
  +            delayBytes.setEnabled(false);
  +
  +            //delay interval
  +            c.anchor = GridBagConstraints.WEST;
  +            c.gridwidth = 1;
  +            delayTimeLabel = new JLabel(getMessage("delay02", "Delay in Milliseconds"));
  +            opts.add(delayTimeLabel, c);
  +            delayTimeLabel.setForeground(Color.gray);
  +            c.anchor = GridBagConstraints.WEST;
  +            c.gridwidth = GridBagConstraints.REMAINDER;
  +            opts.add(delayTime = new NumberField(6), c);
  +            delayTime.setEnabled(false);
  +
  +            //enabler callback
  +            delayBox.addActionListener(new ActionListener() {
  +                public void actionPerformed(ActionEvent event) {
  +                    if (delaySupport.equals(event.getActionCommand())) {
  +                        boolean b = delayBox.isSelected();
  +                        Color color = b ? Color.black : Color.gray;
  +
  +                        delayBytes.setEnabled(b);
  +                        delayTime.setEnabled(b);
  +                        delayBytesLabel.setForeground(color);
  +                        delayTimeLabel.setForeground(color);
  +                    }
  +                }
  +                ;
  +            }
  +            );
  +
               // Spacer
               //////////////////////////////////////////////////////////////////
               mainPane.add( Box.createRigidArea(new Dimension(1, 10)), c );
  @@ -317,29 +414,44 @@
                           if ( add.equals(event.getActionCommand()) ) {
                               String   text ;
                               Listener l = null ;
  -                            int      lPort = Integer.parseInt(port.getText());
  +                            int      lPort;
  +                            lPort=port.getValue(0);
  +                            if(lPort==0) {
  +                                //no port, button does nothing
  +                                return;
  +                            }
                               String   tHost = host.getText();
                               int      tPort = 0 ;
  -
  -                            text = tport.getText();
  -                            if ( text != null && !text.equals("") )
  -                                tPort = Integer.parseInt(text);
  +                            tPort=tport.getValue(0);
  +                            SlowLinkSimulator slowLink=null;
  +                            if(delayBox.isSelected()) {
  +                                int bytes= delayBytes.getValue(0);
  +                                int time = delayTime.getValue(0);
  +                                slowLink=new SlowLinkSimulator(bytes,time);
  +                            }
                               l = new Listener( noteb, null, lPort, tHost, tPort,
  -                                proxyButton.isSelected() );
  +                                           proxyButton.isSelected(), slowLink);
   
                               // Pick-up the HTTP Proxy settings
                               ///////////////////////////////////////////////////
                               text = HTTPProxyHost.getText();
  -                            if ( "".equals(text) ) text = null ;
  +                            if ( "".equals(text) ) {
  +                                text = null ;
  +                            }
                               l.HTTPProxyHost = text ;
                               text = HTTPProxyPort.getText();
  -                            if ( "".equals(text) ) text = null ;
  -                            if ( text != null )
  +                            int proxyPort=HTTPProxyPort.getValue(-1);
  +                            if(proxyPort!=-1) {
                                   l.HTTPProxyPort = Integer.parseInt(text);
  -
  +                            }
  +                            //reset the port
                               port.setText(null);
  +
  +                            /* but not, any more, the target port and host
  +                               values
                               host.setText(null);
                               tport.setText(null);
  +                            */
                           }
                       }
                       ;
  @@ -350,8 +462,14 @@
               notebook.repaint();
               notebook.setSelectedIndex( notebook.getTabCount() - 1 );
           }
  +
  +
       }
   
  +    /**
  +     * wait for incoming connections, spawn a connection thread when
  +     * stuff comes in.
  +     */
       class SocketWaiter extends Thread {
           ServerSocket  sSocket = null ;
           Listener      listener ;
  @@ -372,12 +490,13 @@
                   for (; ; ) {
                       Socket inSocket = sSocket.accept();
   
  -                    if ( pleaseStop ) break ;
  +                    if ( pleaseStop ) {
  +                        break ;
  +                    }
                       new Connection( listener, inSocket );
                       inSocket = null ;
                   }
  -            }
  -            catch ( Exception exp ) {
  +            } catch ( Exception exp ) {
                   if ( !"socket closed".equals(exp.getMessage()) ) {
                       JLabel tmp = new JLabel( exp.toString() );
   
  @@ -389,19 +508,109 @@
               }
           }
   
  +        /**
  +         * force a halt by connecting to self and then closing the server socket
  +         */
           public void halt() {
               try {
                   pleaseStop = true ;
                   new Socket( "127.0.0.1", port );
  -                if ( sSocket != null ) sSocket.close();
  -            }
  -            catch ( Exception e ) {
  +                if ( sSocket != null ) {
  +                    sSocket.close();
  +                }
  +            } catch ( Exception e ) {
                   e.printStackTrace();
               }
           }
       }
   
   
  +    /**
  +     * class to simulate slow connections by slowing down the system
  +     */
  +    static class SlowLinkSimulator {
  +        private int delayBytes;
  +        private int delayTime;
  +        private int currentBytes;
  +        private int totalBytes;
  +
  +        /**
  +         * construct
  +         * @param delayBytes bytes per delay; set to 0 for no delay
  +         * @param delayTime delay time per delay in milliseconds
  +         */
  +        public SlowLinkSimulator(int delayBytes, int delayTime) {
  +            this.delayBytes = delayBytes;
  +            this.delayTime = delayTime;
  +        }
  +
  +        /**
  +         * construct by copying delay bytes and time, but not current
  +         * count of bytes
  +         * @param that source of data
  +         */
  +        public SlowLinkSimulator(SlowLinkSimulator that) {
  +            this.delayBytes=that.delayBytes;
  +            this.delayTime=that.delayTime;
  +        }
  +
  +        /**
  +         * how many bytes have gone past?
  +         * @return
  +         */
  +        public int getTotalBytes() {
  +            return totalBytes;
  +        }
  +
  +        /**
  +         * log #of bytes pumped. Will pause when necessary. This method is not
  +         * synchronized
  +         * @param bytes
  +         */
  +        public void pump(int bytes) {
  +            totalBytes+=bytes;
  +            if(delayBytes==0) {
  +                //when not delaying, we are just a byte counter
  +                return;
  +            }
  +            currentBytes += bytes;
  +            if(currentBytes>delayBytes) {
  +                //we have overshot. lets find out how far
  +                int delaysize=currentBytes/delayBytes;
  +                long delay=delaysize*(long)delayTime;
  +                //move byte counter down to the remainder of bytes
  +                currentBytes=currentBytes%delayBytes;
  +                //now wait
  +                try {
  +                    Thread.sleep(delay);
  +                } catch (InterruptedException e) {
  +                    ; //ignore the exception
  +                }
  +            }
  +        }
  +
  +        /**
  +         * get the current byte count
  +         * @return
  +         */
  +        public int getCurrentBytes() {
  +            return currentBytes;
  +        }
  +
  +        /**
  +         * set the current byte count
  +         * @param currentBytes
  +         */
  +        public void setCurrentBytes(int currentBytes) {
  +            this.currentBytes = currentBytes;
  +        }
  +
  +    }
  +
  +    /**
  +     * this class handles the pumping of data from the incoming socket to the
  +     * outgoing socket
  +     */
       class SocketRR extends Thread {
           Socket        inSocket  = null ;
           Socket        outSocket  = null ;
  @@ -414,11 +623,12 @@
           int           tableIndex = 0 ;
           String type = null;
           Connection    myConnection = null;
  +        SlowLinkSimulator slowLink;
   
           public SocketRR(Connection c, Socket inputSocket, InputStream inputStream,
               Socket outputSocket, OutputStream outputStream,
               JTextArea _textArea, boolean format,
  -            TableModel tModel, int index, final String type) {
  +            TableModel tModel, int index, final String type, SlowLinkSimulator slowLink) {
               inSocket = inputSocket ;
               in       = inputStream ;
               outSocket = outputSocket ;
  @@ -429,6 +639,7 @@
               tableIndex = index ;
               this.type = type;
               myConnection = c;
  +            this.slowLink= slowLink;
               start();
           }
   
  @@ -458,42 +669,56 @@
                       String tmpStr = (String) tmodel.getValueAt(tableIndex,
                               REQ_COLUMN);
   
  -                    if ( !"".equals(tmpStr) )
  +                    if ( !"".equals(tmpStr) ) {
                           reqSaved = tmpStr.length();
  +                    }
                   }
   
  -                a:
  +            a:
                   for ( ; ; ) {
  -                    if ( done ) break;
  +                    if ( done ) {
  +                        break;
  +                    }
                       //try{
                       //len = in.available();
                       //}catch(Exception e){len=0;}
                       len = buffer.length ;
  -                    // Used to be 1, but if we block it doesn't matter 
  +                    // Used to be 1, but if we block it doesn't matter
                       // however 1 will break with some servers, including apache
  -                    if ( len == 0 ) len = buffer.length;
  -                    if ( saved + len > buffer.length) len = buffer.length - saved ;
  +                    if ( len == 0 ) {
  +                        len = buffer.length;
  +                    }
  +                    if ( saved + len > buffer.length) {
  +                        len = buffer.length - saved ;
  +                    }
                       int len1 = 0;
   
                       while ( len1 == 0 ) {
                           try {
                               len1 = in.read(buffer, saved, len);
  -                        } 
  +                        }
                           catch ( Exception ex ) {
  -                            if ( done && saved == 0  ) break a;
  +                            if ( done && saved == 0  ) {
  +                                break a;
  +                            }
                               len1 = -1;
                               break;
                           }
                       }
                       len = len1;
   
  -                    if ( len == -1 && saved == 0 ) break ;
  -                    if ( len == -1) done = true;
  +                    if ( len == -1 && saved == 0 ) {
  +                        break ;
  +                    }
  +                    if ( len == -1) {
  +                        done = true;
  +                    }
   
                       // No matter how we may (or may not) format it, send it
                       // on unformatted - we don't want to mess with how its
                       // sent to the other side, just how its displayed
                       if ( out != null && len > 0 ) {
  +                        slowLink.pump(len);
                           out.write( buffer, saved, len );
                       }
   
  @@ -502,8 +727,9 @@
                                   REQ_COLUMN);
   
                           old = old + new String(buffer, saved, len);
  -                        if ( old.length() > 50 )
  +                        if ( old.length() > 50 ) {
                               old = old.substring(0, 50);
  +                        }
   
                           reqSaved = old.length();
   
  @@ -520,7 +746,9 @@
                           boolean inXML = false ;
                           int     bufferLen = saved ;
   
  -                        if ( len != -1 ) bufferLen += len ;
  +                        if ( len != -1 ) {
  +                            bufferLen += len ;
  +                        }
                           i1 = 0 ;
                           i2 = 0 ;
                           saved = 0 ;
  @@ -537,8 +765,9 @@
                                   inXML = true ;
                               }
                               if ( buffer[i1] == '<' && buffer[i1 + 1] == '/' ) {
  -                                if (previousIndent > nextIndent)
  +                                if (previousIndent > nextIndent) {
                                       thisIndent = nextIndent;
  +                                }
                                   previousIndent = nextIndent--;
                                   inXML = true ;
                               }
  @@ -547,9 +776,12 @@
                                   inXML = true ;
                               }
                               if ( thisIndent != -1 ) {
  -                                if ( thisIndent > 0 ) tmpbuffer[i2++] = (byte) '\n';
  -                                for ( i = tabWidth * thisIndent; i > 0; i-- )
  +                                if ( thisIndent > 0 ) {
  +                                    tmpbuffer[i2++] = (byte) '\n';
  +                                }
  +                                for ( i = tabWidth * thisIndent; i > 0; i-- ) {
                                       tmpbuffer[i2++] = (byte) ' ';
  +                                }
                               }
                               atMargin = ( buffer[i1] == '\n' || buffer[i1] == '\r');
   
  @@ -561,8 +793,9 @@
                           textArea.append( new String( tmpbuffer, 0, i2 ) );
   
                           // Shift saved bytes to the beginning
  -                        for ( i = 0 ; i < saved ; i++ )
  +                        for ( i = 0 ; i < saved ; i++ ) {
                               buffer[i] = buffer[bufferLen - saved + i];
  +                        }
                       }
                       else {
                           textArea.append( new String( buffer, 0, len ) );
  @@ -584,18 +817,24 @@
                   try {
                       if (out != null) {
                           out.flush();
  -                        if (null != outSocket) outSocket.shutdownOutput();
  -                        else out.close();
  +                        if (null != outSocket) {
  +                            outSocket.shutdownOutput();
  +                        } else {
  +                            out.close();
  +                        }
                           out = null;
                       }
  -                } 
  +                }
                   catch (Exception e) {
                       ;
                   }
                   try {
                       if (in != null) {
  -                        if (inSocket != null) inSocket.shutdownInput();
  -                        else in.close();
  +                        if (inSocket != null) {
  +                            inSocket.shutdownInput();
  +                        } else {
  +                            in.close();
  +                        }
                           in = null;
                       }
                   }
  @@ -608,16 +847,24 @@
   
           public  void halt() {
               try {
  -                if ( inSocket != null )  inSocket.close();
  -                if ( outSocket != null ) outSocket.close();
  +                if ( inSocket != null ) {
  +                    inSocket.close();
  +                }
  +                if ( outSocket != null ) {
  +                    outSocket.close();
  +                }
                   inSocket  = null ;
                   outSocket = null ;
  -                if ( in != null ) in.close();
  -                if ( out != null ) out.close();
  +                if ( in != null ) {
  +                    in.close();
  +                }
  +                if ( out != null ) {
  +                    out.close();
  +                }
                   in = null ;
                   out = null ;
                   done = true;
  -            } 
  +            }
               catch ( Exception e ) {
                   e.printStackTrace();
               }
  @@ -625,6 +872,9 @@
       }
   
   
  +    /**
  +     * a connection listens to a single current connection
  +     */
       class Connection extends Thread {
           Listener     listener ;
           boolean      active ;
  @@ -644,11 +894,13 @@
   
           String       HTTPProxyHost = null ;
           int          HTTPProxyPort = 80 ;
  +        private SlowLinkSimulator slowLink;
   
           public Connection(Listener l) {
               listener = l ;
               HTTPProxyHost = l.HTTPProxyHost ;
               HTTPProxyPort = l.HTTPProxyPort ;
  +            slowLink =l.slowLink;
           }
   
           public Connection(Listener l, Socket s ) {
  @@ -668,33 +920,42 @@
                   active        = true ;
   
                   HTTPProxyHost = System.getProperty( "http.proxyHost" );
  -                if ( HTTPProxyHost != null && HTTPProxyHost.equals("") )
  +                if ( HTTPProxyHost != null && HTTPProxyHost.equals("") ) {
                       HTTPProxyHost = null ;
  +                }
   
                   if ( HTTPProxyHost != null ) {
                       String tmp = System.getProperty( "http.proxyPort" );
   
  -                    if ( tmp != null && tmp.equals("") ) tmp = null ;
  -                    if ( tmp == null ) HTTPProxyPort = 80 ;
  -                    else HTTPProxyPort = Integer.parseInt( tmp );
  +                    if ( tmp != null && tmp.equals("") ) {
  +                        tmp = null ;
  +                    }
  +                    if ( tmp == null ) {
  +                        HTTPProxyPort = 80 ;
  +                    } else {
  +                        HTTPProxyPort = Integer.parseInt( tmp );
  +                    }
                   }
   
  -                if ( inSocket != null )
  +                if ( inSocket != null ) {
                       fromHost = (inSocket.getInetAddress()).getHostName();
  -                else
  +                } else {
                       fromHost = "resend" ;
  +                }
  +
   
  -                DateFormat   df = new SimpleDateFormat("MM/dd/yy hh:mm:ss aa");
  +                String dateformat=getMessage("dateformat00", "yyyy-MM-dd HH:mm:ss");
  +                DateFormat   df = new SimpleDateFormat(dateformat);
   
                   time = df.format( new Date() );
   
                   int count = listener.connections.size();
   
  -                listener.tableModel.insertRow(count + 1, new Object[] { 
  +                listener.tableModel.insertRow(count + 1, new Object[] {
                           getMessage("active00", "Active"),
                           time,
                           fromHost,
  -                        listener.hostField.getText(), "" 
  +                        listener.hostField.getText(), ""
                       }
                   );
                   listener.connections.add( this );
  @@ -729,11 +990,13 @@
                   InputStream  tmpIn2  = null ;
                   OutputStream tmpOut2 = null ;
   
  -                if ( tmpIn1 == null )
  +                if ( tmpIn1 == null ) {
                       tmpIn1  = inSocket.getInputStream();
  +                }
   
  -                if ( inSocket != null )
  +                if ( inSocket != null ) {
                       tmpOut1 = inSocket.getOutputStream();
  +                }
   
                   String         bufferedData = null ;
                   StringBuffer   buf = null ;
  @@ -751,10 +1014,14 @@
                           int len ;
   
                           len = tmpIn1.read(b, 0, 1);
  -                        if ( len == -1 ) break ;
  +                        if ( len == -1 ) {
  +                            break ;
  +                        }
                           s = new String( b );
                           buf.append( s );
  -                        if ( b[0] != '\n' ) continue ;
  +                        if ( b[0] != '\n' ) {
  +                            continue ;
  +                        }
                           break ;
                       }
   
  @@ -767,16 +1034,22 @@
                           URL  url ;
   
                           start = bufferedData.indexOf( ' ' ) + 1;
  -                        while ( bufferedData.charAt(start) == ' ' ) start++ ;
  +                        while ( bufferedData.charAt(start) == ' ' ) {
  +                            start++ ;
  +                        }
                           end   = bufferedData.indexOf( ' ', start );
                           String urlString = bufferedData.substring( start, end );
   
  -                        if ( urlString.charAt(0) == '/' ) urlString = urlString.substring(1);
  +                        if ( urlString.charAt(0) == '/' ) {
  +                            urlString = urlString.substring(1);
  +                        }
                           if ( listener.isProxyBox.isSelected() ) {
                               url = new URL( urlString );
                               targetHost = url.getHost();
                               targetPort = url.getPort();
  -                            if ( targetPort == -1 ) targetPort = 80 ;
  +                            if ( targetPort == -1 ) {
  +                                targetPort = 80 ;
  +                            }
   
                               listener.tableModel.setValueAt( targetHost, index + 1,
                                   OUTHOST_COLUMN );
  @@ -791,15 +1064,15 @@
                               listener.tableModel.setValueAt( targetHost, index + 1,
                                   OUTHOST_COLUMN );
                               bufferedData = bufferedData.substring( 0, start) +
  -                            url.toExternalForm() +
  -                            bufferedData.substring( end );
  +                                url.toExternalForm() +
  +                                bufferedData.substring( end );
   
                               targetHost = HTTPProxyHost ;
                               targetPort = HTTPProxyPort ;
                           }
   
                       }
  -                } 
  +                }
                   else {
                       //
                       // Change Host: header to point to correct host
  @@ -814,12 +1087,14 @@
                           int len ;
   
                           len = tmpIn1.read(b1, 0, 1);
  -                        if ( len == -1 )
  +                        if ( len == -1 ) {
                               break ;
  +                        }
                           s1 = new String( b1 );
                           buf.append( s1 );
  -                        if ( b1[0] != '\n' )
  +                        if ( b1[0] != '\n' ) {
                               continue ;
  +                        }
                           // we have a complete line
                           String line = buf.toString();
   
  @@ -833,14 +1108,19 @@
                               break ;
                           }
                           // add it to our headers so far
  -                        if (bufferedData == null)
  +                        if (bufferedData == null) {
                               bufferedData = line;
  -                        else
  +                        } else {
                               bufferedData = bufferedData.concat(line);
  +                        }
   
                           // failsafe
  -                        if (line.equals("\r\n")) break;
  -                        if ("\n".equals(lastLine) && line.equals("\n")) break ;
  +                        if (line.equals("\r\n")) {
  +                            break;
  +                        }
  +                        if ("\n".equals(lastLine) && line.equals("\n")) {
  +                            break ;
  +                        }
                           lastLine = line ;
                       }
                       if ( bufferedData != null ) {
  @@ -849,16 +1129,20 @@
                           s1 = bufferedData.substring( 0, idx );
                           int i = s1.indexOf('\n');
   
  -                        if ( i > 0 ) s1 = s1.substring(0, i - 1);
  +                        if ( i > 0 ) {
  +                            s1 = s1.substring(0, i - 1);
  +                        }
                           s1 = s1 + "                           " +
  -                        "                       ";
  +                                  "                       ";
                           s1 = s1.substring(0, 51);
                           listener.tableModel.setValueAt( s1, index + 1,
                               REQ_COLUMN );
                       }
                   }
   
  -                if ( targetPort == -1 ) targetPort = 80 ;
  +                if ( targetPort == -1 ) {
  +                    targetPort = 80 ;
  +                }
                   outSocket = new Socket(targetHost, targetPort );
   
                   tmpIn2  = outSocket.getInputStream();
  @@ -866,25 +1150,30 @@
   
                   if ( bufferedData != null ) {
                       byte[] b = bufferedData.getBytes();
  -
                       tmpOut2.write( b );
  +                    slowLink.pump(b.length);
                   }
   
                   boolean format = listener.xmlFormatBox.isSelected();
   
  +
  +                //this is the channel to the endpoint
                   rr1 = new SocketRR(this, inSocket, tmpIn1, outSocket,
                       tmpOut2, inputText, format,
  -                    listener.tableModel, index + 1, "request:" );
  +                    listener.tableModel, index + 1, "request:", slowLink);
  +                //create the response slow link from the inbound slow link
  +                SlowLinkSimulator responseLink = new SlowLinkSimulator(slowLink);
  +                //this is the channel from the endpoint
                   rr2 = new SocketRR( this, outSocket, tmpIn2, inSocket,
                       tmpOut1, outputText, format,
  -                    null, 0, "response:" );
  +                    null, 0, "response:", responseLink);
   
                   while ( rr1 != null || rr2 != null ) {
                       // Only loop as long as the connection to the target
                       // machine is available - once that's gone we can stop.
                       // The old way, loop until both are closed, left us
                       // looping forever since no one closed the 1st one.
  -                    // while( !rr2.isDone() ) 
  +                    // while( !rr2.isDone() )
                       if (null != rr1 && rr1.isDone()) {
                           if ( index >= 0  && rr2 != null) {
                               listener.tableModel.setValueAt(getMessage("resp00", "Resp"),
  @@ -933,11 +1222,17 @@
                   PrintWriter  wr = new PrintWriter(st);
                   int index = listener.connections.indexOf( this );
   
  -                if ( index >= 0 )
  +                if ( index >= 0 ) {
                       listener.tableModel.setValueAt( getMessage("error00", "Error"), 1 + index, STATE_COLUMN );
  +                }
                   e.printStackTrace(wr);
                   wr.close();
  -                outputText.append( st.toString() );
  +                if(outputText!=null) {
  +                    outputText.append( st.toString() );
  +                } else {
  +                    //something went wrong before we had the output area
  +                    System.out.println(st.toString());
  +                }
                   halt();
               }
           }
  @@ -948,11 +1243,19 @@
   
           public void halt() {
               try {
  -                if ( rr1 != null ) rr1.halt();
  -                if ( rr2 != null ) rr2.halt();
  -                if ( inSocket  != null ) inSocket.close();
  +                if ( rr1 != null ) {
  +                    rr1.halt();
  +                }
  +                if ( rr2 != null ) {
  +                    rr2.halt();
  +                }
  +                if ( inSocket  != null ) {
  +                    inSocket.close();
  +                }
                   inSocket = null ;
  -                if ( outSocket != null ) outSocket.close();
  +                if ( outSocket != null ) {
  +                    outSocket.close();
  +                }
                   outSocket = null ;
               }
               catch ( Exception e ) {
  @@ -977,6 +1280,9 @@
       }
   
   
  +    /**
  +     * this is one of the tabbed panels that acts as the actual proxy
  +     */
       class Listener extends JPanel {
           public  Socket      inputSocket     = null ;
           public  Socket      outputSocket    = null ;
  @@ -1002,15 +1308,36 @@
           public  JTabbedPane notebook        = null ;
           public  String      HTTPProxyHost   = null ;
           public  int         HTTPProxyPort   = 80 ;
  -
  -        final public Vector connections = new Vector();
  -
  +        public  int         delayBytes      = 0;
  +        public  int         delayTime       = 0;
  +        public SlowLinkSimulator slowLink;
  +
  +        public final Vector connections = new Vector();
  +
  +        /**
  +         * create a listener
  +         * @param _notebook
  +         * @param name
  +         * @param listenPort
  +         * @param host
  +         * @param targetPort
  +         * @param isProxy
  +         * @param slowLink optional reference to a slow connection
  +         */
           public Listener(JTabbedPane _notebook, String name,
               int listenPort, String host, int targetPort,
  -            boolean isProxy) {
  +            boolean isProxy, SlowLinkSimulator slowLink) {
               notebook = _notebook ;
  -            if ( name == null ) name = getMessage("port01", "Port") + " " + listenPort ;
  -
  +            if ( name == null ) {
  +                name = getMessage("port01", "Port") + " " + listenPort ;
  +            }
  +            //set the slow link to the passed down link
  +            if(slowLink!=null) {
  +                this.slowLink=slowLink;
  +            } else {
  +                //or make up a no-op one.
  +                this.slowLink=new SlowLinkSimulator(0,0);
  +            }
               this.setLayout( new BorderLayout() );
   
               // 1st component is just a row of labels and 1-line entry fields
  @@ -1054,8 +1381,12 @@
   
               stopButton.addActionListener( new ActionListener() {
                       public void actionPerformed(ActionEvent event) {
  -                        if ( getMessage("stop00", "Stop").equals(event.getActionCommand()) ) stop();
  -                        if ( start.equals(event.getActionCommand()) ) start();
  +                        if ( getMessage("stop00", "Stop").equals(event.getActionCommand()) ) {
  +                            stop();
  +                        }
  +                        if ( start.equals(event.getActionCommand()) ) {
  +                            start();
  +                        }
                       }
                   }
               );
  @@ -1090,7 +1421,9 @@
   
               sel.addListSelectionListener( new ListSelectionListener() {
                       public void valueChanged(ListSelectionEvent event) {
  -                        if (event.getValueIsAdjusting()) return ;
  +                        if (event.getValueIsAdjusting()) {
  +                            return ;
  +                        }
                           ListSelectionModel m = (ListSelectionModel) event.getSource();
                           int divLoc = outPane.getDividerLocation();
   
  @@ -1138,11 +1471,11 @@
                           }
                           outPane.setDividerLocation(divLoc);
                       }
  -                } 
  +                }
               );
  -            tableModel.addRow( new Object[] { 
  -                    "---", getMessage("mostRecent00", "Most Recent"), "---", "---", "---" 
  -                } 
  +            tableModel.addRow( new Object[] {
  +                    "---", getMessage("mostRecent00", "Most Recent"), "---", "---", "---"
  +                }
               );
   
               JPanel  tablePane = new JPanel();
  @@ -1168,7 +1501,9 @@
               removeButton.setEnabled( false );
               removeButton.addActionListener( new ActionListener() {
                       public void actionPerformed(ActionEvent event) {
  -                        if ( removeSelected.equals(event.getActionCommand()) ) remove();
  +                        if ( removeSelected.equals(event.getActionCommand()) ) {
  +                            remove();
  +                        }
                       }
                   }
               );
  @@ -1176,7 +1511,9 @@
               removeAllButton.setEnabled( false );
               removeAllButton.addActionListener( new ActionListener() {
                       public void actionPerformed(ActionEvent event) {
  -                        if ( removeAll.equals(event.getActionCommand()) ) removeAll();
  +                        if ( removeAll.equals(event.getActionCommand()) ) {
  +                            removeAll();
  +                        }
                       }
                   }
               );
  @@ -1228,7 +1565,9 @@
               saveButton.setEnabled( false );
               saveButton.addActionListener( new ActionListener() {
                       public void actionPerformed(ActionEvent event) {
  -                        if ( save.equals(event.getActionCommand()) ) save();
  +                        if ( save.equals(event.getActionCommand()) ) {
  +                            save();
  +                        }
                       }
                   }
               );
  @@ -1236,7 +1575,9 @@
               resendButton.setEnabled( false );
               resendButton.addActionListener( new ActionListener() {
                       public void actionPerformed(ActionEvent event) {
  -                        if ( resend.equals(event.getActionCommand()) ) resend();
  +                        if ( resend.equals(event.getActionCommand()) ) {
  +                            resend();
  +                        }
                       }
                   }
               );
  @@ -1246,10 +1587,14 @@
                           if (switchStr.equals(event.getActionCommand()) ) {
                               int v = outPane.getOrientation();
   
  -                            if ( v == 0 )  // top/bottom
  +                            if ( v == 0 ) {
  +                                // top/bottom
                                   outPane.setOrientation(1);
  -                            else  // left/right
  +                            }
  +                            else  {
  +                                // left/right
                                   outPane.setOrientation(0);
  +                            }
                               outPane.setDividerLocation(0.5);
                           }
                       }
  @@ -1258,8 +1603,9 @@
   
               closeButton.addActionListener( new ActionListener() {
                       public void actionPerformed(ActionEvent event) {
  -                        if (close.equals(event.getActionCommand()) )
  +                        if (close.equals(event.getActionCommand()) ) {
                               close();
  +                        }
                       }
                   }
               );
  @@ -1272,7 +1618,7 @@
               pane1.setDividerLocation( 150 );
               this.add( pane1, BorderLayout.CENTER );
   
  -            // 
  +            //
               ////////////////////////////////////////////////////////////////////
               sel.setSelectionInterval(0, 0);
               outPane.setDividerLocation( 150 );
  @@ -1343,15 +1689,18 @@
               for ( int i = top ; i >= bot ; i-- ) {
                   ((Connection) connections.get(i - 1)).remove();
               }
  -            if ( bot > connections.size() ) bot = connections.size();
  +            if ( bot > connections.size() ) {
  +                bot = connections.size();
  +            }
               lsm.setSelectionInterval(bot, bot);
           }
   
           public void removeAll() {
               ListSelectionModel lsm = connectionTable.getSelectionModel();
               lsm.clearSelection();
  -            while ( connections.size() > 0 )
  +            while ( connections.size() > 0 ) {
                   ((Connection) connections.get(0)).remove();
  +            }
   
               lsm.setSelectionInterval(0, 0);
           }
  @@ -1369,7 +1718,7 @@
   
                       rc = lsm.getLeadSelectionIndex();
   
  -                    int n = 0;                    
  +                    int n = 0;
                       for (Iterator i = connections.iterator();i.hasNext();n++) {
                         Connection conn = (Connection)i.next();
                         if (lsm.isSelectedIndex(n + 1) ||
  @@ -1381,16 +1730,16 @@
                                       "\n" )).getBytes() );
                           rc = Integer.parseInt( tPortField.getText() );
                           out.write( (new String(getMessage("targetPort01", "Target Port:") + " " + rc + "\n" )).getBytes() );
  -                    
  +
                           out.write( (new String("==== " + getMessage("request01", "Request") + " ====\n" )).getBytes() );
                           out.write( conn.inputText.getText().getBytes() );
  -                    
  +
                           out.write( (new String("==== " + getMessage("response00", "Response") + " ====\n" )).getBytes() );
                           out.write( conn.outputText.getText().getBytes() );
                           out.write("\n==============\n".getBytes());
                         }
                       }
  -                    
  +
                       out.close();
                   }
                   catch ( Exception e ) {
  @@ -1406,7 +1755,9 @@
                   ListSelectionModel lsm = connectionTable.getSelectionModel();
   
                   rc = lsm.getLeadSelectionIndex();
  -                if ( rc == 0 ) rc = connections.size();
  +                if ( rc == 0 ) {
  +                    rc = connections.size();
  +                }
                   Connection conn = (Connection) connections.get( rc - 1 );
   
                   if ( rc > 0 ) {
  @@ -1426,10 +1777,13 @@
                       pos3 = text.indexOf( "\n\n" );
                       if ( pos3 == -1 ) {
                           pos3 = text.indexOf( "\r\n\r\n" );
  -                        if ( pos3 != -1 ) pos3 = pos3 + 4 ;
  +                        if ( pos3 != -1 ) {
  +                            pos3 = pos3 + 4 ;
  +                        }
                       }
  -                    else
  +                    else {
                           pos3 += 2 ;
  +                    }
   
                       headers = text.substring( 0, pos3 );
   
  @@ -1474,24 +1828,31 @@
           if ( listenPort != 0 ) {
               Listener l = null ;
   
  -            if ( targetHost == null )
  +            if ( targetHost == null ) {
                   l = new Listener( notebook, null, listenPort,
  -                    targetHost, targetPort, true );
  -            else
  +                    targetHost, targetPort, true, null);
  +            } else {
                   l = new Listener( notebook, null, listenPort,
  -                    targetHost, targetPort, false );
  +                    targetHost, targetPort, false, null);
  +            }
               notebook.setSelectedIndex( 1 );
   
               l.HTTPProxyHost = System.getProperty( "http.proxyHost" );
  -            if ( l.HTTPProxyHost != null && l.HTTPProxyHost.equals("") )
  +            if ( l.HTTPProxyHost != null && l.HTTPProxyHost.equals("") ) {
                   l.HTTPProxyHost = null ;
  +            }
   
               if ( l.HTTPProxyHost != null ) {
                   String tmp = System.getProperty( "http.proxyPort" );
   
  -                if ( tmp != null && tmp.equals("") ) tmp = null ;
  -                if ( tmp == null ) l.HTTPProxyPort = 80 ;
  -                else l.HTTPProxyPort = Integer.parseInt( tmp );
  +                if ( tmp != null && tmp.equals("") ) {
  +                    tmp = null ;
  +                }
  +                if ( tmp == null ) {
  +                    l.HTTPProxyPort = 80 ;
  +                } else {
  +                    l.HTTPProxyPort = Integer.parseInt( tmp );
  +                }
               }
           }
   
  @@ -1502,11 +1863,11 @@
   
       protected void processWindowEvent(WindowEvent event) {
           switch ( event.getID() ) {
  -        case WindowEvent.WINDOW_CLOSING: 
  +        case WindowEvent.WINDOW_CLOSING:
               exit();
               break ;
   
  -        default: 
  +        default:
               super.processWindowEvent(event);
               break ;
           }
  @@ -1522,26 +1883,39 @@
       public void setOutputHostPort(char hostName, int port) {
       }
   
  +    /**
  +     * set up the L&F
  +     */
  +    private static void setupLookAndFeel(boolean nativeLookAndFeel) throws Exception {
  +        UIManager.setLookAndFeel(
  +                nativeLookAndFeel ? UIManager.getSystemLookAndFeelClassName()
  +                    : UIManager.getCrossPlatformLookAndFeelClassName());
  +        JFrame.setDefaultLookAndFeelDecorated(true);
  +    }
  +    /**
  +     * this is our main method
  +     * @param args
  +     */
       public static void main(String[] args) {
           try {
  +            //switch between swing L&F here
  +            setupLookAndFeel(true);
               if ( args.length == 3 ) {
                   int p1 = Integer.parseInt( args[0] );
                   int p2 = Integer.parseInt( args[2] );
   
  -                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                   new tcpmon( p1, args[1], p2 );
               }
               else if ( args.length == 1 ) {
                   int p1 = Integer.parseInt( args[0] );
   
  -                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                   new tcpmon( p1, null, 0 );
               }
               else if ( args.length != 0 ) {
  -                System.err.println( getMessage("usage00", "Usage:") + " tcpmon [listenPort targetHost targetPort]\n");
  +                System.err.println( getMessage("usage00", "Usage:")
  +                        + " tcpmon [listenPort targetHost targetPort]\n");
               }
               else {
  -                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                   new tcpmon(0, null, 0);
               }
           }
  @@ -1562,8 +1936,7 @@
                   initializeMessages();
               }
               return messages.getString(key);
  -        }
  -        catch (Throwable t) {
  +        } catch (Throwable t) {
               // If there is any problem whatsoever getting the internationalized
               // message, return the default.
               return defaultMsg;
  @@ -1578,5 +1951,163 @@
       private static void initializeMessages() {
           messages = ResourceBundle.getBundle("org.apache.axis.utils.tcpmon");
       } // initializeMessages
  +
  +    /**
  +     * a text field with a restricted set of characters
  +     */
  +    static class RestrictedTextField extends JTextField {
  +        protected String validText;
  +
  +        public RestrictedTextField(String validText) {
  +            setValidText(validText);
  +        }
  +
  +        public RestrictedTextField(int columns, String validText) {
  +            super(columns);
  +            setValidText(validText);
  +        }
  +
  +        public RestrictedTextField(String text, String validText) {
  +            super(text);
  +            setValidText(validText);
  +        }
  +
  +        public RestrictedTextField(String text, int columns, String validText) {
  +            super(text, columns);
  +            setValidText(validText);
  +        }
  +
  +        private void setValidText(String validText) {
  +            this.validText = validText;
  +        }
  +
  +        /**
  +         * fascinatingly, this method is called in the super() constructor,
  +         * meaning before we are fully initialized. C++ doesnt actually permit
  +         * such a situation, but java clearly does...
  +         * @return a new document
  +         */
  +        public Document createDefaultModel() {
  +            return new RestrictedDocument();
  +        }
  +
  +        /**
  +         * this class strips out invaid chars
  +         */
  +        class RestrictedDocument extends PlainDocument {
  +
  +
  +            /**
  +             * Constructs a plain text document.  A default model using
  +             * <code>GapContent</code> is constructed and set.
  +             */
  +            public RestrictedDocument() {
  +
  +            }
  +
  +            /**
  +             * add a string; only those chars in the valid text list are allowed
  +             * @param offset
  +             * @param string
  +             * @param attributes
  +             * @throws BadLocationException
  +             */
  +            public void insertString(int offset, String string, AttributeSet attributes)
  +                    throws BadLocationException {
  +
  +                if (string == null) {
  +                    return;
  +                }
  +                int len = string.length();
  +                StringBuffer buffer = new StringBuffer(string.length());
  +                for (int i = 0; i < len; i++) {
  +                    char ch = string.charAt(i);
  +                    if (validText.indexOf(ch) >= 0) {
  +                        buffer.append(ch);
  +                    }
  +                }
  +                super.insertString(offset, new String(buffer), attributes);
  +            }
  +        } //end class NumericDocument
  +    }
  +
  +    /**
  +     * because we cant use Java1.4's JFormattedTextField, here is
  +     * a class that accepts numbers only
  +     */
  +    static class NumberField extends RestrictedTextField {
  +
  +        private static final String VALID_TEXT = "0123456789";
  +
  +        /**
  +         * Constructs a new <code>TextField</code>.  A default model is created,
  +         * the initial string is <code>null</code>,
  +         * and the number of columns is set to 0.
  +         */
  +        public NumberField() {
  +            super(VALID_TEXT);
  +        }
  +
  +        /**
  +         * Constructs a new empty <code>TextField</code> with the specified
  +         * number of columns.
  +         * A default model is created and the initial string is set to
  +         * <code>null</code>.
  +         *
  +         * @param columns  the number of columns to use to calculate
  +         *   the preferred width; if columns is set to zero, the
  +         *   preferred width will be whatever naturally results from
  +         *   the component implementation
  +         */
  +        public NumberField(int columns) {
  +            super(columns, VALID_TEXT);
  +        }
  +
  +
  +        /**
  +         * get the int value of a field, any invalid (non int) field returns
  +         * the default
  +         * @param def default value
  +         * @return the field contents
  +         */
  +        public int getValue(int def) {
  +            int result = def;
  +            String text = getText();
  +            if (text != null && text.length() != 0) {
  +                try {
  +                    result = Integer.parseInt(text);
  +                } catch (NumberFormatException e) {
  +
  +                }
  +            }
  +            return result;
  +        }
  +
  +        /**
  +         * set the text to a numeric value
  +         * @param value number to assign
  +         */
  +        public void setValue(int value) {
  +            setText(Integer.toString(value));
  +        }
  +
  +    } //end class NumericTextField
  +
  +    /**
  +     * hostname fields
  +     */
  +    static class HostnameField extends RestrictedTextField {
  +        //list of valid chars in a hostname
  +        private static final String VALID_TEXT =
  +                "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWZYZ-.";
  +
  +        public HostnameField(int columns) {
  +            super(columns, VALID_TEXT);
  +        }
  +
  +        public HostnameField() {
  +            super(VALID_TEXT);
  +        }
  +    }
   
   }