Java HTTP example - Reading and writing to an HTTP server

Suppose you're asked to create a Java applet that needs to communicate back to a web server (i.e., an HTTP server), but you're given several restrictions.  What kind of restrictions?  Suppose you're told that sockets, JDBC, and most every other cool communication technology was outlawed.  What will you do?

I ran into this problem a short time ago when I decided to create a "to-do list" applet that would help me track various tasks I was working on.  Because I'm constantly moving from site to site, I decided to base this applet on our company's Internet server.

Unfortunately, because our company's web server is hosted by a remote Internet Service Provider (ISP), I wasn't allowed to use sockets or RMI to communicate between the applet and the server.  Further, because we also don't have a database server out there, I had no direct access to a database.

Without the use of sockets, JDBC, RMI, or other technologies, I had to get creative.  All I had at my disposal was our remotely-hosted HTTP server.  Very quickly I realized that I needed a way that my Java applet could read and write flat files on our Internet server.

Our Java HTTP example

In this article, we'll demonstrate how to read flat text database files from a web server by looking at portions of my "To-Do List" code.  We'll also show how to take the data we read and display it in an AWT List component.

Then, because we can't write directly to the filesystem of the web server, we'll look at how we can simulate an old-fashioned HTML Post method by writing data to a CGI program on the HTTP server.  Then, we'll let the CGI program write the data to the Server filesystem.

As a final note before we get started, I created this applet using Java JDK 1.0.x technology.  Because many Internet users are still using older browsers, I follow this philosophy for most Internet applets I create (Intranets are a different story).

The "To Do List" Java applet

As a means of demonstrating the process of reading and writing files to an HTTP server, we'll first create a mini-version of the "ToDoList" applet.  The GUI for this applet is shown in Figure 1.  In the remainder of this article we'll use this applet as a sample interface for our read/write code.

Figure 1: The ToDoList applet displays the current "To-Do List" and offers an option to add a new "to-do" item.

Java HTTP example - Creating the applet GUI

You can use any GUI builder you want to build the ToDoList applet, or you can code it manually.  As you can see from Figure 1, the ToDoList applet consists of two labels, two buttons, a List component, and a TextField component.

The code for the GUI portion of the applet is shown in Listing 1.  Don't worry if your X-Y coordinates aren't the same as those shown in Listing 1 - the actual values aren't too important for this example.

// The 'ToDoList' applet

import java.awt.*; 
import java.applet.*;

public class ToDoList extends Applet
{

  java.awt.Button      addButton; 
  java.awt.Label       newLabel; 
  java.awt.TextField   addTextField; 
  java.awt.Label       toDoLabel; 
  java.awt.List        toDoList; 
  java.awt.Button      refreshButton;

  public void init() {

  super.init(); 
  setLayout(null); 
  addNotify(); 
  resize(410,336);

  addButton = new java.awt.Button("Add to List"); 
  addButton.reshape(290,222,71,23); 
  addButton.setFont(new Font("Dialog", Font.PLAIN, 12)); 
  add(addButton);

  newLabel = new java.awt.Label("New To-Do Item"); 
  newLabel.reshape(25,202,100,22); 
  newLabel.setFont(new Font("Dialog", Font.BOLD, 12)); 
  add(newLabel);

  addTextField = new java.awt.TextField(); 
  addTextField.reshape(24,225,243,21); 
  add(addTextField);

  toDoLabel = new java.awt.Label("To-Do List"); 
  toDoLabel.reshape(24,24,69,22); 
  toDoLabel.setFont(new Font("Dialog", Font.BOLD, 12)); 
  add(toDoLabel);

  toDoList = new java.awt.List(0,false); 
  add(toDoList); 
  toDoList.reshape(25,48,238,123);

  refreshButton = new java.awt.Button("Refresh"); 
  refreshButton.reshape(287,49,71,23); 
  refreshButton.setFont(new Font("Dialog", Font.PLAIN, 12)); 
  add(refreshButton);

  // "getToDoList()" not created yet: 
  // getToDoList();

  }  // end of init() method

}  // end of ToDoList class 

Listing 1: The Java source code for the GUI portion of the ToDoList applet.

Java HTTP example - Reading from an HTTP server

Given the proper permissions, you can easily read files directly from the filesystem of an HTTP server.  In this section we'll show how to read a file from a web server just by specifying the URL of the desired file.

I've created a method named getToDoList() to perform the applet's read function.  This method is called once when the applet is first started, and again each time the user clicks on the Refresh button.

