15.6 Writing Data to a Server


Sometimes you need to write data to a URLConnection for example, when you submit a form to a web server using POST or upload a file using PUT. The getOutputStream() method returns an OutputStream on which you can write data for transmission to a server:

 public OutputStream getOutputStream( ) 

Since a URLConnection doesn't allow output by default, you have to call setDoOutput(true) before asking for an output stream. When you set doOutput to true for an http URL, the request method is changed from GET to POST. In Chapter 7, you saw how to send data to server-side programs with GET. However, GET should be limited to safe operations, such as search requests or page navigation, and not used for unsafe operations that create or modify a resource, such as posting a comment on a web page or ordering a pizza. Safe operations can be bookmarked, cached, spidered, prefetched, and so on. Unsafe operations should not be.

Once you've got the OutputStream , buffer it by chaining it to a BufferedOutputStream or a BufferedWriter . You should generally also chain it to a DataOutputStream , an OutputStreamWriter , or some other class that's more convenient to use than a raw OutputStream . For example:

 try {   URL u = new URL("http://www.somehost.com/cgi-bin/acgi");       // open the connection and prepare it to POST   URLConnection uc = u.openConnection( );   uc.setDoOutput(true);   OutputStream raw = uc.getOutputStream( );   OutputStream buffered = new BufferedOutputStream(raw);   OutputStreamWriter out = new OutputStreamWriter(buffered, "8859_1");   out.write("first=Julie&middle=&last=Harting&work=String+Quartet\r\n");   out.flush( );   out.close( ); } catch (IOException ex) {   System.err.println(ex); } 

Sending data with POST is almost as easy as with GET. Invoke setDoOutput(true) and use the URLConnection 's getOutputStream( ) method to write the query string rather than attaching it to the URL. Java buffers all the data written onto the output stream until the stream is closed. This is necessary so that it can determine the necessary Content-length header. The query string contains two name -value pairs separated by ampersands. The complete transaction, including client request and server response, looks something like this:

 %  telnet www.ibiblio.org 80  Trying Connected to www.ibiblio.org. Escape character is '^]'.  POST /javafaq/books/jnp3/postquery.phtml HTTP/1.0   ACCEPT: text/plain   Content-type: application/x-www-form-urlencoded   Content-length: 65   username=Elliotte+Rusty+Harold&email=elharo%40metalab%2eunc%2eedu  HTTP/1.1 200 OK Date: Mon, 10 May 2004 21:08:52 GMT Server: Apache/1.3.29 (Unix) DAV/1.0.3 mod_perl/1.29 PHP/4.3.5 X-Powered-By: PHP/4.3.5 Connection: close Content-Type: text/html <html xmlns="http://www.w3.org/1999/xhtml"> <head>   <title>Query Results</title> </head> <body> <h1>Query Results</h1> <p>You submitted the following name/value pairs:</p> <ul> <li>username = Elliotte Rusty Harold</li> <li>email = elharo@metalab.unc.edu</li> </ul> <hr /> Last Modified May 10, 2004 </body> </html> Connection closed by foreign host. 

For that matter, as long as you control both the client and the server, you can use any other sort of data encoding you like. For instance, SOAP and XML-RPC both POST data to web servers as XML rather than an x-www-form-url-encoded query string. However, if you deviate from the standard, you'll find that your nonconforming client can't talk to most server-side programs or that your nonconforming server-side program can't process requests from most clients . The query string format used here is used by all web browsers and is expected by most server-side APIs and tools.

Example 15-8 is a program called FormPoster that uses the URLConnection class and the QueryString class from Chapter 7 to post form data. The constructor sets the URL. The query string is built using the add( ) method. The post( ) method actually sends the data to the server by opening a URLConnection to the specified URL, setting its doOutput field to true , and writing the query string on the output stream. It then returns the input stream containing the server's response.

The main( ) method is a simple test for this program that sends the name "Elliotte Rusty Harold" and the email address elharo@metalab.unc.edu to the resource at http://www.cafeaulait.org/books/jnp3/postquery.phtml. This resource is a simple form tester that accepts any input using either the POST or GET method and returns an HTML page showing the names and values that were submitted. The data returned is HTML; this example simply displays the HTML rather than attempting to parse it. It would be easy to extend this program by adding a user interface that lets you enter the name and email address to be postedbut since doing that triples the size of the program while showing nothing more of network programming, it is left as an exercise for the reader. Once you understand this example, it should be easy to write Java programs that communicate with other server-side scripts.

Example 15-8. Posting a form
 import java.net.*; import java.io.*; import com.macfaq.net.*; public class FormPoster {   private URL url;   // from Chapter 7, Example 7-9   private QueryString query = new QueryString( );        public FormPoster (URL url) {     if (!url.getProtocol( ).toLowerCase( ).startsWith("http")) {       throw new IllegalArgumentException(        "Posting only works for http URLs");        }         this.url = url;   }      public void add(String name, String value) {     query.add(name, value);       }      public URL getURL( ) {     return this.url;    }   public InputStream post( ) throws IOException {     // open the connection and prepare it to POST     URLConnection uc = url.openConnection( );     uc.setDoOutput(true);     OutputStreamWriter out       = new OutputStreamWriter(uc.getOutputStream( ), "ASCII");     // The POST line, the Content-type header,     // and the Content-length headers are sent by the URLConnection.     // We just need to send the data     out.write(query.toString( ));     out.write("\r\n");     out.flush( );     out.close( );     // Return the response     return uc.getInputStream( );   }   public static void main(String args[]) {     URL url;     if (args.length > 0) {       try {         url = new URL(args[0]);       }       catch (MalformedURLException ex) {         System.err.println("Usage: java FormPoster url");         return;       }     }     else {       try {         url = new URL(           "http://www.cafeaulait.org/books/jnp3/postquery.phtml");       }       catch (MalformedURLException ex) { // shouldn't happen         System.err.println(ex);         return;        }     }     FormPoster poster = new FormPoster(url);     poster.add("name", "Elliotte Rusty Harold");     poster.add("email", "elharo@metalab.unc.edu");          try {       InputStream in = poster.post( );            // Read the response       InputStreamReader r = new InputStreamReader(in);       int c;       while((c = r.read( )) != -1) {         System.out.print((char) c);       }       System.out.println( );       in.close( );     }     catch (IOException ex) {       System.err.println(ex);        }   } } 

Here's the response from the server:

 %  java -classpath .:jnp3e.jar FormPoster  <html xmlns="http://www.w3.org/1999/xhtml"> <head>         <title>Query Results</title> </head> <body> <h1>Query Results</h1> <p>You submitted the following name/value pairs:</p> <ul> <li>name = Elliotte Rusty Harold</li> <li>email = elharo@metalab.unc.edu </li> </ul> <hr /> Last Modified May 10, 2004 </body> </html> 

The main( ) method tries to read the first command-line argument from args[0] . The argument is optional; if there is an argument, it is assumed to be a URL that can be POSTed to. If there are no arguments, main() initializes url with a default URL, http://www.cafeaulait.org/books/jnp3/postquery.phtml. main( ) then constructs a FormPoster object. Two name-value pairs are added to this FormPoster object. Next, the post( ) method is invoked and its response read and printed on System.out .

The post( ) method is the heart of the class. It first opens a connection to the URL stored in the url field. It sets the doOutput field of this connection to true since this URLConnection needs to send output and chains the OutputStream for this URL to an ASCII OutputStreamWriter that sends the data; then flushes and closes the stream. Do not forget to close the stream! If the stream isn't closed, no data will be sent. Finally, the URLConnection 's InputStream is returned.

To summarize, posting data to a form requires these steps:

  1. Decide what name-value pairs you'll send to the server-side program.

  2. Write the server-side program that will accept and process the request. If it doesn't use any custom data encoding, you can test this program using a regular HTML form and a web browser.

  3. Create a query string in your Java program. The string should look like this:


    Pass each name and value in the query string to URLEncoder.encode( ) before adding it to the query string.

  4. Open a URLConnection to the URL of the program that will accept the data.

  5. Set doOutput to true by invoking setDoOutput(true) .

  6. Write the query string onto the URLConnection 's OutputStream .

  7. Close the URLConnection 's OutputStream .

  8. Read the server response from the URLConnection 's InputStream .

Posting forms is considerably more complex than using the GET method described in Chapter 7. However, GET should only be used for safe operations that can be bookmarked and linked to. POST should be used for unsafe operations that should not be bookmarked or linked to.

The getOutputStream( ) method is also used for the PUT request method, a means of storing files on a web server. The data to be stored is written onto the OutputStream that getOutputStream( ) returns. However, this can be done only from within the HttpURLConnection subclass of URLConnection , so discussion of PUT will have to wait a little while.

Java Network Programming
Java Network Programming, Third Edition
ISBN: 0596007213
EAN: 2147483647
Year: 2003
Pages: 164

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net