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.
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!
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);
}