Return-Path: <env_25700394-1301180217@hermes.sun.com>
Received: from pacific-carrier-annex.mit.edu by po10.mit.edu (8.9.2/4.7) id NAA21754; Tue, 19 Nov 2002 13:49:49 -0500 (EST)
Received: from hermes.sun.com (hermes.sun.com [64.124.140.169])
	by pacific-carrier-annex.mit.edu (8.9.2/8.9.2) with SMTP id NAA23967
	for <alexp@mit.edu>; Tue, 19 Nov 2002 13:49:46 -0500 (EST)
Date: 19 Nov 2002 08:57:30 -0800
From: "JDC Tech Tips" <JDC_Tech_Tips@hermes.sun.com>
To: alexp@mit.edu
Message-Id: <25700394-1301180217@hermes.sun.com>
Subject: Core Java Technologies Tech Tips, Nov. 19, 2002 (Multi-Column Lists, Timeouts on Socket Connections)
Mime-Version: 1.0
Content-Type: text/html; charset=us-ascii
Content-Transfer-Encoding: 7bit
X-Mailer: SunMail 1.0

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>
Core Java Technologies Technical Tips
</title>

<style type="text/css">

CODE {color: #333333; font-family: Verdana, Courier, Monospace; font-size: 10pt}
PRE {color: #333333; font-family: Verdana, Courier, Monospace; font-size: 10pt}
BODY, div, span {color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 10pt}
td, th {color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 10pt}
tr {color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 10pt}
table {font-family: Arial, Helvetica, sans-serif; font-size: 10pt}
p {color: #333333; font-family: arial,helvetica,sans-serif; font-size: 10pt}
li {color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 10pt}
br {color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 10pt}
div {color: #666699; font-family: Arial, Helvetica, sans-serif; font-size: 10pt}
sup {font-family: Arial, Helvetica, sans-serif; font-size: 5pt}
h3 {color: #666699; font-family: Arial, Helvetica, sans-serif; font-size: 11pt}
h4, b {color: #666699; font-family: Arial, Helvetica, sans-serif; font-size: 10pt}
blockquote, input, select {color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 10pt}
ul, ol {color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 10pt}
a:link {font-size: 10pt; font-family: Arial, Helvetica, sans-serif; color:#666699 }
span.purple {font-weight: bold; color: #666699; font-family: Arial, Helvetica, sans-serif; font-size: 10pt}
span.small {font-size: 8pt; font-family: Arial, Helvetica, sans-serif; color:#333333 }
span.link {font-size: 8pt; font-family: Arial, Helvetica, sans-serif; color:#666699 }
</style>

</head>

<body bgcolor="#ffffff">
<a name="top"></a>
<table border="0" cellpadding="0" cellspacing="0" width="611">
<tr>
<td colspan="3" bgcolor="#cccccc" width="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" border="0" alt="image"></td>
</tr>

<tr>
<td bgcolor="#cccccc" width="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" border="0" alt="image"></td>

<td>
<table border="0" cellpadding="0" cellspacing="0" width="611">
<tr>
<td colspan="2"><a href="http://developer.java.sun.com" target="_blank"><img src="http://developer.java.sun.com/images/headers/core_ttips_hdr.jpg" width="611" height="160" alt="Core Java Technologies Technical Tips" border="0"></a></td>
</tr>

<tr>
<td colspan="2" bgcolor="#cccccc" width="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" border="0" alt="image"></td>
</tr>

<!-- ================== -->
<!-- Start Main Content -->
<!-- ================== -->

<tr>
<td height="20">&nbsp;&nbsp;&nbsp;<a href="http://developer.java.sun.com/developer/TechTips/txtarchive/2002/Nov02_JohnZ.txt?s=06&w=47" style="text-decoration:none;" target="_blank">View this issue as simple text</a></td>
<td align="right" height="20"><span class="purple">November 19, 2002</span>&nbsp;&nbsp;&nbsp;&nbsp;</td>
</tr>

<tr><td colspan="2">

<FORM METHOD="GET" ACTION="http://search.java.sun.com/search/java/">
<table border="0" cellpadding="10" cellspacing="0" width="100%">
<tr>
<td>
        
<table border="0" cellpadding="3" cellspacing="0" width="100%">
<tr> 
<td align="left" VALIGN="middle" width="20%"><h3>In this Issue</h3></td>
              
<td valign="middle" align="right" width="70%">
<font size="2">
<INPUT TYPE="text" SIZE="15" MAXLENGTH="128" NAME=qt></FONT></td>
            
<td VALIGN="middle" WIDTH="55">
<INPUT TYPE="image" SRC="http://developer.java.sun.com/images/v4a_search.gif" ALT="Search" value="search" BORDER="0" WIDTH="55"></td>
</tr>
</table>

</FORM>

<p>
Welcome to the Core Java<sup>TM</sup> Technologies Tech Tips, November 19, 2002. Here you'll get tips on using core Java technologies and APIs, such as those in Java 2 Platform, Standard Edition (J2SE<sup>TM</sup>).
</p>

<p>
This issue covers:
</p>

<a href="#1"><img src="http://developer.java.sun.com/images/anchor.gif" border="0" alt="">Displaying Multi-column Lists</a>
<br>    
<a href="#2"><img src="http://developer.java.sun.com/images/anchor.gif" border="0" alt="">Dealing with Timeouts on Socket Connections</a>
</p>

<p>
These tips were developed using Java 2 SDK, Standard Edition, v 1.4. 
</p>

<p>
This issue of the Core Java Technologies Tech Tips is written by John Zukowski, president of <a href="http://www.jzventures.com" target="_blank">JZ Ventures, Inc.</a> 
</p>

<p>
See the Subscribe/Unsubscribe note at the end of this newsletter to subscribe to Tech Tips that focus on technologies and products in other Java platforms.
</p>

<table width="100%" border="0" cellspacing="0" cellpadding="0" align="center">

<!-- Grey Horizontal Line Begins Here -->

<tr>
<td bgcolor="#cccccc" height="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" ALT="Pixel" border="0"></td>
</tr>
</table> 

<!-- Grey Horizontal Line ends Here -->

<a name="1"></a>

<h3>DISPLAYING MULTI-COLUMN LISTS</h3>

<p>
A common request in newsgroups and forums lately seems to be the ability to have a <code>JList</code> show its options in multiple columns. In this scenario, the columns are displayed in the <code>JList</code>, and then a user selects a row in the display. There are at least three ways to satisfy this request. This tip examines each of these three approaches.
</p>

<p>
First, let's examine what might be the simplest solution: use <code>JTable</code> instead of <code>JList</code>. The <code>JTable</code> component was specifically designed to offer support for multiple columns of data. So why bother &quot;shoe-horning&quot; into a <code>JList</code> what the <code>JTable</code> component gives you by design?
</p>

<p>
Here's an illustration of the <code>JTable</code> approach. The following program displays a list of countries and their current political leader in multiple columns. You can then select a row from the display. Notice that the columns have headers -- this is a nice feature of <code>JTable</code>. Notice too that you can display multiple rows in the <code>JTable</code>. 
</p>

<pre>
  import java.awt.*;
  import javax.swing.*;
  import javax.swing.table.*;
  
  public class Leaders {
    public static void main(String args[]) {
      JFrame frame = new JFrame(&quot;Leaders&quot;);
      frame.setDefaultCloseOperation(
        JFrame.EXIT_ON_CLOSE);
      Container contentPane = frame.getContentPane();
      String headers[] = {&quot;Leader&quot;, &quot;Country&quot;};
      String data[][] = {
        {&quot;Tony Blair&quot;, &quot;England&quot;},
        {&quot;Thabo Mbeki&quot;, &quot;South Africa&quot;},
        {&quot;Megawati Soekarnoputri&quot;, &quot;Indonesia&quot;},
        {&quot;Hosni Mubarak&quot;, &quot;Egypt&quot;},
        {&quot;Vladimir Putin&quot;, &quot;Russia&quot;},
        {&quot;Vicente Fox&quot;, &quot;Mexico&quot;},
        {&quot;Ariel Sharon&quot;, &quot;Israel&quot;}
      };
      TableModel model =
        new DefaultTableModel(data, headers) {
          // Make read-only
          public boolean isCellEditable(int x, int y) {
            return false;
          }
        };
      JTable table = new JTable(model);
      // Set selection to first row
      ListSelectionModel selectionModel =
        table.getSelectionModel();
      selectionModel.setSelectionInterval(0, 0);
      selectionModel.setSelectionMode(
        ListSelectionModel.SINGLE_SELECTION);
      // Add to screen so scrollable
      JScrollPane scrollPane = new JScrollPane (table);
      contentPane.add(scrollPane, BorderLayout.CENTER);
      frame.setSize(300, 100);
      frame.show();
    }
  }
</pre>

<!-- ************** HTML only **************************** -->
<p>
<img src="http://developer.java.sun.com/developer/JDCTechTips/images/tt111902_Leaders.gif">
</p>
<!-- ***************************************************** -->

<p>
When you use a <code>JTable</code> as shown in this example, you must use a <code>ListSelectionListener</code> to listen for the selection of a new row. Notice that, as you can do for <code>JList</code>, you can place the <code>JTable</code> in a <code>JScrollPane</code> and provide scrolling support.
</p>

<p>
The second way of providing multiple columns in a selectable set of data does use the <code>JList</code> component. For this technique, you need to think about the underlying design of the <code>JList</code> component. Each selectable option in a <code>JList</code> is not a component by itself. Instead each option is a product of what's called a renderer. A renderer knows how to draw each option in the <code>JList</code> but has no concept of the overall list.
</p>

<p>
Typically, a renderer is a <code>JLabel</code> (see the documentation of the <a href="http://java.sun.com/j2se/1.4.1/docs/api/javax/swing/DefaultListCellRenderer.html?s=06&w=47" target="_blank"><code>javax.swing.DefaultListCellRenderer</code> class</a>. However, the <code>ListCellRenderer</code> interface only requires that the renderer be a <code>Component</code>.
</p>

<pre>
     public Component getListCellRendererComponent(
         JList list,
         Object value,
         int index,
         boolean isSelected,
         boolean cellHasFocus)
</pre>

<p>
Any component will do.
</p>

<p>
This suggests the second way of offering multiple columns: return a Container, where the Container contains one <code>Component</code> per column. Here's an example that illustrates the second approach. The example uses the same data that was used in the previous, <code>JTable</code> example. But in this example the data is converted to a <code>JList</code> model. The data is then added in the renderer. 
</p>

<pre>
  import java.awt.*;
  import javax.swing.*;
  
  public class ListLeaders {
    static class MyCellRenderer extends JPanel 
          implements ListCellRenderer {
      JLabel left;
      JLabel right;
      MyCellRenderer() {
        setLayout(new GridLayout(1, 2));
        left = new JLabel();
        right = new JLabel();
        left.setOpaque(true);
        right.setOpaque(true);
        add(left);
        add(right);
      }
      public Component getListCellRendererComponent(
               JList list,
               Object value,
               int index,
               boolean isSelected,
               boolean cellHasFocus) {
        String leftData = ((String[])value)[0];
        String rightData = ((String[])value)[1];
        left.setText(leftData);
        right.setText(rightData);
        if (isSelected) {
          right.setBackground(
             list.getSelectionBackground());
          right.setForeground(
             list.getSelectionForeground());
          left.setBackground(
             list.getSelectionBackground());
          left.setForeground(
             list.getSelectionForeground());
        } else {
          right.setBackground(list.getBackground());
          right.setForeground(list.getForeground());
          left.setBackground(list.getBackground());
          left.setForeground(list.getForeground());
        }
        setEnabled(list.isEnabled());
        setFont(list.getFont());
        return this;
      }
    }

    public static void main(String args[]) {
      JFrame frame = new JFrame(&quot;ListLeaders&quot;);
      frame.setDefaultCloseOperation(
        JFrame.EXIT_ON_CLOSE);
      Container contentPane = frame.getContentPane();
      String data[][] = {
        {&quot;Tony Blair&quot;, &quot;England&quot;},
        {&quot;Thabo Mbeki&quot;, &quot;South Africa&quot;},
        {&quot;Megawati Soekarnoputri&quot;, &quot;Indonesia&quot;},
        {&quot;Hosni Mubarak&quot;, &quot;Egypt&quot;},
        {&quot;Vladimir Putin&quot;, &quot;Russia&quot;},
        {&quot;Vicente Fox&quot;, &quot;Mexico&quot;},
        {&quot;Ariel Sharon&quot;, &quot;Israel&quot;}
      };
      JList list = new JList(data);
      list.setCellRenderer(new MyCellRenderer());
      JScrollPane scrollPane = new JScrollPane(list);
      contentPane.add(scrollPane, BorderLayout.CENTER);
      frame.setSize(300, 150);
      frame.show();
    }
  }
</pre>

<!-- ************** HTML only **************************** -->
<p>
<img src="http://developer.java.sun.com/developer/JDCTechTips/images/tt111902_ListLeaders.gif">
</p>
<!-- ***************************************************** -->

<p>
Although the <code>JList</code> does provide multiple columns of data to choose from, it doesn't display grid lines (something that the <code>JTable</code> does provide).
</p>

<p>
The third way of getting multiple columns of data in a <code>JList</code> depends on a <code>JList</code> feature that is new in J2SE 1.4. Using this technique doesn't actually provide multiple columns of data for selection. Instead, it offers a single column of data spread over multiple columns.
</p>

<p>
This new feature is controlled by the new <code>setLayoutOrientation</code> method of <code>JList</code>. By specifying one of three modes found in <code>JList</code>: <code>VERTICAL</code> (the default), <code>HORIZONTAL_WRAP</code>, and <code>VERTICAL_WRAP</code>, you can position choices for selection in one of three different ways.
</p>

<p>
<code>VERTICAL</code> positions data in a single column:
</p>

<pre>
  1
  2
  3
  4
  5
  6
</pre>

<p>
<code>HORIZONTAL_WRAP</code> positions data in cells similar to the way the <code>GridLayout</code> layout manager positions data, that is, a row at a time:
</p>

<pre>
  1   2
  3   4
  5   6
</pre>

<p>
<code>VERTICAL_WRAP</code> positions the data in cells going up and down instead of left-to-right.
</p>

<pre>
   1   4
   2   5
   3   6
</pre>

<p>
Here's a demonstration of the different modes. The following program provides a geography test. It asks for the capital of a country, and lists possible answers alphabetically in three different <code>JList</code> components, one <code>JList</code> component for each of the modes. Pick an answer to see how well you know world capitals.
</p>

<pre>
  import javax.swing.*;
  import javax.swing.event.*;
  import java.awt.*;
  import java.awt.event.*;

  public class ListWrap extends JFrame {

    static final String asCity[] = {
       &quot;Asmara&quot;,     &quot;Berlin&quot;,     &quot;Kuala Lumpur&quot;,
       &quot;Paramaribo&quot;, &quot;Paris&quot;,      &quot;Sana&quot;,
       &quot;Sucre&quot;,      &quot;Tokyo&quot;,      &quot;Ulan Bator&quot;,
       &quot;Valletta&quot;,   &quot;Washington&quot;, &quot;Yaounde&quot;
       };

    static final String asCountry[] = {
       &quot;Eritrea&quot;,  &quot;Germany&quot;, &quot;Malaysia&quot;,
       &quot;Suriname&quot;, &quot;France&quot;,  &quot;Yemen&quot;,
       &quot;Bolivia&quot;,  &quot;Japan&quot;,   &quot;Mongolia&quot;,
       &quot;Malta&quot;,    &quot;US&quot;,      &quot;Cameroon&quot;
       };

    int current;
    JTextField input;
    JLabel where;
    JButton submitButton, nextButton;

    public ListWrap() {
      setTitle( &quot;Capitals&quot; );
      setDefaultCloseOperation(EXIT_ON_CLOSE);

      JPanel westPanel = new JPanel(
          new GridLayout(3, 1));
      westPanel.add(new JLabel(
          &quot;What is the capitol of...&quot;,
          JLabel.CENTER));
      westPanel.add(where =
          new JLabel(asCountry[0], JLabel.CENTER));
      input = new JTextField(10);
      JPanel westSouth = new JPanel();
      westSouth.add(input);
      westPanel.add(westSouth);

      ListSelectionListener selectionListener =
          new ListSelectionListener() {
        public void valueChanged(
            ListSelectionEvent lse) {
          if (!lse.getValueIsAdjusting()) {
            Object source = lse.getSource();
            int index = (
                (JList)source).getSelectedIndex();
            input.setText(asCity[index]);
            checkAnswer();
          }
        }
      };

      JTabbedPane tabbedPane = new JTabbedPane();

      JList normalWrap = new JList(asCity);
      normalWrap.addListSelectionListener(
          selectionListener);
      tabbedPane.addTab(&quot;Standard&quot;, null,
        new JScrollPane(
            normalWrap), &quot;Standard Orientation&quot;);

      JList verticalWrap = new JList(asCity);
      verticalWrap.setLayoutOrientation(
          JList.VERTICAL_WRAP);
      verticalWrap.addListSelectionListener(
          selectionListener);
      tabbedPane.addTab(&quot;Vertical Wrap&quot;, null,
        verticalWrap, &quot;Vertical Wrap Orientation&quot;);

      JList horizontalWrap = new JList(asCity);
      horizontalWrap.setLayoutOrientation(
          JList.HORIZONTAL_WRAP);
      horizontalWrap.addListSelectionListener(
          selectionListener);
      tabbedPane.addTab(&quot;Horizontal Wrap&quot;, null,
        horizontalWrap, &quot;Horizontal Wrap Orientation&quot;);

      JPanel eastPanel = new JPanel();
      eastPanel.add(tabbedPane);

      ActionListener actionListener = 
          new ActionListener() {
        public void actionPerformed(ActionEvent ae) {
          Object source = ae.getSource();
          if (source == submitButton) {
            checkAnswer();
          } else if (source == nextButton) {
            doNext();
          }
        }
      };

      JPanel southPanel = new JPanel();

      submitButton = new JButton(&quot;Submit Answer&quot;);
      submitButton.addActionListener(actionListener);
      southPanel.add(submitButton);

      nextButton = new JButton(&quot;Next&quot;);
      nextButton.addActionListener(actionListener);
      southPanel.add(nextButton);

      Container contentPane = getContentPane();
      contentPane.add(westPanel, BorderLayout.WEST);
      contentPane.add(eastPanel, BorderLayout.EAST);
      contentPane.add(southPanel, BorderLayout.SOUTH);

      pack();
      show();
    }

    public void checkAnswer() {
      int messageType = 0;
      String result = null;
      String s = input.getText();
    
      if (s.equalsIgnoreCase(asCity[current])) {
        result = &quot;Correct!&quot;;
        messageType = JOptionPane.INFORMATION_MESSAGE;
      } else {
        result = &quot;Try Again.&quot;;
        messageType = JOptionPane.WARNING_MESSAGE;
      }

      JOptionPane.showMessageDialog(this,
        result, &quot;Result&quot;, messageType);
    }

    public void doNext() {
      current++;
      if (current &gt;= asCountry.length) { 
        current = 0;
      }
      where.setText(asCountry[current]);
      input.setText(&quot;&quot;);
    }
 
    public static void main(String args[]) {
      new ListWrap();
    }
  }  
</pre>

<!-- ************** HTML only **************************** -->
<p>
<img src="http://developer.java.sun.com/developer/JDCTechTips/images/tt111902_ListWrap.gif">
</p>
<!-- ***************************************************** -->

<p>
The number of rows and columns shown in a <code>JList</code> is controlled by the available screen space and the <code>visibleRowCount</code> property. The <code>visibleRowCount</code> property is an integer that specifies the preferred number of visible rows. By default, <code>visibleRowCount</code> has a setting of 8. If the <code>visibleRowCount</code> property is set to zero or a negative number, and the <code>layoutOrientation</code> is <code>HORIZONTAL_WRAP</code>, the width of the <code>JList</code> determines the number of rows to show. If the <code>visibleRowCount</code> property is set to zero or a negative number, and the <code>layoutOrientation</code> is <code>VERTICAL_WRAP</code>, the height of the <code>JList</code> determines the number of rows to show. 
</p>

<p>
For more information on what's new in <code>JList</code> for J2SE 1.4, see the <code>JList</code> section in "<a href="http://java.sun.com/j2se/1.4/docs/guide/swing/SwingChanges.html#JList?s=06&w=47" target="_blank">Swing Changes and New Features for Java 2 SDK, Standard Edition, v 1.4</a>".
</p>

<table width="100%" border="0" cellspacing="0" cellpadding="0" align="center">

<!-- Grey Horizontal Line Begins Here -->

<tr>
<td bgcolor="#cccccc" height="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" ALT="Pixel" border="0"></td>
</tr>
</table> 

<!-- Grey Horizontal Line ends Here -->

<a name="2"></a>

<h3>DEALING WITH TIMEOUTS ON SOCKET CONNECTIONS</h3>

<p>
The 1.4 version of the Java 2 Software Development Kit (SDK) incorporates many long awaited features into the standard <code>java.net</code> library set. Some of these features are forward thinking, such as bringing next-generation Internet Protocol version 6 (IPv6) support to TCP and UDP-based programs. Other features simply bring capabilities available to C/C++ programs for many years. 
</p>

<p>
One of the new features has to do with socket timeouts. If you've been programming with the networking libraries for some time, you might ask, &quot;Don't the libraries already support timeout?&quot; And, technically speaking, they do. However, now with the 1.4 release, there is support for a second form of socket timeouts.
</p>

<p>
The timeout support previously available with the <code>java.net.Socket</code> class (that is, since the 1.1 release of the networking libraries) is through the <code>setSoTimeout</code> method. Through this method you can enable (or disable) the <code>SO_TIMEOUT</code> setting in milliseconds. This setting controls how long your read call from the socket will wait before it gives up. If you don't set the option, the call could block for a very long time, theoretically forever. By setting the <code>SO_TIMEOUT</code> option, you limit the amount of time a read request from across a socket can wait. If no response comes back within the specified time, the read operation gives up. 
</p>

<p>
The new support for timeouts available with the 1.4 release has to do with connect timeouts. It controls how long a request waits for the server to respond with a valid connection. Servers 
can hold requests without processing until current requests are completed. Setting a timeout on a connection request permits you to cycle through a series of servers until one is available to
handle your request. This new way of timeout is done on the connect call.
</p>

<p>
Here's a fragment of code that let's you set the connect timeout Instead of passing the <code>InetAddress</code> (host) and port to the <code>Socket</code> construction, you create a <code>SocketAddress</code> to identify the connection point. The timeout is then set after creating the <code>Socket</code> and calling its connect method, passing in the <code>SocketAddress</code> and the timeout value.
</p>

<pre>
  int timeout = 500; // half a second
  SocketAddress socketAddress = 
    new InetSocketAddress(host, port);
  Socket socket = new Socket();
  socket.connect(socketAddress, timeout);
</pre>

<p>
You'll then be connected -- assuming no exceptions are thrown. If, however, the request doesn't connect within the specified time, you'll get a <code>SocketTimeoutException</code>. Of course, if the server rejects the request, you'll still get a <code>ConnectionException</code> with a message of connection refused.
</p>

<p>
The following program demonstrates the differences in the timeout support. There are five ways to run the program:
</p>

<ul>
<li>
Run with no parameters, that is: 
<pre>
java EchoClientTest 
</pre>
The program tries to connect to port 7, that is, the ECHO service, on your local machine. If it isn't running, you get a connection refused message. If it is running, the program connects to the ECHO service. For each line that you type, the program displays the response from the server. That response is exactly what was sent, hence the name ECHO service. <br><br> 
</li>

<li>
Run with one parameter, for example:
<pre>
java EchoClientTest web.mit.edu 
</pre>
The program tries to connect to port 7 on whatever host you specify. If you have an ECHO service running inside your firewall, this option would be how you specify it. Or, if you don't have an ECHO service running that you are aware of, you can connect to the one at Massachusetts Institute of Technology at their <code>web.mit.edu</code> server. Of course, the point of the exercise isn't to find an existing one, but to connect to one that will timeout.<br><br>
</li>

<li>
Run with two parameters, for example:
<pre>
java EchoClientTest web.mit.edu 9000
</pre>
The program uses the first parameter as the host. The second parameter then serves as an alternate port for connection. Unless you pick a well known port like 80 (which is for HTTP/web requests), the connection request should be rejected, and you'll get a Connection exception.<br><br>
</li>

<li>
Run with three parameters, for example:
<pre>
java EchoClientTest web.mit.edu 7 5000 
</pre>
This tries out the new 1.4 way of setting the connect timeout value. The third parameter is the timeout setting in miliseconds. Try not to set too small a value because it won't give the receiving end a chance to accept the request. Try to find a value that is reasonable for your situation. If the server doesn't respond with a valid connection within the specified time, the program continues by throwing a <code>SocketTimeoutException</code> from which you can recover. 
<br><br>
For example, the command:
<pre>
java EchoClientTest web.mit.edu 7 5000
</pre>
specifies a 5 second timeout. Assuming that the server is up and running at MIT, the connection will likely be established. If so, anything you type is echoed back until you type quit. Typing quit causes the program to quit (after the echo). 
<br><br>  
By comparison, if you enter the command:
<pre>
java EchoClientTest web.mit.edu 7 1
</pre>
the connect timeout is set so low that the connection won't likely happen. In this case, you get the timeout exception.<br><br>
</li>

<li>
Run the program with four parameters, for example:
<pre>
java EchoClientTest web.mit.edu 9000 1 x
</pre>
The fourth parameter can be anything, it is just meant to serve as a flag. The program will use the <code>setSoTimeout</code> method to set the socket's read timeout setting. This setting has no effect when making a connection, so you'll always get a <code>ConnectionException</code> if the server doesn't connect you in time. You'll also notice that the timeout value is essentially ignored at connection time. Remember, it only affects read operations after the connection is already established.
</li>
</ul>

<pre>
import java.io.*;
import java.net.*;
import java.util.*;

public class EchoClientTest {

  BufferedReader reader;
  PrintWriter writer;
  int port;
  int timeout;
  Socket socket;
  SocketAddress socketAddress;
  String host;

  private static final int ECHO_PORT = 7;

  public EchoClientTest() {
    this(&quot;localhost&quot;, ECHO_PORT);
  }

  public EchoClientTest(String host) {
    this(host, ECHO_PORT);
  }
  
  public EchoClientTest(String host, int port) {
    this.host = host;
    this.port = port;
    if (getSocketNoTimeout()) {
      doWork();
    }
  }


  public EchoClientTest(
      String host, int port, int timeout) {
    this.host = host;
    this.port = port;
    this.timeout = timeout;
    if (getSocketConnectTimeout()) {
      doWork();
    }
  }
  
  public EchoClientTest(
      String host, int port, int timeout, boolean b) {
    this.host = host;
    this.port = port;
    this.timeout = timeout;
    if (getSocketSetTimeout()) {
      doWork();
    }
  }

  public boolean getSocketNoTimeout() {
    try {
      System.out.println(&quot;Not connected, waiting...&quot;);
      socket = new Socket(host, port);
      System.out.println(
        &quot;Connected. Enter 'quit' to end.&quot;);
    } catch (UnknownHostException e) {
      System.err.println(
        &quot;Don't know about host: &quot; + host + &quot;.&quot;);
      return false;
    } catch (IOException ioe) {
      System.err.println(
        &quot;Connect: &quot; + ioe.getMessage());
      return false;
    }
    return true;
  }

  public boolean getSocketConnectTimeout() {
    try {
      System.out.println(&quot;Not connected, waiting...&quot;);
      socketAddress = 
         new InetSocketAddress(host, port);
      socket = new Socket();
      socket.connect(socketAddress, timeout);
      System.out.println(
        &quot;Connected. Enter 'quit' to end.&quot;);
    } catch(UnknownHostException e) {
      System.err.println(&quot;Don't know about host: &quot; + 
        host + &quot;.&quot;);
      return false;
    } catch(SocketTimeoutException ste) {
      System.err.println(&quot;Timeout: &quot; +
        ste.getMessage());
      return false;
    } catch(IOException ioe) {
      System.err.println(&quot;Connect: &quot; +
        ioe.getMessage());
      return false;
    }
    return true;
  }

  public boolean getSocketSetTimeout() {
    try {
      socketAddress = 
         new InetSocketAddress(host, port);
      socket = new Socket();
      try {
        socket.setSoTimeout(timeout);
      } catch (SocketException se) {
        System.err.println(&quot;Could not set timeout: &quot; +
          se.getMessage());
        return false;
      }
      System.out.println(&quot;Not connected, waiting...&quot;);
      socket.connect(socketAddress);
      System.out.println(
        &quot;Connected. Enter 'quit' to end.&quot;);
    } catch (UnknownHostException e) {
      System.err.println(&quot;Don't know about host: &quot; +
        host + &quot;.&quot;);
      return false;
    } catch (SocketTimeoutException ste) {
      System.err.println(&quot;Timeout: &quot; +
        ste.getMessage());
      return false;
    } catch (IOException ioe) {
      System.err.println(&quot;Connect: &quot; +
        ioe.getMessage());
      return false;
    }
    return true;
  }

  public void doWork() {
    try {
      writer = new PrintWriter(
        socket.getOutputStream(), true);
      reader = new BufferedReader(
        new InputStreamReader(socket.getInputStream()));
    } catch (IOException e) {
      System.err.println(
        &quot;Couldn't get I/O for the connection to: &quot; +
        host + &quot;.&quot;);
      return;
    }

    try {
      BufferedReader stdIn = new BufferedReader(
        new InputStreamReader(System.in));
      String userInput;

      while ((userInput = stdIn.readLine()) != null) {
        writer.println(userInput);
        System.out.println(&quot;echo: &quot; +
          reader.readLine());
        if (userInput.equals(&quot;quit&quot;)) {
          return;
        }
      }

      writer.close();
      reader.close();
      stdIn.close();
      socket.close();
    } catch(IOException ioe) {
      System.err.println(&quot;IOException: &quot; +
        ioe.getMessage());
      return;
    }
  }

  public static void main(String args[]) {
    int thePort = 0;
    int theTimeout = 0;

    if (args.length == 1 &amp;&amp; args[0].equals("?")) {
      System.out.println(
        &quot;No args: localhost, port 7,  no timeout.&quot;);
      System.out.println(
        &quot;1 arg: arghost, port 7, no timeout.&quot;);
      System.out.println(
        &quot;2 args: argHost, argPort, no timeout.&quot;);
      System.out.println(
        &quot;3 args: argHost, argPort, argTimeout, immediate connect.&quot;);
      System.out.println(
        &quot;4 args: argHost, argPort, argTimeout, argAny - set, then connect.&quot;);

      return;
    }

    System.out.println(&quot;Start time: &quot; + new Date());

    if (args.length == 0) {
      new EchoClientTest();
    } else {
      String theHost = args[0];
      //set up port, timeout, if sent
      if (args.length &gt; 1) {
        try {
          thePort = Integer.parseInt(args[1]);
          if (args.length &gt; 2) {
            theTimeout = Integer.parseInt(args[2]);
          }
        } catch(NumberFormatException nfe) {
          System.out.println(
             &quot;Invalid port or timeout value.&quot;);
          return;
        }
      }

      if (args.length == 1) {
        new EchoClientTest(theHost);
      } else if (args.length == 2) {
        new EchoClientTest(theHost, thePort);
      } else if (args.length == 3) {
        new EchoClientTest(
          theHost, thePort, theTimeout);
      } else if (args.length == 4) {
        new EchoClientTest(
          theHost, thePort, theTimeout, true);
      }
    }
    System.out.println(&quot;End time: &quot; + new Date());
  }
}
</pre>

<p>
For cases where a connect timeout isn't specified, the default timeout is specific to the operating system or kernel setting on the machine to which you are connecting.
</p>

<p>
Overall, the combined new and old settings allow more flexible socket creation, binding, and connection. Use accordingly, and your programs should never sit waiting without a way out.
</p>

<p>
For more information on timeouts in socket connections, see "<a href="http://java.sun.com/j2se/1.4/docs/guide/net/enhancements14.html?s=06&w=47" target="_blank">Networking: New Features and Enhancements</a>".
</p>


<table width="100%" border="0" cellspacing="0" cellpadding="0" align="center">

<!-- Grey Horizontal Line Begins Here -->

<tr>
<td bgcolor="#cccccc" height="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" ALT="Pixel" border="0"></td>
</tr>
</table> 

<!-- Grey Horizontal Line ends Here -->
<br>

<span class="small">IMPORTANT: Please read our Terms of Use, Privacy, and Licensing 
policies:<br>
<a href="http://www.sun.com/share/text/termsofuse.html?s=06&w=47" target="_blank"><span class="link">http://www.sun.com/share/text/termsofuse.html</span></a><br>
<a href="http://www.sun.com/privacy/?s=06&w=47" target="_blank"><span class="link">http://www.sun.com/privacy/</span></a><br> 
<a href="http://developer.java.sun.com/berkeley_license.html?s=06&w=47" target="_blank"><span class="link">http://developer.java.sun.com/berkeley_license.html</span></a>
</span><br><br>


<span class="small">
Comments? Send your feedback on the Core Java<sup>TM</sup> Technologies Tech Tips to: <a href="mailto:jdc-webmaster@sun.com"><span class="link">jdc-webmaster@sun.com</span></a>
</span><br><br>

<span class="small">
Subscribe to other Java developer Tech Tips:
</span><br><br>

<span class="small">
- Enterprise Java Technologies Tech Tips. Get tips on using enterprise Java technologies and APIs, such as those in the Java 2 Platform, Enterprise Edition (J2EE<sup>TM</sup>).<br>
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2ME<sup>TM</sup>).<br><br>
</span>
   
<span class="small">
To subscribe to these and other JDC publications:<br>
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to <a href="http://developer.java.sun.com/subscription/?s=06&w=47" target="_blank"><span class="link">subscribe</span></a> to and click &quot;Update&quot;.<br>
  - To unsubscribe, go to the <a href="http://developer.java.sun.com/subscription/?s=06&w=47" target="_blank"><span class="link">subscriptions page</span></a>, uncheck the appropriate checkbox, and click &quot;Update&quot;.
</span><br><br>

<span class="small">ARCHIVES: You'll find the Core Java Technologies Tech Tips archives at:<br>
<a href="http://java.sun.com/jdc/TechTips/?s=06&w=47" target="_blank"><span class="link">http://java.sun.com/jdc/TechTips/index.html</span></a>
</span><br><br>

<span class="small">Copyright 2002 <a href="http://www.sun.com?s=06&w=47" target="_blank"><span class="link">Sun Microsystems, Inc.</span></a> All rights reserved.
<br>901 San Antonio Road, Palo Alto, California 94303 USA.
</span><br><br>

<span class="small">This document is protected by copyright. For more information, see:
<br><a href="http://java.sun.com/jdc/copyright.html?s=06&w=47" target="_blank"><span class="link">http://java.sun.com/jdc/copyright.html</span></a>
</span><br><br>

<span class="small">
Core Java Technologies Tech Tips<br>
November 19, 2002
</span><br><br>

<span class="small">Sun, Sun Microsystems, Java, Java Developer Connection, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.</span><br><br>


<!-- ================ -->
<!-- End Main Content -->
<!-- ================ -->

<center>
<a href="http://www.sun.com" target="_blank"><img src="http://developer.java.sun.com/images/lgsun.gif" border="0" alt="Sun Microsystems, Inc."></a>
</center>

</td>
</tr>
</table>

</td></tr>
</table>
</td>

<td bgcolor="#cccccc" width="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" border="0" alt=""></td>
</tr>
<tr>
<td colspan="3" bgcolor="#cccccc" width="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" border="0" alt=""></td>
</tr>
</table>

<table bgcolor = "#efefef"><tr><td><a href="http://bulkmail.sun.com/servlet/PreferenceServlet?action=change&pref_name=content-type&pref_value=text&id=25700394-1301180217">Please send me newsletters in text.</a><br><a href="http://bulkmail.sun.com/unsubscribe?25700394-1301180217">Please unsubscribe me from this newsletter.</a><img src="http://bulkmail2.sun.com/OTServlet?id=25700394-1301180217" width=1 height=1></td></tr></table></body>
</html>

