1. A Simple Web Client

import java.io.*;
import java.net.*;
 
/**
 * This program connects to a Web server and downloads the specified URL
 * from it.  It uses the HTTP protocol directly.
 **/
 
public class HttpClient {
  public static void main(String[] args) {
    try {
      // Check the arguments 
      if ((args.length != 1) && (args.length != 2))
        throw new IllegalArgumentException("Wrong number of arguments");
      
      // Get an output stream to write the URL contents to 
      OutputStream to_file;
      if (args.length == 2) to_file = new FileOutputStream(args[1]);
      else to_file = System.out;
       
      // Now use the URL class to parse the user-specified URL into
      // its various parts: protocol, host, port, filename.  Check the protocol 
      URL url = new URL(args[0]);
      String protocol = url.getProtocol();
      if (!protocol.equals("http"))
        throw new IllegalArgumentException("URL must use 'http:' protocol");
      String host = url.getHost();
      int port = url.getPort();
      if (port == -1) port = 80;  // if no port, use the default HTTP port
      String filename = url.getFile();
      // Open a network socket connection to the specified host and port 
      Socket socket = new Socket(host, port);
      // Get input and output streams for the socket
      InputStream from_server = socket.getInputStream();
      PrintWriter to_server = 
        new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
      
      // Send the HTTP GET command to the Web server, specifying the file.
      // This uses an old and very simple version of the HTTP protocol 
      to_server.println("GET " + filename);
      to_server.flush();  // Send it right now!
      
      // Now read the server's response, and write it to the file 
      byte[] buffer = new byte[4096];
      int bytes_read;
      while((bytes_read = from_server.read(buffer)) != -1)
        to_file.write(buffer, 0, bytes_read);
      
      // When the server closes the connection, we close our stuff 
      socket.close();
      to_file.close();
    }
    catch (Exception e) {    // Report any errors that arise 
      System.err.println(e);
      System.err.println("Usage: java HttpClient <URL> [<filename>]");
    }
  }
}

Here's how you use it:
tucotuco.cs.indiana.edu% pwd
/nfs/paca/home/user2/dgerman/jweb
tucotuco.cs.indiana.edu% ls
HttpClient.java  HttpMirror.java
tucotuco.cs.indiana.edu% javac HttpClient.java
tucotuco.cs.indiana.edu% java HttpClient http://tucotuco.cs.indiana.edu:19800
<html>
<head>
<title>
Home Page
</title>
<meta http-equiv="pragma" content="no-cache">
</head>
<body bgcolor=white>
<h1>Welcome!</h1>
This page has been accessed <img src="/cgi-bin/homepage"> times. 
</body>
</html> 
tucotuco.cs.indiana.edu%
Source code in: /u/dgerman/jweb

2. A Simple Web Server

import java.io.*;
import java.net.*;
 
/**
 * This program is a very simple Web server.  When it receives a HTTP request
 * it sends the request back as the reply.  This can be of interest when
 * you want to see just what a Web client is requesting, or what data is
 * being sent when a form is submitted, for example.
 **/ 
public class HttpMirror {
  public static void main(String args[]) {
    try {
      // Get the port to listen on 
      int port = Integer.parseInt(args[0]);  
      // Create a ServerSocket to listen on that port. 
      ServerSocket ss = new ServerSocket(port);  
      // Now enter an infinite loop, waiting for connections and handling them.  
      for(;;) {  
        // Wait for a client to connect.  The method will block, and when it
        // returns the socket will be already connected to the client  
        Socket client = ss.accept();  
        // Get input and output streams to talk to the client from the socket  
        BufferedReader in = 
          new BufferedReader(new InputStreamReader(client.getInputStream()));
        PrintWriter out =
          new PrintWriter(new OutputStreamWriter(client.getOutputStream()));
         
        // Start sending our reply, using the HTTP 1.0 protocol  
        out.println("HTTP/1.0 200 ");              // Version & status code 
        out.println("Content-Type: text/plain");   // The type of data we send 
        out.println();                             // End of response headers
        out.flush();
         
        // Now, read the HTTP request from the client, and send it right
        // back to the client as part of the body of our response.
        // The client doesn't disconnect, so we never get an EOF.
        // It does sends an empty line at the end of the headers, though.  
        // So when we see the empty line, we stop reading.  This means we 
        // don't mirror the contents of POST requests, for example. 
        String line;
        while((line = in.readLine()) != null) {
          if (line.length() == 0) break;
          out.println(line);
        }
         
        // Close the streams and socket, breaking the connection to the client 
        out.close();
        in.close();
        client.close();
      } // Loop again, waiting for the next connection 
    }
    // If anything goes wrong, print an error message 
    catch (Exception e) {
      System.err.println(e);
      System.err.println("Usage: java HttpMirror <port>");
    }
  }
}

Compile and launch (use your 2nd port):
tucotuco.cs.indiana.edu% pwd
/nfs/paca/home/user2/dgerman/jweb
tucotuco.cs.indiana.edu% ls
HttpClient.java  HttpMirror.java
tucotuco.cs.indiana.edu% javac HttpMirror.java
tucotuco.cs.indiana.edu% netstat -a | grep 29800
tucotuco.cs.indiana.edu% java HttpMirror 29800
Try it: here.

Or from inside a form:

Username:

