August 09, 2005

Lesson learned: copying bytes from an OutputStream to an InputStream in Weblogic 8

A few weeks back, I posted about calling one servlet from another, passing a multipart/form-data for submission. I ended up using an HttpURLConnection and POSTing to the second servlet. My target platform was Weblogic 8 on Solaris 8, but I was developing on Windows Server 2003; both had Weblogic running on a Java 1.4 platform.

I set both the doOutput and doInput properties of the connection to true, so I can first post the needed data and then read the response, which I can parse and pass on to the user. Here's the setup:

    URL url = new URL("http://localhost/myws/myservlet");
    URLConnection con = url.openConnection();
    HttpURLConnection conn = (HttpURLConnection)con;
    conn.setDoOutput(true);
    conn.setDoInput(true);
    conn.setRequestProperty("Content-Type", request.getHeader("Content-Type"));
    conn.setRequestProperty("Cookie", request.getHeader("Cookie"));
    BufferedInputStream bis = new BufferedInputStream(request.getInputStream());
    BufferedOutputStream bos = new BufferedOutputStream(conn.getOutputStream());

I set the Cookie property so that the user does not have to reauthenticate to the second servlet.

However, when I was reading from the first servlet's InputStream and writing to the second servlet's OutputStream, I encountered some issues. The below code ran perfectly fine in the development environment, but in the production environment, the file being transferred was corrupted. The corruption happened in a number of ways, actually. At first, the file was about twice the size. Then, after fiddling a bit and moving the bis.close() and bos.close() closer to the write/read, I was able to get the file to be smaller than the posted file. However, it was a zip file and was still corrupt.)

    byte[] data = new byte[1024];
    int res = bis.read(data);
    while (res != -1) {
        bos.write(data);
        res = bis.read(data);
    }
    bos.flush();
    // other stuff, like getting response code
    bis.close();
    bos.close();

You can see that I'm double buffering the InputStream here, first with the BufferedInputStream, and then with my byte array, data[]. That's apparently unnecessary; I don't know where I got the idea. It actually leads to loss of data on the Solaris box.

Luckily, the Java Cookbook (and for that matter, the I/O section of the Java Tutorial) suggested code similar to this:

    int res;
    while ((res = bis.read()) != -1) {
        bos.write(res);
    }
    bis.close();
    bos.close();

This code works on both Windows and Solaris. I'm a bit mystified as to why the first byte transfer method worked on Windows but not Solaris, and I thought I'd post this so that any other folks struggling with the same problem don't endure the debugging that I did.

Posted by moore at August 9, 2005 07:06 AM
Comments
© Moore Consulting, 2003-2006