Render a pdf stream on a jsp using struts2 - java

I am using struts2 in my web application. I want to render a pdf stream on a jsp. i am currently doing this:
public String renderPDF() throws Exception
{
myService.rederPDF(getServletResponse().getServletOutputStream());
return SUCCESS;
}
The rederPDF method of myService gets a pdf stream and writes to the servlet response output stream. But this throws an exception that "The response has already been committed".

This exception occurs when you already sent some thing to client before you forward.
I am using Servlets for downloading files. Have a look.
public class FileDownloadServlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
byte[] b = null;
ServletOutputStream sop = null;
try {
response.setContentType("application/pdf");
response.setHeader("Content-Disposition","attachment; filename=yourFileName.pdf");
sop = response.getOutputStream();
b = myService.getFileData(); /* your code */
sop.write(b);
return;
} catch (Exception e) {
/* some code*/
}
finally{
/* some code*/
}
}
}

Related

<error-page> is not working for servlet

when exception in servlet then is not working but for jsp its work properly
web.xml code
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/error.jsp</location>
</error-page>
servlet code
protected void processRequest(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException
{
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
/*
* TODO output your page here. You may use following sample code.
*/
String a=null;
a.toString();//this line will throw exception
}
finally {
out.close();
}
}
it does not redirect to error.jsp
Servlet code
this will throw the exception to the general error page
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
/*
* TODO output your page here. You may use following sample code.
*/
String a=null;
a.toString();
}
catch(Exception e)
{
throw new ServletException(e);
}
finally {
//dont write out.close();
}
}
when we write catch block in servlet it does not work and when we does not write catch block its work properly.
Servlet Code
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException{
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
DAL db=null;
ResultSet rs=null;
parameter p1=new parameter();
// Object param[];
// List<Object> param=new ArrayList<Object>();
long myId=0;
try {
db=new DAL();
String name=request.getParameter("fn");
db.setQuery("{call usp_StudentInsertData(?,?)}");
db.setInParam(1,name);
db.setInParam(2,1000);
db.insertUpdate();
out.println("insert");
response.sendRedirect("home.jsp");
}
catch(Exception e)
{
}
finally {
}
}

Reading binary data from HttpServletRequest

Using Jetty, I'm sending bytes to URL http://localhost:8080/input/ like so -
public static void sampleBytesRequest (String url)
{
try
{
HttpClient client = new HttpClient();
client.start();
client.newRequest(url)
.content(new InputStreamContentProvider(new ByteArrayInputStream("batman".getBytes())))
.send();
}
catch (Exception e) { e.printStackTrace(); }
}
My server (also Jetty) has a handler like so -
public final class JettyHandler extends AbstractHandler implements JettyConstants, LqsConstants
{
#Override
public void handle (String target,
Request baseRequest,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType(UTF_ENCODING);
String requestBody = null;
try { requestBody = baseRequest.getReader().readLine(); }
catch (IOException e) { e.printStackTrace(); }
System.out.println(new String(IOUtils.toByteArray(request.getInputStream())));
}
}
As you can see, I'm trying to recreate the original string from the binary data and print it to stdout.
However, if I set a break point at the print statement in the handler, when the request reaches that line, the server abruptly seems to skip over it.
What am I doing wrong? How can I get the binary data I'm sending over and recreate the string?
Thank you!
Turns out the issue was with my client.
Instead of
client.newRequest(url)
.content(new InputStreamContentProvider(new ByteArrayInputStream("batman".getBytes())))
.send();
The proper way to do this is -
client.newRequest(url)
.content(new BytesContentProvider("batman".getBytes()), "text/plain")
.send();

HTML5 Server Sent Event Servlet on Tomcat 7 buffers events until socket close

