WriteListener (servlet 3.1) semantics - java

Let's say I'm writing chunks of data to an HttpServletResponse. So my method receives an array of bytes, I write it to response.getOutputStream(), and then I release the thread. When I receive another chunk of data, my method will be awaken, and it will write to getOutputStream() again. In the end, I call to AsyncContext.complete().
Now, the WriteListener.onWritePossible() spec says:
this method will be invoked by the container the first time when it is
possible to write data. The container will subsequently invoke the
onWritePossible method if and only if isReady method on
ServletOutputStream, described below, returns false.
It seems that when the container calls this method, I already need to have my response buffered somewhere, because onWritePossible() may never be called again. So, for the previous example, I need to write all chunks of data I receive in a buffer (a byte array, or maybe a temporary file if the buffer is big enough), and if onWritePossible() is called before my response is complete, what should I do? Block the thread until I have all my response data?

Check code in following link. May not be the exact solution but it's idea can be a solution for your case:
Servlet 3.1 Async IO Echo

hmm.. Maintaining a buffer seems to be the way
public void onWritePossible() throws IOException {
doWrite();
}
// this is some callback where you received next chunk of data
public void onMoreDataReceived(byte[] data) {
putDataToBuffer(data);
doWrite();
}
// this method is non-blocking
private void synchronized doWrite() throws IOException {
while (_servletOutputStream.isReady() && hasMoreDataInBuffer()) {
_servletOutputStream.write(getMoreBytesFromBuffer());
}
}

Related

Does Spring MVC has something like CancellationToken? [duplicate]

How can I detect that the client side of a tomcat servlet request has disconnected? I've read that I should do a response.getOutputStream().print(), then a response.getOutputStream().flush() and catch an IOException, but is there a way I can detect this without writing any data?
EDIT:
The servlet sends out a data stream that doesn't necessarily end, but doesn't necessarily have any data flowing through it (it's a stream of real time events). I need to actually detect when the client disconnects because I have some cleanup I have to do at that point (resources to release, etcetera). If I have the HttpServletRequest available, will trying to read from that throw an IOException if the client disconnects?
is there a way I can detect this
without writing any data?
No because there isn't a way in TCP/IP to detect it without writing any data.
Don't worry about it. Just complete the request actions and write the response. If the client has disappeared, that will cause an IOException: connection reset, which will be thrown into the servlet container. Nothing you have to do about that.
I need to actually detect when the client disconnects because I have some cleanup I have to do at that point (resources to release, etcetera).
There the finally block is for. It will be executed regardless of the outcome. E.g.
OutputStream output = null;
try {
output = response.getOutputStream();
// ...
output.flush();
// ...
} finally {
// Do your cleanup here.
}
If I have the HttpServletRequest available, will trying to read from that throw an IOException if the client disconnects?
Depends on how you're reading from it and how much of request body is already in server memory. In case of normal form encoded requests, whenever you call getParameter() beforehand, it will usually be fully parsed and stored in server memory. Calling the getInputStream() won't be useful at all. Better do it on the response instead.
Have you tried to flush the buffer of the response:
response.flushBuffer();
Seems to throw an IOException when the client disconnected.

StreamCorruptedException | OptionalDataException in objectInputStream.readObject() in multithreaded environment

I have a Client-Server architecture. The server can have * clients so for each of them two threads (input & output) are created.
I have one master class that coordinates all actions on server side. it has (among others) such a method:
public static synchronized void sendMessageToUser(Message message, String username){
clientOutputThreadPool.submit(new ObjectStreamOutputCallable(userObjectOutputStreams.get(username), message));
}
the objectOutputStreamCallable gets the objectOutputStream for the specific user passed (i keep them in a hashmap to reuse them). The callable is executed in a threadpool
the callable looks like this:
#Override
public Object call() throws Exception {
writeObjectToStream();
return null;
}
private synchronized void writeObjectToStream() throws IOException {
oos.reset();
oos.writeObject(message);
oos.flush();
}
Now I !Sometimes! get the above mentioned errors (on the client side). The fact that this only happens about 30-40% of the time, gets me to believe, that it has something to do with concurrency. Could it be e.g. that the message object that is being serialized is at the same time manipulated somewhere else in the code and that then creates the error? I have read many times that one may not use more than one objectOutputStream or objectInputStream . But I cannot find any place in my code where I use different objectOutputStreams for the same client. Each one has one oos that is created at socket creation time and then kept in a hashmap for later use. also i reset the socket before each message but that still has no effect...

Synchronizing methods in RXTX

Situation:
I'm trying to make the incoming data from SerialPort usefull for my purposes. In one class Processor.java I've implemented several methods - one of them (serialEvent) implements gnu.io.SerialPortEventListener. It stores the information read from inputStream in a buffer which is a byte array. There is also a method, which writes data to outputStream.
Problem:
I want to implement a method (in the same class) which will write something to outputStream depending on the messages read from the inputStream.
Pseudo code:
#Override
public void serialEvent(SerialPortEvent event) {
// get data
}
public void writeData(String dataToWrite) {
// write data
}
public void respond() {
// write data
// wait for appropriate response (read data)
// write data
// ...
}
How can I do this?
Only thing that comes to mind is a background thread that waits for input-buffer-full condition to process the received message and responds to it.
If you are communicating in fixed length packets or start-stop marked packets you should create a thread that would monitor the serial port, buffer the received data and once a "packet/message complete" condition is met to fire an event to a registered listener (in another thread if possible). That listener would then process the message and respond (in its own thread).

Input/Outputstream Java Servlets

I have a question pertaining to the use of the ServletInputStream and ServletOutputStream available in Java Servlets. First I'll give some much needed context:
The assignment I am working on calls on implementing Task Queues in the google app engine. I've been able to get tasks to be added to the app engine and the appropriate workers to be called. However, I am struggling to figure out how to pass an ArrayList<> of serializable objects to the worker's doPost() method. The pervailing method is apparently to use the input and outputstreams of the HTTP request and response objects, respectively, to handle this communication between servlets. I've googled extensively but haven't been able to find a clear example of how to prepare such an arraylist for transmission as an outputstream, adding it to the response of the first servlet, then retrieving it from the request in the second servlet and finally converting it back into an arraylist for use in the code of the doPost() method. So that is basically my question. Due to my inexperience with Java, it is difficult for me to figure it all out by myself and am mostly struggling to wrap my head around it.
To clarify a bit more, I'll post the doPost() method of the worker in question:
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
try
{
ArrayList<Quote> qs = /*Here the list needs to be read in.*/ null;
EntityManager manager = EMF.get().createEntityManager();
CarRentalModel.get().confirmQuotes(qs, manager);
}
catch (ReservationException e)
{
}
}
Any help would be greatly appreciated.
Thank you in advance,
Kevin
It's worth to follow BalusC's advice. If you are looking for a simple and quick solution, you can do it with Java's serialization:
In your doPost() method, you can create an ObjectInputStream which reads data from the underlying servlet input stream and deserializes (makes objects out of) the data.
ServletInputStream sis = req.getInputStream();
ObjectInputStream ois = new ObjectInputStream(sis);
ArrayList<Quote> qs = (ArrayList<Quote>) ois.readObject();
You write the object on the other side analogously with an ObjectOutputStream and its writeObject() method. If this doesn't work on spot, try to .flush() or .close() your output stream after finishing your write operations to trigger sending over any remaining buffered data.

