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.ByteArrayOutputStr eam;
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.ServletExcep tion, java.io.IOException {
System.out.println("TESTIN G!!!");
DocumentException ex = null;
ByteArrayOutputStream baosPDF = null;
try {
System.out.println("...... .......... .....1");
baosPDF = generatePDFDocumentBytes(r eq);
System.out.println("...... .......... .....2");
StringBuffer sbFilename = new StringBuffer();
sbFilename.append("filenam e_");
sbFilename.append(System.c urrentTime Millis());
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-Cont rol", "max-age=30");
System.out.println("...... .......... .....4");
resp.setContentType("appli cation/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.toStrin g());
resp.setContentLength(baos PDF.size() );
System.out.println("baosPD F.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(f inal 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.getClas s().getNam e());
doc.addCreationDate();
doc.addProducer();
doc.addCreator(this.getCla ss().getNa me());
doc.addTitle("This is a title.");
doc.addKeywords("pdf, itext, Java, open source, http");
System.out.println("...... .......... ..E");
doc.setPageSize(PageSize.L ETTER);
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( makeGeneralRequestDetailsE lement(req ) );
doc.newPage();
doc.add( makeHTTPHeaderInfoElement( req) );
doc.newPage();
doc.add( makeHTTPParameterInfoEleme nt(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.hasMoreEl ements())
{
String strHeaderName = (String) enumHeaderNames.nextElemen t();
String strHeaderValue = req.getHeader(strHeaderNam e);
if (strHeaderValue == null)
{
strHeaderValue = "";
}
mapHeaders.put(strHeaderNa me, 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 makeGeneralRequestDetailsE lement(
final HttpServletRequest req)
{
Map mapRequestDetails = new TreeMap();
mapRequestDetails.put("Sch eme", req.getScheme());
mapRequestDetails.put("HTT P method", req.getMethod());
mapRequestDetails.put("Aut hType", req.getAuthType());
mapRequestDetails.put("Que ryString", req.getQueryString());
mapRequestDetails.put("Con textPath", req.getContextPath());
mapRequestDetails.put("Req uest URI", req.getRequestURI());
mapRequestDetails.put("Pro tocol", req.getProtocol());
mapRequestDetails.put("Rem ote address", req.getRemoteAddr());
mapRequestDetails.put("Rem ote host", req.getRemoteHost());
mapRequestDetails.put("Ser ver name", req.getServerName());
mapRequestDetails.put("Ser ver port", "" + req.getServerPort());
mapRequestDetails.put("Pre ferred 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 makeHTTPParameterInfoEleme nt(
final HttpServletRequest req)
{
Map mapParameters = null;
mapParameters = new java.util.TreeMap(req.getP arameterMa p());
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("Except ion = " + 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
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.ByteArrayOutputStr
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.ServletExcep
System.out.println("TESTIN
DocumentException ex = null;
ByteArrayOutputStream baosPDF = null;
try {
System.out.println("......
baosPDF = generatePDFDocumentBytes(r
System.out.println("......
StringBuffer sbFilename = new StringBuffer();
sbFilename.append("filenam
sbFilename.append(System.c
sbFilename.append(".pdf");
System.out.println("......
//////////////////////////
// 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-Cont
System.out.println("......
resp.setContentType("appli
System.out.println("......
//
//
// 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(
sbContentDispValue.append(
sbContentDispValue.append(
resp.setHeader(
"Content-disposition",
sbContentDispValue.toStrin
resp.setContentLength(baos
System.out.println("baosPD
ServletOutputStream sos;
sos = resp.getOutputStream();
baosPDF.writeTo(sos);
sos.flush();
}
catch (DocumentException dex)
{
resp.setContentType("text/
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(f
throws DocumentException
{
System.out.println("......
Document doc = new Document();
ByteArrayOutputStream baosPDF = new ByteArrayOutputStream();
PdfWriter docWriter = null;
System.out.println("......
try
{
System.out.println("......
docWriter = PdfWriter.getInstance(doc,
System.out.println("......
doc.addAuthor(this.getClas
doc.addCreationDate();
doc.addProducer();
doc.addCreator(this.getCla
doc.addTitle("This is a title.");
doc.addKeywords("pdf, itext, Java, open source, http");
System.out.println("......
doc.setPageSize(PageSize.L
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("......
doc.add(new Paragraph(
"This is a multi-page document."));
doc.add( makeGeneralRequestDetailsE
doc.newPage();
doc.add( makeHTTPHeaderInfoElement(
doc.newPage();
doc.add( makeHTTPParameterInfoEleme
}
}
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(
{
Map mapHeaders = new java.util.TreeMap();
Enumeration enumHeaderNames = req.getHeaderNames();
while (enumHeaderNames.hasMoreEl
{
String strHeaderName = (String) enumHeaderNames.nextElemen
String strHeaderValue = req.getHeader(strHeaderNam
if (strHeaderValue == null)
{
strHeaderValue = "";
}
mapHeaders.put(strHeaderNa
}
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 makeGeneralRequestDetailsE
final HttpServletRequest req)
{
Map mapRequestDetails = new TreeMap();
mapRequestDetails.put("Sch
mapRequestDetails.put("HTT
mapRequestDetails.put("Aut
mapRequestDetails.put("Que
mapRequestDetails.put("Con
mapRequestDetails.put("Req
mapRequestDetails.put("Pro
mapRequestDetails.put("Rem
mapRequestDetails.put("Rem
mapRequestDetails.put("Ser
mapRequestDetails.put("Ser
mapRequestDetails.put("Pre
Table tab = null;
tab = makeTableFromMap(
"Request info",
"Value",
mapRequestDetails);
return (Element) tab;
}
/**
*
*
* @param req HTTP request object
* @return an iText Element object
*
*/
protected Element makeHTTPParameterInfoEleme
final HttpServletRequest req)
{
Map mapParameters = null;
mapParameters = new java.util.TreeMap(req.getP
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("Except
}
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
Download and save the generated file to disk and check that file.
ASKER
I tried to save it and open it, but the PDF was still corrupted.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
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("appli cation/pdf ");
resp.setStatus(HttpServlet Response.S C_OK);
System.out.println("Return ing 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("appli cation/pdf ");
resp.setStatus(HttpServlet Response.S C_OK);
System.out.println("Return ing 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!
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
resp.setContentType("appli
resp.setStatus(HttpServlet
System.out.println("Return
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("appli
resp.setStatus(HttpServlet
System.out.println("Return
return;
}
}
I also had to REMOVE the cache control headers from my JSP:
<meta http-equiv="Content-Style-
<meta http-equiv="Cache-Control"
<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 :)