I'm trying to add a server side event servlet to my web application. Below is the code for my servlet: ( Several different versions )
Using getOutputStream():
#WebServlet(urlPatterns = {"/hello"}, asyncSupported = true)
public class HelloServlet extends HttpServlet
{
private static final long serialVersionUID = 2889150327892593198L;
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.setContentType("text/event-stream");
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Connection", "keep-alive");
response.setCharacterEncoding("UTF-8");
ServletOutputStream out = response.getOutputStream();
try{
for(int i=0; i<10; i++) {
out.print("id: "+ i +"\n");
out.print("data: "+ System.currentTimeMillis() +"\n\n");
out.flush();
response.flushBuffer();
System.out.println("time sent:"+ System.currentTimeMillis());
System.out.println("IsCommitted:" + response.isCommitted() );
Thread.sleep(1000);
}
}
catch(Exception e)
{
e.printStackTrace();
}
out.close();
}
}
Using PrintStream:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.setContentType("text/event-stream");
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Connection", "keep-alive");
response.setCharacterEncoding("UTF-8");
PrintWriter writer = response.getWriter();
try{
for(int i=0; i<10; i++) {
writer.write("id: "+ i +"\n");
writer.write("data: "+ System.currentTimeMillis() +"\n\n");
writer.flush();
response.flushBuffer();
System.out.println("time sent:"+ System.currentTimeMillis());
System.out.println("IsCommitted:" + response.isCommitted() );
Thread.sleep(1000);
}
}
catch(Exception e)
{
e.printStackTrace();
}
writer.close();
}
An Async Version using https://github.com/mariomac/jeasse
SseDispatcher dispatcher = null;
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
System.out.println("test started. Async mode.");
startThread();
dispatcher = new SseDispatcher(req).ok().open();
}
private void startThread()
{
Thread thread = new Thread()
{
#Override public void run()
{
System.out.println("Thread started");
try {
for(int i=0; i<10; i++)
{
System.out.println("Sending message " + i);
onGivenEvent("message"+1, System.currentTimeMillis()+"" ) ;
Thread.sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
}
dispatcher.close();
System.out.println("Thread ending");
}
};
thread.setDaemon(true);
thread.setName("testsse");
thread.start();
System.out.println("Starting thread");
}
public void onGivenEvent(String eventName, String data) throws IOException
{
if( dispatcher != null)
{
dispatcher.send(eventName, data);
}
}
For all version I'm using curl to validate it:
curl -i -H "Accept: application/json" -X GET http://localhost:8080/testsse/hello
The output only comes at the end when the connection is closed by the server. If the servlet does not close the connection you never get the output.
I need the events to arrive after the server sends them, and not when the connection is closed. What am I doing wrong? This cannot be the way its supposed to work.
I've googled and tried many examples and they all suffer from this same issue.
I've tried many different versions of tomcat 7.0.67, 7.0.34, 7.0.62. I'm using 64 bit version of JDK 8.0.65 on Windows or JDK 8.0.45 on Linux.
Does anyone have this working? What am I doing wrong?
I figured out a solution to this. I switched to using Jersey SSE and it functions as expected.
I could never get the above solution to function correctly. The Server buffered all the IO until the connection closed. I tried all kinds of flushing and manipulating the buffer size.
Hopefully this helps... Start with another framework such as Jersey SSE.

When response is delivered to client in asynchronous Servlets?

I'm having problems understanding how asynchronous servlets work, and in general how servlets deliver their response to the client.
What I'm trying to do is upload a video to a servlet via ajax. I thought that using an async servlet, I would obtain the response immediately in my browser and then the long task would be done in another thread.
I post my initial code here, before any code is written for file process, just an initial servlet to test asynchronism.
#WebServlet(name = "VideoUploader", urlPatterns = {"/VideoUploader"},
asyncSupported = true)
#MultipartConfig
public class VideoUploader extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
final PrintWriter pw = response.getWriter();
final AsyncContext ac = request.startAsync();
ac.setTimeout(80000);
ac.addListener(new AsyncListener() {
#Override
public void onComplete(AsyncEvent event) throws IOException {
System.out.println("On complete");
}
#Override
public void onTimeout(AsyncEvent event) throws IOException {
System.out.println("On timeout");
}
#Override
public void onError(AsyncEvent event) throws IOException {
System.out.println("On error");
}
#Override
public void onStartAsync(AsyncEvent event) throws IOException {
System.out.println("On start async");
}
});
ac.start(new Runnable() {
#Override
public void run() {
for (int i = 0; i <= 10; i++) {
System.out.println("Async task: "
+ Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
ac.complete();
}
});
pw.write("end");
pw.close();
}
}
Then, the client part is:
<form id="formVideo">
<label for="videoFile">VĂ­deo:</label>
<input id="videoFile" name="videoFile" type="file" /> <br/>
<input id="uploadVideoBtn" type="button" value="Subir" onClick="uploadVideo();"/>
</form>
<div id="notificaciones"/>
<script type="text/javascript">
function uploadVideo() {
var file = document.getElementById("videoFile").files[0];
var formdata = new FormData();
formdata.append("file", file);
var xhr = new XMLHttpRequest();
xhr.open("POST","/webapp/VideoUploader", true);
xhr.send(formdata);
xhr.onload = function(e) {
if (this.status == 200) {
alert(this.responseText);
}
};
}
</script>
When I didn't attach a video to the file input, the process is done as I expected, the response is immediately received in the browser. But when I attached a file of any size, my browser doesn't receive the response until the other thread is over.
I was researching on non blocking IO, but I'm not sure if it has something to do with this behaviour or not.
I'm still not sure how I want to implement this, although I'll listen to any advice, but what I would like is to understand the behaviour of this asynchronous servlets.
it is obivious, your browser will wait until the other thread completes. The following steps involved
Client Sent Request to Server
Server allocates Thread (Servlet Container) from ThreadPool
Servlet container creates Servlet instance / reuse existisng Servlet instance and invoke Servcie method in (Servlet Thread)
With in Service method by calling startAsync() will start new thread and pass the request,response instances to the new Thread to process the request note** New Thread is not blocking the http connection , it is just a thread in the jvm which is not bliocking any IO at this moment
Servlet Thread exists service method and returned to thread pool Note** here Response not yet sent to Client / Browser
Once the Process started in step 4 completed that thread will request Servlet Container to allocate to new Servlet thread to send the respond back to Client.
Only the at Step 6 the response will return back to Client. So there is no difference between the normal request and with "asyncSupported = true" from client point of view. Servlet 3.0 supports Threads per request by using "asyncSupported = true" instead of Thread per connection. Thread per connection will cause Thread Starvation.
#WebServlet(name = "VideoUploader", urlPatterns = { "/VideoUploader" }, asyncSupported = true)
#MultipartConfig
public class VideoUploader extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
#Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
final AsyncContext ac = request.startAsync();
ac.setTimeout(80000);
ac.addListener(new AsyncListener() {
public void onComplete(AsyncEvent event) throws IOException {
System.out.println("On complete");
}
public void onTimeout(AsyncEvent event) throws IOException {
System.out.println("On timeout");
}
public void onError(AsyncEvent event) throws IOException {
System.out.println("On error");
}
public void onStartAsync(AsyncEvent event) throws IOException {
System.out.println("On start async");
}
});
ac.start(new Runnable() {
public void run() {
System.out.println("Async task: "
+ Thread.currentThread().getName());
try {
for (Part part : ((HttpServletRequest) ac.getRequest())
.getParts()) {
System.out.println("File received"); // You Should write
// file here
// like
// part.write("fileName");
}
} catch (IOException e1) {
e1.printStackTrace();
} catch (ServletException e1) {
e1.printStackTrace();
}
ac.complete();
PrintWriter pw = null;
try {
pw = ac.getResponse().getWriter();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
pw.write("end");
pw.close();
}
});
}
}
Asynchronous servlet hands over the long running server side job to a different server thread. Non-Blocking IO, a new feature in servlet 3.1, deals with situation when incoming data is blocking or streamed slower than the server can read. Both are solutions to avoid servlet thread starvation. They are not about returning response to client immediately.
Since you are using Ajax, not a regular browser file upload, it should be easily implemented at the Ajax side with even a synchronous servlet, if you do not care about servlet thread starvation. Ajax is asynchronous in nature. Here is an example tutorial
http://www.javabeat.net/asynchronous-file-upload-using-ajax-jquery-progress-bar-and-java/