Do I need to flush the servlet outputstream?

Do I need to "flush" the OutputStream from the HttpServletResponse?
I already saw from to Should I close the servlet outputstream? that I don't need to close it, but it's not clear if I need to flush it. Should I expect it from the container as well?
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
byte[] response = getResponse();
String responseType = getResponseType();
response.setContentLength(response.length);
response.setContentType(responseType);
response.getOutputStream().write(response);
response.getOutputStream().flush(); // yes/no/why?
}
You don't need to. The servletcontainer will flush and close it for you. The close by the way already implicitly calls flush.
See also chapter 5.6 of Servlet 3.1 specification:
5.6 Closure of Response Object
When a response is closed, the container must immediately flush all remaining
content in the response buffer to the client. The following events indicate that the servlet has satisfied the request and that the response object is to be closed:
The termination of the service method of the servlet.
The amount of content specified in the setContentLength or
setContentLengthLong method of the response has been greater than zero and
has been written to the response.
The sendError method is called.
The sendRedirect method is called.
The complete method on AsyncContext is called.
Calling flush while still running the servlet's service is usually only beneficial when you have multiple writers on the same stream and you want to switch of the writer (e.g. file with mixed binary/character data), or when you want to keep the stream pointer open for an uncertain time (e.g. a logfile).
Guess that the same answer you got in your other question applies here: if it is your stream, flush and close it. Otherwise the stream creator should be doing it, unless otherwise stated.
To point out an insidious exception to the rule “no need to flush”: Working with IBM WebSphere Application Server and using the response Writer (rather than the OutputStream) I found that I had to flush it; otherwise a final portion of my response data was lost. I suppose that IBM's HttpServletResponse class does indeed flush the OutputStream but uses a separate buffer for the Writer and does not flush it. Other application servers seem to do this.
So if you send your response data to the Writer it is safer to flush it. But there is no need to flush the OutputStream into the bargain.
(I would have posted this as a comment but lack the reputation to do it.)
java.lang.Object
extended byjava.io.Writer
extended byjavax.servlet.jsp.JspWriter
close
public abstract void close()
throws IOException
Close the stream, flushing it first.
This method needs not be invoked explicitly for the initial JspWriter as the code generated by the JSP container will automatically include a call to close().
Closing a previously-closed stream, unlike flush(), has no effect.
Throws:
IOException - If an I/O error occurs
============================
So, DO NOT close the output stream explicitly.

Categories

Resources