Version: 2.0.0 (stable)
Ok, so I'm using Restlet on the Server side only as a useful way of unit
testing an application that emits a variety of HTTP requests. I can check in my
unit tests that the correct request from the application is being sent, as well
as send different responses back to check the behaviour of the application
under different conditions. All nicely self contained with minimal dependencies
... great
But ... I am getting errors which both occur in different tests (not very
predictably) and are different errors... and sometimes everything works !
I have tried a whole bunch of stuff and read through lots of messages on this
list and others, but still no joy ... very frustrating.
I am relatively new to Restlet so I expect I might be misunderstanding
something or doing it wrong somehow.
Some possibly relevent info about the sending application :-
Its an IBM enterprise middleware product (so the HTTP implementation should be
solid ;-)
POST requests use :-
- HTTP 1.1
- KeepAlive
- DONT include an Accept header
- Do inlcude Content-Type and Content-Length
E.g. :-
POST /mbunittest/myflow HTTP/1.1
Content-Length: 123
Content-Type: text/xml; charset=utf-8
Host: 127.0.0.1:8193
SOAPAction: ""
Connection: keep-alive
...
I mention keep-alive, because I have a suspician that it might have something
to do with the errors.
If I run ONE TEST at a time, no problems
If I run multiple tests (that means the application sends multiple requests to
the Restlet Application using the SAME HTTP (keep-alive) connection, the
problems start.
I'm going to check tommorrow if I change the middleware to NOT use keep-alive,
if the problems disappear, but for obvious reasons we don't have the middleware
configured this way in production so its not really a solution, just an
experiment.
I notice that Restlet sends back 'chunked' data (at least for the text/xml
responses (not sure if thats a problem or not). Captured from TCPMon :-
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Date: Fri, 27 Aug 2010 20:21:10 GMT
Accept-Ranges: bytes
Server: Restlet-Framework/2.0.0
Vary: Accept-Charset, Accept-Encoding, Accept-Language, Accept
Content-Type: text/xml; charset=UTF-8
cb
<?xml version="1.0" encoding="UTF-8"?><Numbers>
<Odds>
<Five>5</Five>
<Three>3</Three>
<One>1</One>
</Odds>
<Evens>
<Six>6</Six>
<Four>4</Four>
<Two>2</Two>
</Evens>
</Numbers>
0
So what sort of error occur ... well they vary and are not reproducable at
least in any predictable way
I see a few different java.lang.NullPointerException's usually related to
manipulating the entity, sometimes one of the methods will 'hang' and cause a
timeout, I have seen socket related errors .. and somethimes all of the tests
run successfully !
I got me thinking about whether the response stream is clearing out properly
and led me to try the 'release' and 'exhaust' methods (settling on the later)
but they haven't made any real difference (AFAICT).
Question: Since this is just supporting unit testing and performance and
scalability are not important at all, I wonder if I constrained the Restlet
server to ONE THREAD or at the other extreme [say] 100 THREADS would that help
?? If so can you advise how to do that, I tried various methods without success.
Below is some of the code. I will provide more details if needed, but I'm
hoping that someone will either spot something obvious or have experienced
something similar.
Kind Regards
Fraser.
So this is the set up :-
I have a JUnit class which initailises a restlet Application thus :-
public class MbMockHttpServerTest {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
MbHttpMockAFComBufApplication.initialise(Port);
}
... and stops it when all tests have completed thus :-
@AfterClass
public static void tearDownAfterClass() throws Exception {
MbHttpMockAFComBufApplication.stopServer();
}
The Application looks like this :-
public class MbHttpMockAFComBufApplication extends Application {
...
public static void initialise(int Port) throws Exception {
mockMbHttpServer = new Server(Protocol.HTTP, Port);
mockMbHttpServer.setNext(new MbHttpMockAFComBufApplication());
mockMbHttpServer.start();
}
@Override
public Restlet createInboundRoot() {
Router router = new Router(getContext());
router.attachDefault(MbHttpMockAFComBufResource.class);
return router;
}
public static void stopServer() throws Exception{
if(mockMbHttpServer.isStarted()){
System.out.println("Attempting to stop server.");
mockMbHttpServer.stop();
System.out.println("Server has been successfully stopped.");
} else {
System.out.println("Server has already been successfully stopped.");
}
}
Hopefully nothing too problematic here ???
Here are the POST methods from the ServerResource class :-
public class MbHttpMockAFComBufResource extends ServerResource {
@Override
protected void doInit() throws ResourceException {
}
@Post("xml")
public Representation postRequestAsXML(Representation entity) throws
ResourceException {
DomRepresentation response = null;
try {
String resourcePath = getReference().getPath();
// store the request
storeXMLRequest(entity, resourcePath);
// send the response
Document responseDoc = getResponse(resourcePath);
response = new DomRepresentation(MediaType.TEXT_XML);
response.setIndenting(false);
response.setNamespaceAware(true);
response.setDocument(responseDoc);
setStatus(Status.SUCCESS_OK);
//return response;
} catch (Exception e) {
setStatus(Status.SERVER_ERROR_INTERNAL, e.getMessage());
throw new ResourceException(e);
} finally {
response.exhaust();
}
return response;
}
@Post("txt")
public Representation postRequestAsText(Representation entity) throws
ResourceException {
StringRepresentation response = null;
try {
String resourcePath = getReference().getPath();
// store the request
storeTextRequest(entity, resourcePath);
// send the response
response = new
StringRepresentation(MbHttpMockAFComBufApplication.getResponseBuf(resourcePath).getPayload());
setStatus(Status.SUCCESS_OK);
} catch (Exception e) {
setStatus(Status.SERVER_ERROR_INTERNAL, e.getMessage());
throw new ResourceException(e);
} finally {
response.exhaust();
}
return response;
}
JUST SHOWING THESE METHODS BECAUSE ERRORS SOMETIMES OCCUR HERE
private void storeXMLRequest(Representation entity, String serviceURL) throws
Exception{
try {
DomRepresentation request = new DomRepresentation(entity);
request.setNamespaceAware(true);
request.setIndenting(false);
Document requestDoc;
requestDoc = request.getDocument();
...
Node payload = extractPayload(requestDoc);
String payloadXML = Utils.w3cNodeToString(payload);
...
} catch (Exception e) {
throw new Exception(e);
}
}
private void storeTextRequest(Representation entity, String serviceURL)
throws Exception{
try {
// store the request as a CommBuffer
CommBufferJava reqBuf = new CommBufferJava(1,0);
reqBuf.setPayload(entity.getText());
...
} catch (Exception e) {
throw new Exception(e);
}
}
------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=2652186