Solved

PDF does not open

Posted on 2004-10-13
5
1,066 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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

Online Training Solution

Drastically shorten your training time with WalkMe's advanced online training solution that Guides your trainees to action. Forget about retraining and skyrocket knowledge retention rates.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

For beginner Java programmers or at least those new to the Eclipse IDE, the following tutorial will show some (four) ways in which you can import your Java projects to your Eclipse workbench. Introduction While learning Java can be done with…
By the end of 1980s, object oriented programming using languages like C++, Simula69 and ObjectPascal gained momentum. It looked like programmers finally found the perfect language. C++ successfully combined the object oriented principles of Simula w…
Viewers will learn about the regular for loop in Java and how to use it. Definition: Break the for loop down into 3 parts: Syntax when using for loops: Example using a for loop:
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.

726 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