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.

2 thoughts on “Lesson learned: copying bytes from an OutputStream to an InputStream in Weblogic 8

  1. Carl Smotricz says:

    This post is over 3 years old, but I thought I’d respond anyway and clear up the problem.

    In the code fragment above, Dan ignores the data count from bis.read() . Depending on the size of the text, the last call to read() will almost never read exactly 1024 bytes. My preferred solution is:
    while (true) {
    int count = bis.read(data);
    if (count

    The solutions quoted from the cookbook and tutorial have a performance problem: The read() and write() methods, as well as the underlying operating system calls, are repeated for each byte. With megabytes of data, we’d be talking a lot of unnecessary overhead. Buffering is good!

  2. Carl Smotricz says:

    oops… code in comment mangled by HTML. One more try:
    while (true) {
      int count = bis.read(data);
      if (count < 0) break;
      bos.write(data, 0, count);
    }

Comments are closed.


© Moore Consulting, 2003-2020