?
Solved

Apache HttpClient: send Vector object from servlet to client

Posted on 2005-05-06
17
Medium Priority
?
1,744 Views
Last Modified: 2013-11-24
Hi,

I'm writing an application where the client sends a request (GET) to a servlet.
For the request I'm using the Jakarta Commons HttpClient from Apache, v2.0.2

The request looks like this:

HttpClient client = new HttpClient();
client.setTimeout(timeout * 1000);
url = new URL(p_protocol, p_hostname, p_WebserverPort, file);
String strUrl = url.toExternalForm();
GetMethod method = new GetMethod(strUrl);

// Provide custom retry handler (seems to be necessary)
DefaultMethodRetryHandler retryhandler = new DefaultMethodRetryHandler();
retryhandler.setRequestSentRetryEnabled(false);
retryhandler.setRetryCount(1);
method.setMethodRetryHandler(retryhandler);

// Prevent CLOSE_WAITs
method.addRequestHeader( "Connection", "close");

// set content type
method.setRequestHeader("Content-type", "text/plain");

// add token
method.setRequestHeader("token", getHostname() + "-" + getID());

The servlet checks the token, and if that is valid it should send a
Vector with strings back to the client.

Currently, the code looks like this:

String receivedToken = request.getHeader("token");
if (validToken()) {
  ObjectOutputStream oOut = new ObjectOutputStream(response.getOutputStream());
  oOut.write(Base64.encodeBase64(SerializationUtils.serialize(servletVector)));
  oOut.flush();
  oOut.close();
}

and this is the client code for reading the response:

Vector servletVector = (Vector) SerializationUtils.deserialize(Base64.decodeBase64(method.getResponseBodyAsString().getBytes()));

But when I run this code, I get following exception:
java.lang.ArrayIndexOutOfBoundsException: -84
  at org.apache.commons.codec.binary.Base64.isBase64(Base64.java:137)
  at org.apache.commons.codec.binary.Base64.discardNonBase64(Base64.java:478)
  at org.apache.commons.codec.binary.Base64.decodeBase64(Base64.java:374)
  at net.testpackage.Client.pullData(Client.java:1465)
  at net.testpackage.Client.run(Client.java:1971)

When leaving out the Base64 Encoding/Decoding, I get following exception:
org.apache.commons.lang.SerializationException: java.io.UTFDataFormatException
  at org.apache.commons.lang.SerializationUtils.deserialize(SerializationUtils.java:204)
  at org.apache.commons.lang.SerializationUtils.deserialize(SerializationUtils.java:229)
  at net.testpackage.Client.pullData(Client.java:1471)
  at net.testpackage.Client.run(Client.java:1978)
Caused by: java.io.UTFDataFormatException
  at java.io.ObjectInputStream$BlockDataInputStream.readUTFSpan(Unknown Source)
  at java.io.ObjectInputStream$BlockDataInputStream.readUTFBody(Unknown Source)
  at java.io.ObjectInputStream$BlockDataInputStream.readUTF(Unknown Source)
  at java.io.ObjectInputStream.readString(Unknown Source)
  at java.io.ObjectInputStream.readObject0(Unknown Source)
  at java.io.ObjectInputStream.readObject(Unknown Source)
  at org.apache.commons.lang.SerializationUtils.deserialize(SerializationUtils.java:199)
  ... 3 more

I tried already several other methods (like converting the Vector to a
ByteArrayOutputStream) but until now I haven't succeeded to get it working.

Any help would be appreciated.
0
Comment
Question by:guydeschepper
  • 8
  • 7
  • 2
17 Comments
 
LVL 86

Expert Comment

by:CEHJ
ID: 13944207
If you're base64 encoding it before sending, then you don't need an ObjectOutputStream really. Also you probably shouldn't set it as a header - just send it as part of the response
0
 

Author Comment

by:guydeschepper
ID: 13944286
Sorry, I'm not sure what you're suggesting.

First of all, I'm not setting it as a header as you can see in the code, so that can't be the problem
So are you saying I can't use on ObjectOutputStream for sending a String ?
If so, what should I use then ?
To be honnest, I don't see why it would be a problem using an ObjectOutputStream ?
But maybe you can explain a bit more ?

