Link to home
Start Free TrialLog in
Avatar of nateforrest1
nateforrest1

asked on

PDF does not open

I have a couple of weird things going on with my application.  When a link is clicked an Action class is called which creates a PDF document on the fly and uses the ByteArrayOutputStream to send the PDF to the browser window.  I'm getting some different behavior depending on which browser I am using:

IE(6.028) - The document displays properly, but the Action class is actually called twice.  I've checked the struts-config.xml file and my JSP page and it looks like it should only be called once.  I have read that there might be a problem with a bad <table> tag in the form that could cause this type of behavior, but it doesn't seem right to me.  

Mozilla(1.7.3), Firefox(0.10.1) - The Action class is only called once and the PDF does not display.  Instead it displays an error message of "The file is damaged and cannot be repaired".  However, this is only true if the PDF file size is more than ~50,000 bytes, anything less and the PDF displays fine.  (I put a for loop in the code that I modified to create smaller or larger files.)

I was using Adobe Reader 5.1 and experienced the same problems so I upgraded to Adobe Reader 6.0.2, but the problems still persist.


Here is the code for the test servlet:

package com.test;

import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;

// import the iText packages
import com.lowagie.text.*;
import com.lowagie.text.pdf.*;

/**
 *
 *  This servlet will generate a PDF document and send the document
 *  to the client via the ServletOutputStream
 */
public class PDFServlet extends HttpServlet {

      public PDFServlet() {
            super();
      }

      /**
       *  
       *
       * Implement doGet so that this servlet will process all HTTP GET requests
       *
       * @param req HTTP request object
       * @param resp HTTP response object
       *
       */
      public void doPost(HttpServletRequest req, HttpServletResponse resp) throws javax.servlet.ServletException, java.io.IOException {
            System.out.println("TESTING!!!");
            DocumentException ex = null;
            
            ByteArrayOutputStream baosPDF = null;
            
            try {
                  System.out.println(".....................1");
                  baosPDF = generatePDFDocumentBytes(req);
                  System.out.println(".....................2");
                  StringBuffer sbFilename = new StringBuffer();
                  sbFilename.append("filename_");
                  sbFilename.append(System.currentTimeMillis());
                  sbFilename.append(".pdf");
                  System.out.println(".....................3");
                  ////////////////////////////////////////////////////////
                  // Note:
                  //
                  // It is important to set the HTTP response headers
                  // before writing data to the servlet's OutputStream
                  //
                  ////////////////////////////////////////////////////////
                  //
                  //
                  // Read the HTTP 1.1 specification for full details
                  // about the Cache-Control header
                  //
                  resp.setHeader("Cache-Control", "max-age=30");
                  System.out.println(".....................4");
                  resp.setContentType("application/pdf");
                  System.out.println(".....................5");
                  //
                  //
                  // The Content-disposition header is explained
                  // in RFC 2183
                  //
                  //    http://www.ietf.org/rfc/rfc2183.txt
                  //
                  // The Content-disposition value will be in one of
                  // two forms:
                  //
                  //   1)  inline; filename=foobar.pdf
                  //   2)  attachment; filename=foobar.pdf
                  //
                  // In this servlet, we use "inline"
                  //
                  StringBuffer sbContentDispValue = new StringBuffer();
                  sbContentDispValue.append("inline");
                  sbContentDispValue.append("; filename=");
                  sbContentDispValue.append(sbFilename);
                                          
                  resp.setHeader(
                        "Content-disposition",
                        sbContentDispValue.toString());

                  resp.setContentLength(baosPDF.size());
                  System.out.println("baosPDF.size = " + baosPDF.size());

                  ServletOutputStream sos;

                  sos = resp.getOutputStream();
                  
                  baosPDF.writeTo(sos);
                  
                  sos.flush();
            }
            catch (DocumentException dex)
            {
                  resp.setContentType("text/html");
                  PrintWriter writer = resp.getWriter();
                  writer.println(
                              this.getClass().getName()
                              + " caught an exception: " 
                              + dex.getClass().getName()
                              + "<br>");
                  writer.println("<pre>");
                  dex.printStackTrace(writer);
                  writer.println("</pre>");
            }
            finally
            {
                  if (baosPDF != null)
                  {
                        baosPDF.reset();
                  }
            }
             
      }

