# Tutorial: iText by Example

## iText in a Web Application

MyJavaServer.com:
All the examples in this chapter are hosted at MyJavaServer.com. MyJavaServer.com is a free J2EE hosting service, that is part of the Javalobby network of Java developer sites. As a Java developer, you can get a free Javalobby membership. This entitles you to great offers like free books, downloads, a weekly newsletter with the latest Java news and announcements, and access to a personalized version of the biggest Javadocs collection on the web: JDocs.com. In addition, you can also create your own free Java blog at the Java blogging site, JRoller.com.
Go to top of the page
Hello World:
In the general Hello World example, we created a Hello World PDF file from a standalone Java program. Now we are going to do exactly the same thing, but instead of sending the generated document to a FileOutputStream, we are going to send everything to the OutputStream of a HttpServletResponse object:

    PdfWriter.getInstance(document, response.getOutputStream());

In the example, we accept a parameter presentationtype that can be one of the following values:

- pdf
- html
- rtf

Depending on the parameter you passed, you should see a PDF, HTML or RTF page in your browser.
Example: java com.lowagie.examples.general.webapp.HelloWorldServlet
Generates a simple 'Hello World' file from a servlet (PDF, HTML or RTF)
Test this example: presentationtype=pdf presentationtype=html presentationtype=rtf
Extra jars needed in your CLASSPATH: servlet.jar
Remark that I didn't say 'you will see a PDF, HTML or RTF page in your browser'. It should work on all browsers, but we know it won't work on some. For instance: we have set the ContentType to PDF:

    response.setContentType("application/pdf");

