2

I am using servlet which is used for open document like doc,txt,pdf,ppt etc..

my code snippet as below.

Documents document = db.getDocument(docCode);
 String contentType = document.getDocMimeType();
 byte[] docContentBytes = document.getDocContentBytes();  

 ServletOutputStream out = response.getOutputStream ();
 response.setHeader("X-UA-Compatible", "IE=8");
 response.setHeader("Content-disposition", "attachment;filename=\"Document\""); 
 response.setHeader("Pragma","private");
 response.setHeader("Cache-Control","must-revalidate, post-check=0, pre-check=0");
 response.setHeader("Content-Transfer-Encoding","binary");

 if(contentType!=null){
     response.setContentType(contentType);
 }else{
     response.setContentType("application/pdf");
 }

 BufferedInputStream bis = null;
 BufferedOutputStream bos = null;
 ByteArrayInputStream bais = null;

 if(docContentBytes != null) {
  try{
         bais = new ByteArrayInputStream(docContentBytes);
         bis = new BufferedInputStream(bais);


         bos = new BufferedOutputStream(out);
         byte[] buff = new byte[2048];
         int bytesRead;
         // Simple read/write loop.
         while(-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
         bos.write(buff, 0, bytesRead);
         }
 }catch(final MalformedURLException e) {
 System.out.println ( "MalformedURLException." );
 throw e;
 } catch(final IOException e) {
 System.out.println ( "IOException." );
 throw e;
 } finally {
     if (bais != null)
         bais.close();

         if (bis != null)
             bis.close();

         if (bos != null)
             bos.close();
 }
 } 

Now when I m trying to open multiple documents then after some time I will get broken pipe error from tomcat server.

my DataSource implementation as below.

<Resource name="jdbc/TEST_DS"
                        auth="Container"
                        type="javax.sql.DataSource"
                        driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
                        url="jdbc:sqlserver://hostName;databaseName=TEST"
                        username="test"
                        password="testPwd"
                        maxPoolSize="50" 
                removeAbandoned="true"
                        removeAbandonedTimeout="1000"
                        logAbandoned="true"
                        />

Any one can please suggest what I need to modify in this code ?

Ruchi
  • 5,032
  • 13
  • 59
  • 84

4 Answers4

1

From looking at the answers here it looks like potentially the ordering of the closing is causing the issue.

Change this code...

finally {
     if (bais != null)
         bais.close();

         if (bis != null)
             bis.close();

         if (bos != null)
             bos.close();
 }

To...

finally {
         bais.close();
         bos.close();
         bis.close();
 }
Community
  • 1
  • 1
David
  • 19,577
  • 28
  • 108
  • 128
1

There are several reasons for getting that error:

  • The network drops while the Server is attempting to communicate.
  • The user cancels the request.
  • The database is down or refuses a connection.

What you need to do it is to close in this order:

finally {
      if(bos != null)
         bos.close();
      if(bis != null)
         bis.close();
      if(bais != null)
         bais.close();
}

Hope this helps!

alicia
  • 597
  • 1
  • 5
  • 17
1

You are not supposed to close the response's outputstream. I am not sure whether this causes your broken pipe error, but I would certainly give it a try.

Documents document = db.getDocument(docCode);
String contentType = document.getDocMimeType();
byte[] docContentBytes = document.getDocContentBytes();

ServletOutputStream out = response.getOutputStream();
response.setHeader("X-UA-Compatible", "IE=8");
response.setHeader("Content-disposition", "attachment;filename=\"Document\"");
response.setHeader("Pragma", "private");
response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
response.setHeader("Content-Transfer-Encoding", "binary");

if (contentType != null) {
    response.setContentType(contentType);
} else {
    response.setContentType("application/pdf");
}


if (docContentBytes != null) {
    try {
        ByteArrayInputStream bais = new ByteArrayInputStream(docContentBytes);

        byte[] buff = new byte[2048];

        int bytesRead;
        while (-1 != (bytesRead = bais.read(buff))) {
            out.write(buff, 0, bytesRead);
        }
    } finally {
        out.flush();
    }
}

Here are some other pointers:

  • buffering the byte array inputstream doesn't make sense; you already have the data in memory

  • closing a buffered stream also closes the underlying stream

  • closing a byte array stream doesn't do anything

  • buffering the outputstream of the response doesn't make sense as you are already using a buffering mechanism in your code

  • a third party library such as common-io is very useful when dealing with streams/files (e.g. IOUtils)

  • post (a part) of your exception stack trace of you are posting a question about an exception

Pieter
  • 2,745
  • 14
  • 17
1

you already have ALL file content loaded in-memory inside byte[] docContentBytes, so why do you need buffering?

however if the exception is caused by communication error between tomcat and browser/client try to remove the buffering and set content-length.

else if the exception is caused by communication error between tomcat and SQL server, your problem is inside one of:

  • db class implementation
  • Documents implementation
  • settings/tunings in your Microsoft SQL server installation

however this is how i would have coded this servlet:

@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException
{
    Database db = Database.getInstance();

    String docCode = request.getParameter("docCode");
    if(docCode == null || docCode.isEmpty()) throw new IllegalArgumentException("docCode is null");

    Documents document = db.getDocument(docCode);
    if(document == null) throw new IllegalStateException("invalid docCode: " + docCode);

    byte[] docContentBytes = document.getDocContentBytes();
    if(docContentBytes == null) throw new IllegalStateException("document " + docCode + " has no content");

    String contentType = document.getDocMimeType();
    if(contentType == null) contentType = "application/octet-stream";

    response.setHeader("X-UA-Compatible", "IE=8");
    response.setHeader("Content-disposition", "attachment;filename=\"Document\"");
    response.setHeader("Pragma", "private");
    response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
    response.setHeader("Content-Transfer-Encoding", "binary");
    response.setContentType(contentType);
    response.setContentLength(docContentBytes.length);

    response.getOutputStream().write(docContentBytes);
}
Michele Mariotti
  • 7,372
  • 5
  • 41
  • 73