write to File from Servlet - java

here is the piece of code that i wrote:
public class ServletCounter extends HttpServlet {
private final Object lock = new Object();
private int serviceCounter = 0;
private FileOutputStream out;
private boolean shuttingDown;
#Override
public void init(ServletConfig servletConfig) throws ServletException {
super.init(servletConfig);
}
#Override
protected void service(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
enteringServiceMethod();
try {
super.service(httpServletRequest, httpServletResponse);
out = new FileOutputStream("C:\\xampp\\tomcat\\webapps\\myapp\\WEB-INF\\lib\\counter.txt");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
#Override
protected void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
if (!shuttingDown) {
writeToFile("number of servlet access = " + serviceCounter );
}
}
#Override
public void destroy() {
...
}
private void enteringServiceMethod() {
synchronized (lock) {
serviceCounter++;
writeToFile("method enteringServiceMethod serviceCounter = " + serviceCounter);
}
}
private int getNumServices() {
synchronized (lock) {
return serviceCounter;
}
}
private void writeToFile(String text) {
System.out.println(text);
text += "\r\n";
try {
out.write(text.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
}
What i need is every time someone opens my Servlet, it should open "counter.txt" file and store a number of how many times the Servlet was opened. for example if the file hold number 8 then after someone accesses the servlet it should store number 9 and delete number 8. does it make sense? can anyone help me override writeToFile method. the code that i wrote is incomplete, but i'm stuck, tried several things and nothing seems to work.

If you are trying to count page hit, then Filter would be the nice approach
Intercept each request and take a synchronized variable in application scope and increment it

Related

How to get the XML from POST request and modify it in Servlet Filter?

I am currently working on a requirement where I need to get the XML (from POST request) in the servlet filter before the request reaches to the Spring controller and then I need to process the XML (cut off some empty nodes/elements) in the filter and then the call should proceed further.
I tried the below code (attached only snippet) and I was able to get the request body (XML) and able to set the modified response.
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
if (httpRequest.getMethod().equalsIgnoreCase("POST")) {
extractDataFromRequest(httpRequest);
httpResponse.getWriter().write("<root><root>");
}
chain.doFilter(request, wrappedResponse);
public static String extractDataFromRequest(HttpServletRequest request) throws IOException {
String line;
StringBuilder builder = new StringBuilder();
BufferedReader reader = request.getReader();
while ((line = reader.readLine()) != null) {
builder.append(line);
}
return builder.toString();
}
However, spring failed with the following exception.
Severe: java.lang.IllegalStateException: PWC3997: getReader() has already been called for this request
at org.apache.catalina.connector.Request.getInputStream(Request.java:1178)
at org.apache.catalina.connector.RequestFacade.getInputStream(RequestFacade.java:407)
at org.springframework.http.server.ServletServerHttpRequest.getBody(ServletServerHttpRequest.java:165)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:120)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:100)
I am looking for a concrete implementation for this requirement from experts.
You can't use the InputStream twice, you need to create a wrapper class which keeps a repeatable copy of the InputStream.
public class ReadTwiceHttpServletRequestWrapper extends HttpServletRequestWrapper {
private ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
public ReadTwiceHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
try {
IOUtils.copy(request.getInputStream(), outputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(new ByteArrayInputStream(outputStream.toByteArray())));
}
#Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
return new ServletInputStream() {
#Override
public int readLine(byte[] b, int off, int len) throws IOException {
return inputStream.read(b, off, len);
}
#Override
public boolean isFinished() {
return inputStream.available() > 0;
}
#Override
public boolean isReady() {
return true;
}
#Override
public void setReadListener(ReadListener arg0) {
// TODO Auto-generated method stub
}
#Override
public int read() throws IOException {
return inputStream.read();
}
};
}
public void setBody(String body) {
outputStream = new ByteArrayOutputStream();
try {
outputStream.write(body.getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public String getBody() {
return new String(outputStream.toByteArray());
}
}
Then you need to initialise that with a Filter which is first in the chain.
public class ReadTwiceFilter implements Filter {
#Override
public void destroy() {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
ReadTwiceHttpServletRequestWrapper readTwiceHttpServletRequestWrapper = new ReadTwiceHttpServletRequestWrapper(
(HttpServletRequest) request);
String newBody = readTwiceHttpServletRequestWrapper.getBody().replace("<soap:studentId>1</soap:studentId>", "<soap:studentId>2</soap:studentId>");
readTwiceHttpServletRequestWrapper.setBody(newBody);
chain.doFilter(readTwiceHttpServletRequestWrapper, response);
}
#Override
public void init(FilterConfig arg0) throws ServletException {
}
}
Change your implementation in the filter to use getInputStream instead of getReader method. This issue arises when the overall implementation invokes both getReader and getInputStream method on ServletRequest.
As mentioned in javadoc, only one of them can be called. Looking at the stacktrace; the controller(spring mvc) is invoking getInputStream on it and hence failing with a message getReader() has already been called...

Using Nonblocking I/O feature of Servlets 3.1 on tomcat 8

Has anyone tried Servlets 3.1 non blocking technique on tomcat?
The request from the browser seems to be waiting forever but when I run the server in debug mode, the call returns but still I don't see "Data read.." and "Data written.." in the logs.
Servlet:
#WebServlet(urlPatterns = "/asyncn", asyncSupported = true)
public class AsyncN extends HttpServlet {
private static final long serialVersionUID = 1L;
#Override
protected void service(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
println("Before starting job");
final AsyncContext actx = request.startAsync();
actx.setTimeout(Long.MAX_VALUE);
actx.start(new HeavyTask(actx));
println("After starting job");
}
class HeavyTask implements Runnable {
AsyncContext actx;
HeavyTask(AsyncContext actx) {
this.actx = actx;
}
#Override
public void run() {
try {
Thread.currentThread().setName("Job-Thread-" + actx.getRequest().getParameter("job"));
// set up ReadListener to read data for processing
ServletInputStream input = actx.getRequest().getInputStream();
ReadListener readListener = new ReadListenerImpl(input, actx);
input.setReadListener(readListener);
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void println(String output) {
System.out.println("[" + Thread.currentThread().getName() + "]" + output);
}
}
Listeners:
public class ReadListenerImpl implements ReadListener {
private ServletInputStream input = null;
private AsyncContext actx = null;
// store the processed data to be sent back to client later
private Queue<String> queue = new LinkedBlockingQueue<>();
ReadListenerImpl(ServletInputStream input, AsyncContext actx) {
this.input = input;
this.actx = actx;
}
#Override
public void onDataAvailable() throws IOException {
println("Data is now available, starting to read");
StringBuilder sb = new StringBuilder();
int len = -1;
byte b[] = new byte[8];
// We need to check input#isReady before reading data.
// The ReadListener will be invoked again when
// the input#isReady is changed from false to true
while (input.isReady() && (len = input.read(b)) != -1) {
String data = new String(b, 0, len);
sb.append(data);
}
println("Data read: "+sb.toString());
queue.add(sb.toString());
}
#Override
public void onAllDataRead() throws IOException {
println("All Data read, now invoking write listener");
// now all data are read, set up a WriteListener to write
ServletOutputStream output = actx.getResponse().getOutputStream();
WriteListener writeListener = new WriteListenerImpl(output, queue, actx);
output.setWriteListener(writeListener);
}
#Override
public void onError(Throwable throwable) {
println("onError");
actx.complete();
throwable.printStackTrace();
}
public static void println(String output) {
System.out.println("[" + Thread.currentThread().getName() + "]" + output);
}
}
public class WriteListenerImpl implements WriteListener {
private ServletOutputStream output = null;
private Queue<String> queue = null;
private AsyncContext actx = null;
WriteListenerImpl(ServletOutputStream output, Queue<String> queue, AsyncContext actx) {
this.output = output;
this.queue = queue;
this.actx = actx;
}
#Override
public void onWritePossible() throws IOException {
println("Ready to write, writing data");
// write while there is data and is ready to write
while (queue.peek() != null && output.isReady()) {
String data = queue.poll();
//do some processing here with the data
try {
data = data.toUpperCase();
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
println("Data written: "+data);
output.print(data);
}
// complete the async process when there is no more data to write
if (queue.peek() == null) {
actx.complete();
}
}
#Override
public void onError(Throwable throwable) {
println("onError");
actx.complete();
throwable.printStackTrace();
}
public static void println(String output) {
System.out.println("[" + Thread.currentThread().getName() + "]" + output);
}
}
Sysout logs:
[http-nio-8080-exec-4]Before starting job
[http-nio-8080-exec-4]After starting job
Sysout logs (when I run the server in debug mode):
[http-nio-8080-exec-6]Before starting job
[http-nio-8080-exec-6]After starting job
[http-nio-8080-exec-6]All Data read, now invoking write listener
[http-nio-8080-exec-6]Ready to write, writing data
Creating the new thread is unnecessary, set the readListener from the service method and everything will work asynchronously.
Couple of comments on your code. In the readListener you have:
while (input.isReady() && (len = input.read(b)) != -1)
would suggest instead using this to stick fully with the asynchronous api:
while (input.isReady() && !input.isFinished())
Also for your write listener you have:
while (queue.peek() != null && output.isReady())
you should reverse the conditionals to:
while (output.isReady() && queue.peek() != null)
this protects against calling ac.complete() early if the very last write goes asynchronous.

Asynchronous property in Servlet 3.0 testing query

I have implemented Asynchronous property in Servlet 3.0 using below tutorial.
http://hmkcode.com/java-servlet-3-0-asynchronous-support/
After implementing a runnable class at back-end, I have observed that the 2 threads are created and one ends up in asynchronous manner and other does back-end processing. I was able to implement successfully the mentioned Asynchronous property.
In the runnable class, I have kept a sleep of 25 seconds and I have tried using outStream.println(Calendar.getInstance().getTimeInMillis()) in the servlet class, I have observed a deviation.The time value which is printed in println is the time when the request started but the outStream is printed on the URL hit page after 25 seconds.
I just want to understand when print was framed within servlet (based on time-stamp I came to this analysis), why is it printed in servlet URL hit page after worker class sleep time.
#WebServlet(name="asyncServlet",value = {"/async"},asyncSupported = true)
public class AsyncServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
#Override
protected void handleRequest(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
servletoutputstream out = response.getoutputstream();
final AsyncContext ctx = req.startAsync();
ctx.addListener(new AsyncListener() {
#Override
public void onTimeout(AsyncEvent arg0) throws IOException {
System.out.println("onTimeout...");
}
#Override
public void onStartAsync(AsyncEvent arg0) throws IOException {
System.out.println("onStartAsync...");
}
#Override
public void onError(AsyncEvent arg0) throws IOException {
System.out.println("onError...");
}
#Override
public void onComplete(AsyncEvent arg0) throws IOException {
System.out.println("onComplete...");
}
});
ctx.start(new Runnable() {
#Override
public void run() {
try {
Thread.currentThread.sleep(1000);
} catch InterruptedException e) {
e.printStackTrace();
}
ctx.complete();
}
});
out.write("Got the request"+calendar.getinstance().gettimeinmillis());
out.close();
}
}
Here I am printing out, the time captured in out string is before the sleep time yet it is printed in after sleep time.
I have tried with PrintWriter, yet same output is observed.
Is there any way to print the response before sleep time using above code.
Below is the code that works as you want.
#WebServlet(name = "asyncServlet", value = { "/async" }, asyncSupported = true)
public class AsyncServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
final PrintWriter out = response.getWriter();
final AsyncContext ctx = req.startAsync();
ctx.addListener(new AsyncListener() {
#Override
public void onTimeout(AsyncEvent arg0) throws IOException {
System.out.println("onTimeout...");
}
#Override
public void onStartAsync(AsyncEvent arg0) throws IOException {
System.out.println("onStartAsync...");
}
#Override
public void onError(AsyncEvent arg0) throws IOException {
System.out.println("onError...");
}
#Override
public void onComplete(AsyncEvent arg0) throws IOException {
System.out.println("onComplete...");
out.close();
}
});
ctx.start(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(3000);
}catch(InterruptedException e) {
e.printStackTrace();
}
try {
out.print("<br> Got the request : "+Calendar.getInstance().getTimeInMillis()+" For Async thread :"+Thread.currentThread().getName());
out.flush();
} catch (Exception e) {
e.printStackTrace();
}
ctx.complete();
}
});
try {
long time=Calendar.getInstance().getTimeInMillis();
out.print("<br>Got the request :"+time+" For Original thread completed :"+Thread.currentThread().getName());
out.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
output :
Got the request :1426238802101 For Original thread completed :http-bio-8080-exec-14
After 3 seconds:
Got the request : 1426238805101 For Async thread :http-bio-8080-exec-9
Click here to see a demo project which contains details code of Asynchronous Servlet.

How implement generic Server-Sent Events Servlet

I'm trying implement server code of Server-Sent Events in a generic way that any Object of my application could send a message to client, so I've decided implement a specific Servlet just for SSE. The initial test codes worked like a charm, but wasn't flexible enought to send messages from different parts of my application. So I've rewrite the code in a way that all objects that has a reference to Servlet object could send a message to the clients:
public class PushServlet extends HttpServlet {
private Thread threadServlet;
private boolean processando=true;
private MensagemSSEBean mensagem;
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
threadServlet=Thread.currentThread();
response.setContentType("text/event-stream; charset=utf-8");
while (processando){
if(!pausarThread())
break;
enviarMensagemParaOCliente(response.getWriter());
}
enviarMensagemDeFechamento(response.getWriter());
}
private void enviarMensagemParaOCliente(PrintWriter saida) {
ConversorMensagemSSE conversor = new ConversorMensagemSSE();
saida.print(conversor.converter(mensagem));
saida.flush();
}
private synchronized void enviarMensagemDeFechamento(PrintWriter saida) {
mensagem.setMensagem("#FECHAR_CONEXAO#");
enviarMensagemParaOCliente(saida);
saida.close();
}
public synchronized void enviarMensagem(MensagemSSEBean mensagem) throws IOException {
this.mensagem=mensagem;
threadServlet.notifyAll();
}
public synchronized void finalizar(){
processando=false;
}
private boolean pausarThread() {
try {
threadServlet.wait();
return true;
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
}
As you can see, I pause the Servlet Thread until something call "enviarMensagem". I didn't tested this code, basically cause I don't know how I can get this Servlet object. Could someone explain me how could I get this Servlet object from any Object?? Another important question, is this the ideal approach for this kind of problem??
Finally I implemented it in a generic way. The servlet class now send keep-alive every ten seconds or the messages in a shared queue:
public class PushServlet extends HttpServlet {
private boolean processing = true;
private HttpServletResponse response;
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.response = response;
configureAndStart();
while (processing) {
try {
sendMessages();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void configureAndStart() throws IOException {
processing = true;
response.setContentType("text/event-stream; charset=utf-8");
sendMessage(new SSEMessageBean(SSEEventType.START));
}
private void sendMessages() throws IOException, InterruptedException {
SSEMessageBean message = MessageQueueController.getInstance().getNextMessage();
while (message != null) {
sendMessage(message);
message = MessageQueueController.getInstance().getNextMessage();
if (message.getEventType() != SSEEventType.END)
return;
}
Thread.sleep(10000);
sendMessage(new SSEMessageBean(SSEEventType.KEEP_ALIVE));
}
public void sendMessage(SSEMessageBean message) throws IOException {
SSEMessageConverter converter = new SSEMessageConverter();
PrintWriter out = response.getWriter();
out.print(converter.convert(message));
out.flush();
if (message.getEventType() == SSEEventType.END) {
processing = false;
out.close();
}
}
}
The objects that want send events to clients simply write in shared queue.

Application-to-Application communication through web sockets

I have some trouble getting application-to-application communication via web sockets (that is without a browser to work). Since this does not seem to be the most usual application of web sockets, I wonder if anybody has any experience doing this.
Why do I want to use web sockets?
Because of firewall issues I need to go through port 80/8080 (and I need to continue to handle some other HTTP communication, so I can't just use plain TCP/IP socket communication).
How did I try to make this work?
I'm using Jetty 8.0 both for the server and for the client. My server code:
public class WebSocketTestServlet extends WebSocketServlet {
public WebSocket doWebSocketConnect(HttpServletRequest arg0, String arg1) {
return new TestWebSocket();
}
class TestWebSocket implements WebSocket, WebSocket.OnTextMessage
{
public void onClose(int arg0, String arg1) {
}
public void onOpen(Connection arg0) {
}
public void onMessage(String messageText) {
}
}
}
My client code:
public class MyWebSocketClient{
MyWebSocketClient() throws IOException
{
WebSocketClientFactory factory = new WebSocketClientFactory();
try {
factory.start();
} catch (Exception e1) {
e1.printStackTrace();
}
WebSocketClient client = factory.newWebSocketClient();
WebSocket.Connection connection = client.open(new URI("ws://myserver:8080/testws"), new WebSocket.OnTextMessage()
{
public void onOpen(Connection connection)
{
}
public void onClose(int closeCode, String message)
{
}
public void onMessage(String data)
{
}
}).get(50, TimeUnit.SECONDS)
}
What problem do I see?
A ProtocolException
Caused by: java.net.ProtocolException: Bad response status 302 Found
at org.eclipse.jetty.websocket.WebSocketClientFactory$HandshakeConnection.closed(WebSocketClientFactory.java:423)
at org.eclipse.jetty.websocket.WebSocketClientFactory$WebSocketClientSelector.endPointClosed(WebSocketClientFactory.java:235)
at org.eclipse.jetty.io.nio.SelectorManager$SelectSet.destroyEndPoint(SelectorManager.java:948)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint.doUpdateKey(SelectChannelEndPoint.java:523)
at org.eclipse.jetty.io.nio.SelectorManager$SelectSet.doSelect(SelectorManager.java:469)
at org.eclipse.jetty.io.nio.SelectorManager$1.run(SelectorManager.java:283)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:598)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:533)
at java.lang.Thread.run(Thread.java:619)
Any idea why this is not working?
Try to add "/" at the end of your address in the client's code:
"ws://myserver:8080/testws/"
It just fixed the issue for me.
Trying to do something similar to allow WS calls to an embedded Jetty REST API...here's my echo test code (Jetty 7), HTH
public class myApiSocketServlet extends WebSocketServlet
{
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException ,IOException
{
OutputStream responseBody = response.getOutputStream();
responseBody.write("Socket API".getBytes());
responseBody.close();
}
public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol)
{
return new APIWebSocket();
}
class APIWebSocket implements WebSocket, WebSocket.OnTextMessage
{
Connection connection;
#Override
public void onClose(int arg0, String arg1)
{
}
#Override
public void onOpen(Connection c)
{
connection = c;
}
#Override
public void onMessage(String msg)
{
try
{
this.connection.sendMessage("I received: " + msg);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}

Categories

Resources