Thanx for your help already...
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 13944375
>>First of all, I'm not setting it as a header as you can see in the code

Ignore that sorry - i misread it

>>So are you saying I can't use on ObjectOutputStream for sending a String ?

You could, but an ObjectOutputStream also sends metadata. Are you reading with OInputStream at the other end?

0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
LVL 86

Expert Comment

by:CEHJ
ID: 13944507
>>You could, but an ObjectOutputStream also sends metadata

(which would be a problem if you're not using ObjectInputStream at the other end). The other problem is you're mixing binary and text content. If you're sending binary output, you must use the output stream directly - you can't use a Writer as you're doing now. So there are really two approaches:

a. use binary output - OOS if you're using OIS at the other end
b. use the Writer to send Base64-encoded data as text
0
 

Author Comment

by:guydeschepper
ID: 13944660
Ok, I see.
I'll try it out (will be later today) and let you know the results.
0
 

Author Comment

by:guydeschepper
ID: 13946912
I tried both suggestions, but still without success:

a) use OOS & OIS:

servlet-code:
---------------
ObjectOutputStream oOut = new ObjectOutputStream(response.getOutputStream());
oOut.writeObject(servletVector);

client-code:
--------------
method.setRequestHeader("Content-type", "text/plain");
ObjectInputStream ois = (ObjectInputStream) method.getResponseBodyAsStream();
Vector servletVector = (Vector) ois.readObject();

Exception:
----------
java.lang.ClassCastException
      at net.testpackage.Client.pullData(Client.java:1462)
      at net.testpackage.Client.run(Client.java:1999)

Note:
------
I also tried the same code, but with
    method.setRequestHeader("Content-type", "application/octet-stream");
But that gave the same exception


b) use Writer to send Base64-encoded data as text:

servlet-code:
---------------
byte[] encodedSerializedData = Base64.encodeBase64(SerializationUtils.serialize(servletVector));
response.getWriter().write(new String(encodedSerializedData));

client-code:
--------------
byte[] servletData = Base64.decodeBase64(method.getResponseBodyAsString().getBytes());
Vector servletVector = (Vector) SerializationUtils.deserialize(servletData);

Exception:
----------
java.lang.ArrayIndexOutOfBoundsException: -84
  at org.apache.commons.codec.binary.Base64.isBase64(Base64.java:137)
  at org.apache.commons.codec.binary.Base64.discardNonBase64(Base64.java:478)
  at org.apache.commons.codec.binary.Base64.decodeBase64(Base64.java:374)
  at net.testpackage.Client.pullData(Client.java:1465)
  at net.testpackage.Client.run(Client.java:1971)

0
 
LVL 86

Expert Comment

by:CEHJ
ID: 13947081
Let's take them one at a time:

a. I don't think you need to set the request header, but if you do then your second mime type is the correct one. That should be set at the server Try the following:

ObjectInputStream ois = new ObjectInputStream(method.getResponseBodyAsStream());
Object o = ois.readObject();
System.out.println(o.getClass());
0
 

Author Comment

by:guydeschepper
ID: 13947511
ok, I will do that, but to be honest I don't think that will help, because I get the nullpointerexception
at the line
ObjectInputStream ois = new ObjectInputStream(method.getResponseBodyAsStream());
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 13948460
If that's the case, it suggests that 'method' is null
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 13948464
(or that the method has not been executed and therefore the stream is not available)
0
 

Author Comment

by:guydeschepper
ID: 13950013
Sorry, I meant ClassCastException instead of NullPointerException.

In the meantime, I tried the code you suggested, but obviously (and as expected) I still get the exception (ClassCastException that is)

So it seams I cannot cast the stream to an ObjectInputStream for some reason.
0
 
LVL 15

Expert Comment

by:aozarov
ID: 13950191
>> ObjectInputStream ois = new ObjectInputStream(method.getResponseBodyAsStream());
I can't see why this will throw ClassCastException as you are not casting anything (but rather wrapping).

In  anycase do you want to try this (and avoid the ObjectStreams):
server:
    response.getOutputStream().write(Base64.encodeBase64(SerializationUtils.serialize(servletVector)));
client:
   Vector servletVector = (Vector) SerializationUtils.deserialize(Base64.decodeBase64(method.getResponseBodyAsString().getBytes("ISO-8859-1")));

