?
Solved

PDF does not open

Posted on 2004-10-13
5
Medium Priority
?
1,068 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 1500 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

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

An old method to applying the Singleton pattern in your Java code is to check if a static instance, defined in the same class that needs to be instantiated once and only once, is null and then create a new instance; otherwise, the pre-existing insta…
In this post we will learn how to connect and configure Android Device (Smartphone etc.) with Android Studio. After that we will run a simple Hello World Program.
This theoretical tutorial explains exceptions, reasons for exceptions, different categories of exception and exception hierarchy.
This tutorial explains how to use the VisualVM tool for the Java platform application. This video goes into detail on the Threads, Sampler, and Profiler tabs.
Suggested Courses
Course of the Month10 days, 17 hours left to enroll

770 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