The Jasper Reports servlet stopped working after calling response.getOutputStream()

I have code such as below. The program stopped working at line servletOutputStream = response.getOutputStream();. I don't know how to resolve this? Can anybody help me with this problem?
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException, SQLException, JRException, ParserConfigurationException, SAXException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
out.println ("<html>");
out.println (" <head>");
out.println (" <meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>");
out.println (" <title>JSP Page</title>");
out.println (" </head>");
out.println (" <body>");
out.println (" <h1>Hello iReport!</h1>");
String resourceName = "D:/classic.jrxml";
response.setContentType("application/pdf");
ServletOutputStream servletOutputStream = null;
servletOutputStream = response.getOutputStream(); // <--
InputStream reportStream = getServletConfig().getServletContext().getResourceAsStream(resourceName);
try {
Driver driver = new org.gjt.mm.mysql.Driver();
DriverManager.registerDriver(driver);
String conString = "jdbc:mysql://localhost:3306/quanlynhasach";
Properties info = new Properties();
info.setProperty("characterEncoding", "utf8");
info.setProperty("user", "root");
info.setProperty("password", "");
Connection con = DriverManager.getConnection(conString, info);
JasperRunManager.runReportToPdfStream(reportStream, servletOutputStream,new HashMap<Object, Object>(), con);
con.close();
}catch(Exception e){
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
e.printStackTrace(printWriter);
response.setContentType("text/plain");
response.getOutputStream().print(stringWriter.toString());
}
out.println (" </body>");
out.println ("</html>");
} finally {
out.close();
}
} // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
/**
* Handles the HTTP <code>GET</code> method.
* #param request servlet request
* #param response servlet response
* #throws ServletException if a servlet-specific error occurs
* #throws IOException if an I/O error occurs
*/
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
try {
processRequest(request, response);
} catch (ParserConfigurationException ex) {
Logger.getLogger(iReport.class.getName()).log(Level.SEVERE, null, ex);
} catch (SAXException ex) {
Logger.getLogger(iReport.class.getName()).log(Level.SEVERE, null, ex);
}
} catch (SQLException ex) {
Logger.getLogger(iReport.class.getName()).log(Level.SEVERE, null, ex);
} catch (JRException ex) {
Logger.getLogger(iReport.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* Handles the HTTP <code>POST</code> method.
* #param request servlet request
* #param response servlet response
* #throws ServletException if a servlet-specific error occurs
* #throws IOException if an I/O error occurs
*/
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
try {
processRequest(request, response);
} catch (ParserConfigurationException ex) {
Logger.getLogger(iReport.class.getName()).log(Level.SEVERE, null, ex);
} catch (SAXException ex) {
Logger.getLogger(iReport.class.getName()).log(Level.SEVERE, null, ex);
}
} catch (SQLException ex) {
Logger.getLogger(iReport.class.getName()).log(Level.SEVERE, null, ex);
} catch (JRException ex) {
Logger.getLogger(iReport.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* Returns a short description of the servlet.
* #return a String containing servlet description
*/
#Override
public String getServletInfo() {
return "Short description";
}// </editor-fold>
Look here:
PrintWriter out = response.getWriter();
// *snip*
servletOutputStream = response.getOutputStream();
You're getting both the Writer and OutputStream from the response. This is not allowed. Read their javadocs:
getOutputStream()
ServletOutputStream getOutputStream() throws java.io.IOException
Returns a ServletOutputStream suitable for writing binary data in the response. The servlet container does not encode the binary data.
Calling flush() on the ServletOutputStream commits the response. Either this method or getWriter() may be called to write the body, not both.
and
getWriter()
java.io.PrintWriter getWriter() throws java.io.IOException
Returns a PrintWriter object that can send character text to the client. The PrintWriter uses the character encoding returned by getCharacterEncoding(). If the response's character encoding has not been specified as described in getCharacterEncoding (i.e., the method just returns the default value ISO-8859-1), getWriter updates it to ISO-8859-1.
Calling flush() on the PrintWriter commits the response.
Either this method or getOutputStream() may be called to write the body, not both.
(emphasis mine)
The problem is in your particular case however much bigger. You're attempting to inline the PDF result of a Jasper Report between those HTML tags within a HTML response. I'm not sure what you thought or smoked while you wrote the code, but that is definitely not going to work. You need to rewrite the servlet that way so that it only returns the PDF and not that bunch of HTML noise. You should move all that HTML out the servlet into some JSP file. Then, you can call that servlet by a simple download link in the JSP
Download PDF
or inside an <iframe> (yes, in JSP)
<iframe src="yourServletUrl" style="width: 500px; height: 300px;"></iframe>
or in an <object> (also here, just in JSP)
<object data="yourServletUrl" type="application/pdf" width="500" height="300" />
Just put that HTML in a JSP page, open the JSP in browser and the webbrowser will take care that the servlet will be invoked and that the PDF will be represented the way you intended.
Your other problem is that the exception handling is not really good. You'll see completely nothing this way as the response buffer is not been resetted. You should instead be doing a
} catch (Exception e) {
throw new ServletException("descriptive message here", e);
}
as the container knows perfectly how to handle exceptions.
That both your doGet() and doPost() are doing exactly the same is by the way also a design smell. The JDBC driver which you used there is completely outdated and deprecated. The way how you registered the driver is clumsy. That the DB connection is not closed in finally is prone to resource leaking. Okay, I'll stop...
I presume that you are getting an IllegalStateException because you are calling getWriter() and getOutputStream() on the same response. Which you're not allowed to do.

Categories