      /**
       *  
       * @param req must be non-null
       *
       * @return a non-null output stream. The output stream contains
       *         the bytes for the PDF document
       *
       * @throws DocumentException
       *
       */
      protected ByteArrayOutputStream generatePDFDocumentBytes(final HttpServletRequest req)
            throws DocumentException
            
      {      
            System.out.println("..................A");
            Document doc = new Document();
            
            ByteArrayOutputStream baosPDF = new ByteArrayOutputStream();
            PdfWriter docWriter = null;
            System.out.println("..................B");
            try
            {
                  System.out.println("..................C");
                  docWriter = PdfWriter.getInstance(doc, baosPDF);
                  System.out.println("..................D");
                  doc.addAuthor(this.getClass().getName());
                  doc.addCreationDate();
                  doc.addProducer();
                  doc.addCreator(this.getClass().getName());
                  doc.addTitle("This is a title.");
                  doc.addKeywords("pdf, itext, Java, open source, http");
                  System.out.println("..................E");
                  doc.setPageSize(PageSize.LETTER);
                  
                  HeaderFooter footer = new HeaderFooter(
                                          new Phrase("This is a footer."),
                                          false);

                  doc.setFooter(footer);
            
                  doc.open();
                  for(int i = 0; i < 25; i++) {
                        System.out.println("i = " + i);
                        doc.add(new Paragraph(
                                          "This document was created by a class named: "
                                          + this.getClass().getName()));
                                          
                        doc.add(new Paragraph(
                                          "This document was created on "
                                          + new java.util.Date()));
                        System.out.println("..................F");
                        
                        doc.add(new Paragraph(
                                          "This is a multi-page document."));
                        
                        doc.add( makeGeneralRequestDetailsElement(req) );
                        
                        doc.newPage();
                        
                        doc.add( makeHTTPHeaderInfoElement(req) );
                        
                        doc.newPage();
                        
                        doc.add( makeHTTPParameterInfoElement(req) );
                  }
                  
            }
            catch (DocumentException dex)
            {
                  baosPDF.reset();
                  throw dex;
            }
            finally
            {
                  if (doc != null)
                  {
                        doc.close();
                  }
                  if (docWriter != null)
                  {
                        docWriter.close();
                  }
            }

            if (baosPDF.size() < 1)
            {
                  throw new DocumentException(
                        "document has "
                        + baosPDF.size()
                        + " bytes");            
            }
            return baosPDF;
      }
      
      /**
       *
       * @param req HTTP request object
       * @return an iText Element object
       *
       */
      protected Element makeHTTPHeaderInfoElement(final HttpServletRequest req)
      {
            Map mapHeaders = new java.util.TreeMap();
            
            Enumeration enumHeaderNames = req.getHeaderNames();
            while (enumHeaderNames.hasMoreElements())
            {
                  String strHeaderName = (String) enumHeaderNames.nextElement();
                  String strHeaderValue = req.getHeader(strHeaderName);
                  
                  if (strHeaderValue == null)
                  {
                        strHeaderValue = "";
                  }
                  mapHeaders.put(strHeaderName, strHeaderValue);
            }

            Table tab = makeTableFromMap(
                        "HTTP header name",
                        "HTTP header value",
                        mapHeaders);
            
            return (Element) tab;
      }

      /**
       *  
       * @param req HTTP request object
       * @return an iText Element object
       *
       */
      protected Element makeGeneralRequestDetailsElement(
                                    final HttpServletRequest req)
      {
            Map mapRequestDetails = new TreeMap();
             
            mapRequestDetails.put("Scheme", req.getScheme());
                        
            mapRequestDetails.put("HTTP method", req.getMethod());
                        
            mapRequestDetails.put("AuthType", req.getAuthType());
                        
            mapRequestDetails.put("QueryString", req.getQueryString());
                        
            mapRequestDetails.put("ContextPath", req.getContextPath());
                        
            mapRequestDetails.put("Request URI", req.getRequestURI());
                        
            mapRequestDetails.put("Protocol", req.getProtocol());
                        
            mapRequestDetails.put("Remote address", req.getRemoteAddr());
                        
            mapRequestDetails.put("Remote host", req.getRemoteHost());
                        
            mapRequestDetails.put("Server name", req.getServerName());
                        
            mapRequestDetails.put("Server port", "" + req.getServerPort());
                        
            mapRequestDetails.put("Preferred locale", req.getLocale().toString());
                        
            Table tab = null;
            
            tab = makeTableFromMap(
                                    "Request info",
                                    "Value",
                                    mapRequestDetails);
            
            return (Element) tab;
      }

