Solved

PDF does not open

Posted on 2004-10-13
5
1,062 Views
Last Modified: 2012-05-05
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




0
Comment
Question by:nateforrest1
  • 3
  • 2
5 Comments
 
LVL 92

Expert Comment

by:objects
ID: 12303715
Download and save the generated file to disk and check that file.
0
 

Author Comment

by:nateforrest1
ID: 12308808
I tried to save it and open it, but the PDF was still corrupted.
0
 
LVL 92

Accepted Solution

by:
objects earned 500 total points
ID: 12312849
Is the file different when dowmloaded with different browsers?
0
 

Author Comment

by:nateforrest1
ID: 12313470
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!
0
 
LVL 92

Expert Comment

by:objects
ID: 12313487
good to hear you got it resolved :)
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
create a gui in perl 3 46
Image decoding from Camera 3 48
thymeleaf natural templating vs JSP 2 30
Java Jpanels and Jframe 8 20
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
Introduction This article is the last of three articles that explain why and how the Experts Exchange QA Team does test automation for our web site. This article covers our test design approach and then goes through a simple test case example, how …
Viewers will learn about if statements in Java and their use The if statement: The condition required to create an if statement: Variations of if statements: An example using if statements:
This video teaches viewers about errors in exception handling.

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now