0
 

Author Comment

by:guydeschepper
ID: 13950223
ok, I tried that code, but still get the ArrayIndexOutOfBoundsException:

java.lang.ArrayIndexOutOfBoundsException: -84
      at org.apache.commons.codec.binary.Base64.isBase64(Base64.java:137)
      at org.apache.commons.codec.binary.Base64.discardNonBase64(Base64.java:478)
      at org.apache.commons.codec.binary.Base64.decodeBase64(Base64.java:374)
      at net.testpackage.Client.pullData(Client.java:1504)
      at net.testpackage.Client.run(Client.java:2007)

and line 1504 of Client.java is the code you suggested:
Vector servletVector = (Vector) SerializationUtils.deserialize(Base64.decodeBase64(method.getResponseBodyAsString().getBytes("ISO-8859-1")));

I really don't understand why this would fail (and especially the ClassCastException when using OOS & OIS seems very strange to me.)
0
 
LVL 15

Expert Comment

by:aozarov
ID: 13950237
Can you check what you get back when you do:
System.out.println(method.getResponseBodyAsString().getBytes("ISO-8859-1"));
That suppose to return you a sting base64 encoded.
You can compare that to what you send in your server:
System.out.println(Base64.encodeBase64(SerializationUtils.serialize(servletVector)));
I wonder if the method inputStream contains more or less and what is the difference...
0
 
LVL 86

Accepted Solution

by:
CEHJ earned 1000 total points
ID: 13950238
>>So it seams I cannot cast the stream to an ObjectInputStream for some reason.

You shouldn't be trying to cast the stream. See the code i posted earlier:

>>
ObjectInputStream ois = new ObjectInputStream(method.getResponseBodyAsStream());
Object o = ois.readObject();
System.out.println(o.getClass());
>>
0
 

Author Comment

by:guydeschepper
ID: 13950360
Oh boy, am I feeling silly.

I must have misread your previous post, as I still used
  ObjectInputStream ois = (ObjectInputStream) method.getResponseBodyAsStream();
instead of the suggested
  ObjectInputStream ois = new ObjectInputStream(method.getResponseBodyAsStream());


I tried again, but this time with the correct code (i.e. wrapping instead of casting) and it seems to be working !

Note that I also added the following code to the server part:
  response.setHeader("Content-type", "application/octet-stream");

But I'm not sure this is necessary.

So, the code that seems to be working for me is the following:

Servlet (i.e. server side):
  ObjectOutputStream oOut = new ObjectOutputStream(response.getOutputStream());
  response.setHeader("Content-type", "application/octet-stream");
  oOut.writeObject(servletVector);

Client:
  method.setRequestHeader("Content-type", "application/octet-stream");
  ObjectInputStream ois = new ObjectInputStream(method.getResponseBodyAsStream());
  Vector servletVector = (Vector) ois.readObject();


I should have done a copy/paste of the code you posted instead of manually modifying my existing code.

Thanx for all your help !

0
 
LVL 86

Expert Comment

by:CEHJ
ID: 13950448
:-) No problem.

>>But I'm not sure this is necessary.

Not necessary, as the entity that's reading it knows the mime type, but

>>method.setRequestHeader("Content-type", "application/octet-stream");

is redundant

0

Featured Post

[Webinar] Cloud and Mobile-First Strategy

Maybe you’ve fully adopted the cloud since the beginning. Or maybe you started with on-prem resources but are pursuing a “cloud and mobile first” strategy. Getting to that end state has its challenges. Discover how to build out a 100% cloud and mobile IT strategy in this webinar.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In this post we will learn different types of Android Layout and some basics of an Android App.
International Data Corporation (IDC) prognosticates that before the current the year gets over disbursing on IT framework products to be sent in cloud environs will be $37.1B.
Viewers will learn about arithmetic and Boolean expressions in Java and the logical operators used to create Boolean expressions. We will cover the symbols used for arithmetic expressions and define each logical operator and how to use them in Boole…
Viewers will learn one way to get user input in Java. Introduce the Scanner object: Declare the variable that stores the user input: An example prompting the user for input: Methods you need to invoke in order to properly get  user input:
Suggested Courses
Course of the Month14 days, 23 hours left to enroll

840 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question