      /**
       *
       *
       * @param req HTTP request object
       * @return an iText Element object
       *
       */
      protected Element makeHTTPParameterInfoElement(
                              final HttpServletRequest req)
      {
            Map mapParameters = null;
            
            mapParameters = new java.util.TreeMap(req.getParameterMap());

            Table tab = null;

            tab = makeTableFromMap(
                        "HTTP parameter name",
                        "HTTP parameter value",
                        mapParameters);
            
            return (Element) tab;
      }
      
      /**
       *
       * @param firstColumnTitle
       * @param secondColumnTitle
       * @param m map containing the data for column 1 and column 2
       *
       * @return an iText Table
       *
       */
      private static Table makeTableFromMap(
                  final String firstColumnTitle,
                  final String secondColumnTitle,
                  final java.util.Map m)
      {
            Table tab = null;

            try
            {
                  tab = new Table(2 /* columns */);
            }
            catch (Exception ex)
            {
                  System.out.println("Exception = " + ex.getMessage());
            }
            
            tab.setBorderWidth(1.0f);
            tab.setPadding(5);
            tab.setSpacing(5);

            tab.addCell(new Cell(firstColumnTitle));
            tab.addCell(new Cell(secondColumnTitle));
            
            tab.endHeaders();

            if (m.keySet().size() == 0)
            {
                  Cell c = new Cell("none");
                  c.setColspan(tab.columns());
                  tab.addCell(c);
            }
            else
            {
                  Iterator iter = m.keySet().iterator();
                  while (iter.hasNext())
                  {
                        String strName = (String) iter.next();
                        Object value = m.get(strName);
                        String strValue = null;
                        if (value == null)
                        {
                              strValue = "";
                        }
                        else if (value instanceof String[])
                        {
                              String[] aValues = (String[]) value;  
                              strValue = aValues[0];
                        }
                        else
                        {
                              strValue = value.toString();
                        }
                        
                        tab.addCell(new Cell(strName));
                        tab.addCell(new Cell(strValue));
                  }
            }
            
            return tab;
      }
      
}

Any help is GREATLY appreciated!

Nate




Avatar of Mick Barry
Mick Barry
Flag of Australia image

Download and save the generated file to disk and check that file.
Avatar of nateforrest1
nateforrest1

ASKER

I tried to save it and open it, but the PDF was still corrupted.
ASKER CERTIFIED SOLUTION
Avatar of Mick Barry
Mick Barry
Flag of Australia image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
No the file is the same.  I think I have a work-around for the issues I was having:

1) Instead of going through Struts have a link in the JSP that directly calls the Servlet.  --> This solved my issues with Mozilla/Firefox and I was able to see the PDF files.

2) IE was still calling the Servlet twice.  After reading more, I found that if the content-header is not received within 10 seconds that IE will make another attempt to get the response.  Since my application is crunching a lot of data its taking 15-20 seconds to create the PDF.  To fix this, I added some code to my Servlet:

                  // IE5 sends a user-agent of contype on the first request, so this can be ignored
                  if (req.getHeader("user-agent").equals("contype")) {
                        resp.setContentType("application/pdf");
                        resp.setStatus(HttpServletResponse.SC_OK);
                        System.out.println("Returning 1...");
                        return;
                  }
                  // IE 5.5 and IE 6 only has an accept-language header on the first request so if present
                  // ignore this request
                  if (theAgent.indexOf("MSIE") != -1){
                        if (accLang != null) {
                              resp.setContentType("application/pdf");
                              resp.setStatus(HttpServletResponse.SC_OK);
                              System.out.println("Returning 2...");
                              return;
                        }
                  }

I also had to REMOVE the cache control headers from my JSP:
<meta http-equiv="Content-Style-Type" content="text/css"/>
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="-1">

I'm not sure why this wasn't working in Struts but at least the process works now.  Thanks for trying to help!
good to hear you got it resolved :)