The code for the getToDoList() method is shown in Listing 2.  First we create an object named url using the URL class.  In this example the URL is hard-wired into the constructor method for the URL class.  (Note that for more robust applet's that you want to share with others, you'll want to use the getCodeBase() method and a relative file path instead of the hard-coded path I'm using.)

Next, we create a URLConnection object named urlConnection by invoking url.openConnection().  Then, this connection is defined to be an input connection by invoking setDoInput() method of the URLConnection class.  To make sure that we get a real copy of the data file and not a cached file, we also invoke setUsesCaches(false).

void getToDoList ()
{ 
  try
  {
    URL                url; 
    URLConnection      urlConn; 
    DataInputStream    dis;

    url = new URL("http://webserver.our-intranet.com/ToDoList/ToDoList.txt");

    // Note:  a more portable URL: 
    //url = new URL(getCodeBase().toString() + "/ToDoList/ToDoList.txt");

    urlConn = url.openConnection(); 
    urlConn.setDoInput(true); 
    urlConn.setUseCaches(false);

    dis = new DataInputStream(urlConn.getInputStream()); 
    String s; 
  
    toDoList.clear(); 
  
    while ((s = dis.readLine()) != null)
    { 
      toDoList.addItem(s); 
    } 
      dis.close(); 
    }

    catch (MalformedURLException mue) {} 
    catch (IOException ioe) {} 
  } 
}

Listing 2: The getToDoList() method retrieves the ToDoList.txt file from the HTTP web server.

Once the initial communication parameters are configured, the data file is read from the web server using the URLConnection's getInputStream() method.  The stream is converted to a DataInputStream as it's read in.

As each line of data is read, it's added to the on-screen List component using the addItem() method of the List component.  Also note that because the getToDoList() method can be called any number of times when the user clicks on the Refresh button, it's necessary to call the clear() method of the toDoList object before adding any new text to it.  Finally, you should close the stream when you're finished reading from it.

Assuming that you have read permission for the URL you're trying to read from, that's all you need to do to read from the file, and add it's contents to the List component.

Java HTTP example - Writing to the HTTP server from the applet

For Java applets, writing data to a web server is a little more complex than reading data from a URL.  Because you can't write directly to the web server's filesystem (generally speaking), a little bit of CGI programming work is also required on the web server.  In essence, you write the data to the CGI program, and the CGI program writes the data to the proper file.

The code to make this happen for our Java applet is shown in Listing 3.  Here, the method named PostNewItem() gets the text from the addTextField object, and sends this data to the HTTP server.

void postNewItem () {  
  try {

    URL                url; 
    URLConnection      urlConn; 
    DataOutputStream   dos; 
    DataInputStream    dis;

    url = new URL("http://webserver.our-intranet.com/cgi-bin/AddToDoItem"); 
    urlConn = url.openConnection(); 
    urlConn.setDoInput(true); 
    urlConn.setDoOutput(true); 
    urlConn.setUseCaches(false); 
    urlConn.setRequestProperty ("Content-Type", "application/x-www-form-urlencoded");

    dos = new DataOutputStream (urlConn.getOutputStream()); 
    String message = "NEW_ITEM=" + URLEncoder.encode(addTextField.getText()); 
    dos.writeBytes(message); 
    dos.flush(); 
    dos.close();

    // the server responds by saying 
    // "SUCCESS" or "FAILURE"

    dis = new DataInputStream(urlConn.getInputStream()); 
    String s = dis.readLine(); 
    dis.close(); 
  
    if (s.equals("SUCCESS")) { 
      toDoList.addItem(addTextField.getText()); 
      addTextField.setText(""); 
    } else { 
      addTextField.setText("Post Error!"); 
    }

  } // end of "try"

  catch (MalformedURLException mue) { 
    addTextField.setText("mue error"); 
  } 
  catch (IOException ioe) { 
    addTextField.setText("IO Exception"); 
  }

}  // end of postNewItem() method 

Listing 3:The postNewItem() method writes data to a complementary CGI script on an HTTP Server.

Notice that the steps required to write the data to the web server are similar to the code used to read from the server.  The basic process involves defining the URL, opening a URL connection, and defining it as an input/output connection (instead of input-only).  Again, we also specify that we don't want a cached version of the URL.  Then, in the last step of configuring the urlConn object, we set the request property.

Once the URL connection is configured, we open the output connection, create a String object (named message) by getting the text string out of the addTextField component, and write the message object to the output stream.

Notice that it's also necessary (and desirable) to read a response from the web server.  In this case, I've configured the CCI script to send a status code back to the applet after the post operation.  The CGI script can write something as simple as "SUCCESS" or "FAILURE" - which I've done here - or you can make the message as complicated as desired.

In this simple case, if the returned message says "SUCCESS", the text string is added to the toDoList object and the addTextField object is cleared.  If the Post attempt fails, I write a failure message into the addTextField component (not a good idea for commercial applets, but hopefully okay for this example).

Java HTTP example - Summary

When you're creating Java applets, and you need to read and write information from flat text files on a web server, the Java language makes reading and writing across the Internet very simple.  Just open a URL connection to your web server, set the connection to be an input or output connection, and transfer your information.

While reading data from a server is very simple, writing information to a web server requires a little more assistance on the server in the form of a CGI script to write your data into a file (or files) on the server.
 

Follow-Up

If you're interested in seeing a slightly more modern version of the ToDoList applet, just click here. Although it's far from complete, it may help you create a working applet for your own site.