title: What causes unbalanced begin/end text in this code?
body: <p>Sorry for the previous post to Nable.
  I was under the impression that all the higher level iText interfaces managed the begin/end text balance but the following code still fails with the unbalanced begin/end text exception.</p>
  
  <p>Could you please suggest what I am doing (not doing) to cause this imbalance.</p>
  
  <p>Cheers and thanks,
  Stephen</p>
  
  <pre><code>package com.opentext.basis.webtop.actions;
  
  import com.opentext.basis.jdbc.BasisResultSet;
  import com.opentext.basis.webtop.servlet.*;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.BufferedInputStream;
  import java.sql.SQLException;
  import java.sql.Statement;
  import java.util.List;
  import java.util.ArrayList;
  import java.util.Iterator;
  import javax.servlet.ServletOutputStream;
  import javax.servlet.http.HttpServlet;
  import javax.servlet.http.HttpServletResponse;
  import org.apache.log4j.Logger;
  import pdf.PDFFooter;
  import java.net.URL;
  import com.opentext.basis.jdbc.BasisConnection;
  import com.itextpdf.text.Document;
  import com.itextpdf.text.DocumentException;
  import com.itextpdf.text.Font;
  import com.itextpdf.text.FontFactory;
  import com.itextpdf.text.Image;
  import com.itextpdf.text.Jpeg;
  import com.itextpdf.text.Paragraph;
  import com.itextpdf.text.Phrase;
  import com.itextpdf.text.Chunk;
  import com.itextpdf.text.pdf.BaseFont;
  import com.itextpdf.text.pdf.ColumnText;
  import com.itextpdf.text.pdf.PdfPCell;
  import com.itextpdf.text.pdf.PdfPTable;
  import com.itextpdf.text.pdf.PdfWriter;
  
  // Referenced classes of package com.opentext.basis.webtop.actions:
  //            AbstractRecordAction, ResultSetBean, ActionResponse, WebtopAction
  
  // This action generates a PDF containing all thumbnails for the current set.
  
  public class tnPDF2 extends AbstractRecordAction
  implements WebtopAction
  {
  
  public tnPDF2()
  {
  }
  
  public void destroy()
  {
      super.destroy();
      mResponse = null;
  }
  
  public String getPageName()
  {
      if(mResponse != null)
          return mResponse.getPage();
      else
          return null;
  }
  
  public String getRedirectUrl()
  {
      if(mResponse != null)
          return mResponse.getURL();
      else
          return null;
  }
  
  public void doAction(HttpServlet httpservlet, Request request, HttpServletResponse httpservletresponse)
      throws SQLException, WebtopException
  {
  //
  // Get request params.
      Font [] fonts = new Font[2];
      fonts[0] = FontFactory.getFont(FontFactory.HELVETICA, 14, Font.NORMAL);
      fonts[1] = FontFactory.getFont(FontFactory.HELVETICA, 11, Font.NORMAL);
      String s = request.getParameter("s");
      Statement mS;
      BasisResultSet brs = null;
      Document document = new Document();
      PdfWriter writer;
      float[] widths = {0.08f,0.1f, 0.07f, 0.25f,0.08f,0.1f, 0.07f, 0.25f};
  
      PdfPTable pics= new PdfPTable(widths);
      pics.setWidthPercentage(100);
  
      httpservletresponse.setHeader("Pragma", "no-cache");
      httpservletresponse.setHeader("Cache-control", "no-cache");
      httpservletresponse.setHeader("Cache-control", "no-store");
      httpservletresponse.setHeader("Expires", "-1");
  
      try {             
              writer = PdfWriter.getInstance(document,httpservletresponse.getOutputStream());
              writer.setPageEvent(new PDFFooter());
  
              document.open();
  
      }
      catch (DocumentException de) {
              System.err.println(de.getMessage());
      }
      catch (Exception e2) {
              System.err.println(e2.getMessage());
      }
      WebtopSession webtopsession = request.getWebtopSession();
      mS = webtopsession.getConnection().createStatement(java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE,java.sql.ResultSet.CONCUR_READ_ONLY);
      String s1 = "select photo_no,title,date_taken,dm_blob from history(" + s + ")";
      brs = (BasisResultSet)mS.executeQuery(s1);
      String sq = brs.getSQLStatement().replaceAll("select.*NATIVE\\('","").replaceAll("'\\) order.*","");
      try {
        Phrase heading =new Phrase("Search results for: " + sq,fonts[0]);
        document.add(heading);
        document.add(Chunk.NEWLINE);
      }
      catch (DocumentException de2) {
              System.err.println(de2.getMessage());
      }
      while (brs.next()){
        String c = brs.getString("photo_no");
        if (c == null)c = "";
        pics.addCell(new Paragraph(c,fonts[1]));
        c = brs.getString("title");
        if (c == null)c = "";
        pics.addCell(new Paragraph(c,fonts[1]));
        c = brs.getString("date_taken");
        if (c == null)c = "";
        pics.addCell(new Paragraph(c,fonts[1]));
  //
        InputStream inputstream = null;
        try {
          inputstream = brs.getBinaryStream("dm_blob");
        }
        catch (Exception se) {
              System.err.println("BLOB get error " + se.getMessage());
        }
        if(inputstream == null){
              pics.addCell(new Paragraph("No thumbnail.",fonts[1]));
        } else {
              ArrayList d = new ArrayList();
              BufferedInputStream imgStream = new BufferedInputStream(inputstream);
              int n;
              try {
                while ((n = imgStream.read()) != -1)
                      d.add(new Byte((byte)n));
                imgStream.close();
                byte [] imgData = new byte[d.size()];
                Iterator it = d.iterator();
                int ix = 0;
                while (it.hasNext())
                      imgData[ix++] = ((Byte)it.next()).byteValue();
                Jpeg jpeg = new Jpeg(imgData);
                PdfPCell cl = new PdfPCell();
                cl.setImage(jpeg);
                pics.addCell(jpeg);
              }  
              catch (Exception e3){
                System.err.println(e3.getMessage());
              }
        }
      }
   // add extra empty cell to force odd last pic.
      pics.addCell(new Paragraph(" ",fonts[1]));
      pics.addCell(new Paragraph(" ",fonts[1]));
      pics.addCell(new Paragraph(" ",fonts[1]));
      pics.addCell(new Paragraph(" ",fonts[1]));
  
      try {
              document.add(pics);
      }
      catch (DocumentException de2) {
              System.err.println(de2.getMessage());
      }
      document.close();
  }
  
  private ActionResponse mResponse;
  private static final Logger gLog = Logger.getLogger("tnPDF2");
  }
  </code></pre>
  
  <p>Here is the PDFFooter code (with this included, the original fails at the document.close()):</p>
  
  <pre><code>package pdf;
  
  import java.awt.Color;
  
  import java.util.*;
  import java.text.SimpleDateFormat;
  
  import com.itextpdf.text.Document;
  import com.itextpdf.text.Element;
  import com.itextpdf.text.ExceptionConverter;
  import com.itextpdf.text.Rectangle;
  import com.itextpdf.text.pdf.BaseFont;
  import com.itextpdf.text.pdf.PdfContentByte;
  import com.itextpdf.text.pdf.PdfPTable;
  import com.itextpdf.text.pdf.PdfPageEventHelper;
  import com.itextpdf.text.pdf.PdfTemplate;
  import com.itextpdf.text.pdf.PdfWriter;
  
  
  
  public class PDFFooter extends PdfPageEventHelper
  {
         public PdfPTable table;
          /** The Graphic state */
  
          /** A template that will hold the total number of pages. */
          public PdfTemplate tpl;
          /** The font that will be used. */
          public BaseFont helv;
          public void onOpenDocument(PdfWriter writer, Document document) {
              try {
                      // initialization of the header table
                  table = new PdfPTable(1);
                  table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT);
                  table.getDefaultCell().setBorderWidth(0);
  
                  Calendar dt = Calendar.getInstance();
                  SimpleDateFormat f2 = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
                  table.addCell(f2.format(dt.getTime()));
  
  
                  // initialization of the template
                  tpl = writer.getDirectContent().createTemplate(100, 100);
                  tpl.setBoundingBox(new Rectangle(-20, -20, 100, 100));
                  // initialization of the font
                  helv = BaseFont.createFont("Helvetica", BaseFont.WINANSI, false);
              }
              catch(Exception e) {
                  throw new ExceptionConverter(e);
              }
          }    
  
  
      public void onEndPage(PdfWriter writer, Document document) {
      PdfContentByte cb = writer.getDirectContent();
      cb.saveState();
      // write the headertable
      table.setTotalWidth(document.right() - document.left());
      table.writeSelectedRows(0, -1, document.left(), document.getPageSize().getHeight() , cb);
      // compose the footer
      String text = "Page " + writer.getPageNumber() + " of ";
      float textSize = helv.getWidthPoint(text, 12);
      float textBase = document.bottom() - 20;
      cb.beginText();
      cb.setFontAndSize(helv, 12);
  
      float adjust = helv.getWidthPoint("0", 12);
      cb.setTextMatrix(document.right() - textSize - adjust, textBase);
      cb.showText(text);
      cb.endText();
      cb.addTemplate(tpl, document.right() - adjust, textBase);
      cb.saveState();
  
  
  }
  
  
  
  /**
   * @see com.itextpdf.text.pdf.PdfPageEventHelper#onCloseDocument(com.itextpdf.text.pdf.PdfWriter, com.itextpdf.text.Document)
   */
  public void onCloseDocument(PdfWriter writer, Document document) {
     tpl.beginText();
     tpl.setFontAndSize(helv, 12);
     tpl.setTextMatrix(0, 0);
     tpl.showText("" + (writer.getPageNumber() - 1));
     tpl.endText();
  }
  </code></pre>