Push to go on.

3. Exceptions

Dealing with Errors

Suppose an error occurs in a Java program. Users expect that programs will act sensibly under error conditions. If an operation cannot be completed because of an error, the program ought to either:

This is not an easy task. The code that detects (or even causes) the error condition is usually far removed from the code that can roll back data to a safe state, or save the user's work and exit cheerfully.

The central mission of exception handling is to transfer control from where the error occurred to an error-handler that can deal with the situation.

The traditional reaction to an error in a function is to return a special error code that that the calling function analyzes. But this is often a very cumbersome method of dealing with errors. Java uses a different approach in that it allows every method an alternate exit path if it is unable to complete its task in the normal way. In that case, the method does not return a value. Instead it throws an object that encapsulates the error information. The method exits immediately; it does not return a value. The code calling the method is not activated. Instead, the exception-handling mechanism begins its search for a handler that can deal with that particular error condition.

Throwing Exceptions

Classification of Error Types To handle exceptional situations in your program, you must take into account the errors and problems that may occur. Sorts of problems that you may have to consider:

In Java an exception is always an instance of a class derived from Throwable. All exceptions descend from this class but immediately split into two branches:
  1. Error
  2. Exception
The Error hierarchy describes internal errors and resource exhaustion inside the Java run time system. You should not throw an object of such type.

In your programming you will focus on the Exception hierarchy. The Exception hierarchy is also split into two branches:

  1. exceptions that derive from RunTimeException
  2. and those that do not.
The general rule is this:
A RunTimeException happens because you made a programming error.

Any other exception occurs because a bad thing, such as an I/O error, happened to your otherwise good program.

Advertising the Exceptions That a Method Throws. A Java method can throw an exception if it encounters a situation it cannot handle. The idea is simple: a function is not only going to tell the Java compiler what values it can return, it is also going to tell the compiler what can go wrong.

For example here's the header for a method in the DataInputStream class to read a line of text from a stream, such as a file or a network connection.

public String readLine() throws IOException
This method returns a string but also has the capacity to go wrong, in which case the method will not return a string, but instead will throw a special object of the IOException class. If it does, then Java will begin to search for a handler that can deal with IOException objects.

Exceptions are thrown for one of four possible scenarios:

  1. you call a method that throws an exception, for example, the readLine method of the DataInputStream;
  2. you detect an error and throw an exception with the throw statement (next section)
  3. you make a programming error (such as a[-1] = 0;)
  4. an internal error occurs in Java
If either of the first two scenarios occurs, you must tell the public that your method may throw an exception. The reason is: any method that throws an exception is a potential death trap. If no handler catches the exception, the program terminates. You declare the possibility that your method may throw an exception with an exception specification in the method header; if a method must deal with more than one exception, you must indicate all exceptions in the header, for example:
class Animation {
  ...
  public Image loadImage (String s) 
               throws EOFException, MalformedURLException {
    ...
  } 

} 
How to Throw an Exception Suppose something terrible has happened in your code. You're reading in a file whose header promised:
Content-length: 1024
But you get an end of file after 733 characters. You decide this situation is so abnormal you decide that you want to throw an exception.

You need to decide what exception type to throw. Some kind of IOException would be a good choice. Perusing the Java API documentation you find an EOFException with the description:

signals that an EOF has been reached unexpectedly during input
Perfect. Here's how we throw it:
throw new EOFException
or, if you prefer,
EOFException e = new EOFException(); 
throw e;
The EOFExceptionhas a second constructor that takes a String argument. You can put this to good use by describing the exceptional condition more carefully:
String gripe = "Content-length: " + len + "Received:" + n;
throw new EOFException;
Here's how it all fits together:
String readData(DataInput in) throws EOFException {
  ...
  while (...) {
    if (ch == -1) // EOF encountered
      throw new EOFException();
    ... 
  }
}
Therefore, throwing an exception is easy:
  1. You find an appropriate exception class.
  2. You make an object of that class.
  3. And then you throw it.
Once Java throws an exception the method does not return to its caller. This means that you do not have to worry about cooking up a default return value or an error code.

Note: you can also create your own Exception classes. Your code may run into a problem that is not adequately described by any of the standard exception classes. In this event you can create your own exception class (just derive it from Exception or from a child class).

Catching Exceptions At this point we know how to throw an exception: we just throw it and then simply forget about it. Of course some code has to catch the exception. Catching exceptions requires more planning.

To catch an exception you need to set up a try/catch block. The simplest form of the try block is as follows:

try {  
  code
  more code
  mode code 
} catch (ExceptionType e) { 
  handler for this type      
}
If any of the code inside the try block throws an exception of the class given in the catch clause, then

  1. Java skips the remainder of the code in the try block and
  2. it executes the handler code inside the catch clause.

If none of the code inside the block throws an exception, then Java skips the catch clause.

Notes:

If any of the code in a method throws an exception of a type other than the one named in the catch clause, Java exits this method immediately. Hopefully, one of its callers has already coded a catch clause for that type.

The compiler strictly enforces the thorws specifiers. If you call a method that throws an explicit exception, you must either handle it or propagate it. (You propagate it by declaring the method as throwing it).

You can handle multiple exception types in a try block and handle each type differently, with several catch clauses.

The finally clause, if it exists, is executed whether or not an exception is caught.