but some browsers look at the file extension, rather than the content-type (don't ask me why). That's why we are going to use something that looks like a pdf-file (with the correct extension) as url-pattern in our web.xml file:

    <servlet-mapping>
      <servlet-name>OutSimplePdf</servlet-name>
      <url-pattern>/servlet/simple.pdf</url-pattern>
    </servlet-mapping>

Some browsers also need to know the content-length of the PDF in advance (otherwise they just give you a blank page). The only way we can work around this, is by buffering the complete file in a ByteArrayOutputStream. That's a pity, because you risk a timeout in the browser-server communication if you need to send really big or time-consuming PDFs.

    Document document = new Document();
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    PdfWriter.getInstance(document, baos);
    document.open();
    document.add(new Paragraph(msg));
    document.close();
    response.setContentType("application/pdf");
    response.setContentLength(baos.size());
    ServletOutputStream out = response.getOutputStream();
    baos.writeTo(out);
    out.flush();

Nicolas Guichard suggests to set some cache headers before writing the PDF to the ServletOutputStream. These headers determine the rules by which the page content may be cached by the client and intermediate proxies. Using these values for the cache headers may help you to avoid some problems:

    response.setHeader("Expires", "0");
    response.setHeader("Cache-Control",
    	"must-revalidate, post-check=0, pre-check=0");
    response.setHeader("Pragma", "public");

So forget about the HelloWorldServlet and use this Servlet instead:
Example: java com.lowagie.examples.general.webapp.OutSimplePdf
Generates a simple PDF file from a servlet. The file is buffered and served with the extension .pdf
Test this example: without message with message
Extra jars needed in your CLASSPATH: servlet.jar
Another annoying feature of some browsers is that they hit the server 2 or 3 times with the same request if you want to serve them a dynamically generated binary file. This type of behaviour of some browsers can be a real pain if you are updating a database or keeping statistics for every PDF that is served. Setting the cache parameters as Nicholas Guichard suggested may help, but it won't help for every browser and maybe you want other settings. So Anis H. proposed the following workaround:

    <html>
    <body leftMargin="0" topMargin="0" scroll="no">
      <embed src="http://myserver/pdfCreationServlet"
      	width="100%" height="100%"
    	type="application/pdf" fullscreen="yes" />
    </body>
    </html>

I keep on repeating 'some browsers this, some browsers that', but in reality, I'm just avoiding to be unfriendly to MicroSoft. In fact, all the problems listed above are typical for MS Internet Explorer. What I am trying to do here, is to propose a solution that works for all versions of all browsers, but don't shoot me if I fail. Every time a new version of MSIE solved one problem, another problem came across (I have stopped wondering why it's the most popular browser in the world; I just don't understand it).
Knowing MSIE gives us, iText developers, such a hard time, you can anticipate MSIE problems and redirect MSIE users to the workaround. This is some example code, written by Bill Ensley:

    <%
      String user = request.getHeader("User-Agent");
      if(user.indexOf("MSIE") != -1 && user.indexOf("Windows") != -1){
        out.print("<body leftMargin=\"0\" topMargin=\"0\" scroll=\"no\">");
        out.print("<EMBED src=\"PDFPreview.pdf?type=pdf\" "
          + "width=\"100%\" height=\"100%\" "
          + "fullscreen=\"yes\" type=\"application/pdf\">");
      }
      else{
        out.print("<body leftMargin=\"0\" topMargin=\"0\" scroll=\"no\">");
        out.print("<script>document.location = 'PDFPreview.pdf?type=pdf';</script>");
      }
    %>

I made some small changes to this code in the next example, you should try it with different browsers:
Example: UserAgent.jsp
Looks at the user-agent: if MSIE on Windows, embed the PDF; if another browser, redirect to the servlet
Test this example: try this with different browsers
Go to top of the page
Workaround for timeout problem:
As I mentioned before, it's a pity we have to buffer the complete PDF in a ByteArrayOutputStream, just because some browsers need to know the length of the generated PDF file in advance. At Ghent University I had to generate reports with grades for several thousands students in one document. Not only was the document very large, database access was rather slow too. So I had the problem that people sometimes failed to get the PDF because their browser said the connection timed out. If I had been able to serve them little bits of PDF at a time (for instance by writing some binary code directly to the ServletOutputStream each time a page was finished), this timeout wouldn't have happened.
I solved this problem by serving some HTML feedback as long as the PDF wasn't finished. The HTML would show the total number of students and the number of students that were added to the PDF so far. I also made a progressbar by stretching a pixel in an image with a width of 0 to 100 (<img src="pixel.gif" height="10" width="<%= myPdf.getPercentage() %>">). This HTML page was refreshed every 3 seconds until the PDF was finished.
In the example that follows, I have simplified this solution. You see there is a subclass MyPdf that implements Runnable. The doGet serves the HTML. The first time you hit the server a new MyPdf is added to your session and a Thread generating the PDF is started. I deliberately slowed down this process by adding Thread.sleep(500). As long as the PDF isn't generated completely (percentage < 100), I send a 'Please Wait' message to the browser. Once the PDF is finished, I send a form with a button to fetch the PDF from the doPost() method. It's a very simple solution. I am using it for 5 years now and the users of my applications at Ghent University are all very happy with it. It's not only a technical solution; it also works on a psychological level. People are rather impatient. They don't like to wait for that internet page to come, not knowing if the connection got lost, if they should hit the reload button, if the server went down... But give them some feedback and time seems to go a lot faster!
Example: java com.lowagie.examples.general.webapp.ProgressServlet
Shows how to avoid receiving a timeout in your browser if generating the PDF takes a really long time.
Test this example: show progress
Extra jars needed in your CLASSPATH: servlet.jar
Go to top of the page
Silent printing:
This is a nice example, but please be careful when you use it. Basicly, you are going to sent a PDF with some javascript to a client browser. This PDF is shown in an iframe, so the user will not necessarily see it on screen (you could for instance hide it). But the javascript action will print it directly to the default printer (as if your client pushed the Print button and the OK button on the print dialog). This is not the kind of functionality you want to put in your application without warning your users...
Example: java com.lowagie.examples.general.webapp.SilentPrintServlet
Explains how to print silently via Servlet/Browser.
Test this example: try it!
Extra jars needed in your CLASSPATH: servlet.jar
Go to top of the page
Hello World JSP:
It's always a bad idea to use JSPs to generate binary data that has to be sent to a client application. I repeat: It's always a bad idea to use JSPs to generate binary data that has to be sent to a client application. I hope you understand that it's always a bad idea to use JSPs to generate binary data that has to be sent to a client application.
OK? Now that you know that, I'll give you a small example of a JSP that generates a PDF file using iText.
Example: HelloWorld.jsp
Generates a simple 'Hello World' file from a JSP page
Test this example: HelloWorld
I like JSP. I have written JSPs myself for different HTML websites, but I haven't heard one sensible argument why people would prefer writing JSPs instead of Servlets to generate PDF. I do have some reasons why you wouldn't use JSP.
If you know JSP, you should know every JSP-file is compiled to a Servlet by your webserver (internally). You should trust me if I say writing the Servlet is easier and less error prone than writing the JSP.
This is why:

- First of all, it's hard to implement all the workarounds mentioned above in a JSP-file. The link to the JSP file in the example, works for me, it gives me a PDF file saying 'Hello World', but it will not necessarily work for you.
- Some servers assume JSP output is not binary.
  Some people on the mailing-list have testified that they can generate correct PDF files on the server from a JSP, they can open the PDF on the server and it looks as expected. But if they use the same code to send the PDF to the browser, they only see a blank page in Acrobat Reader. When they open the PDF file in a text editor, they see lots of unreadable characters in the PDF on the server. If they do the same with the PDF on the client, they see lots of questionmarks: those are bytes that are made corrupt due to the fact that the application server thought they were plain ASCII.
- If you copy the example and start working from there, you will probably add some indentation, newlines, spaces, carriage returns,... If you are used to writing JSPs, it should be your second nature to do this. This is good for most of the stuff you are writing. It has no impact on HTML pages, but now you are generating PDF. All those 'invisible' characters are compiled to a Servlet and are added to the PDF by the Servlet, not by iText. This makes your PDF corrupt! The crossreference table doesn't point to the correct bytepositions anymore. You may or may not be able to open the PDF file. You'll get all kinds of non-reproducable errors. We can't give you any support on this. Our answer will always be: use Servlets instead.

So for the last time: It's always a bad idea to use JSPs to generate binary data that has to be sent to a client application. Use Servlets instead.
Go to top of the page
Amazon books:
amazon.co.uk-link