XPiNC and Attachments: A better PDF handling

For one of my customers I have created a small XPiNC application with contains a lot of documents with attached PDFs. One of the key requirements was the posibility to open and read a PDF directly in Notes Client, without storing it on the desktop.

The first thing to know is that XPiNC applications are running in XULRunner, which means that there is a compatibility to Firefox. That’s why you can use FF plugins*, for example the Foxit Reader plugin (npFoxitReaderPlugin.dll) or the original Acrobat Reader plugin.

These plugins have to be copied to the XULRunner folder, f.e.

C:\Lotus\Notes\framework\rcp\eclipse\plugins\com.ibm.rcp.xulrunner.runtime.win32.x86_6.2.3.20110915-1350\xulrunner\plugins

The plugin has to be installed/copied to each Notes client. For my customer this was no problem and could be done manually because only a small group of users will use the application.

In a second step I have created a XPage which creates the output of the attached PDF:

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false">

   <xp:this.data>
      <xp:dominoDocument var="documentAttachment" action="openDocument" />
   </xp:this.data>

   <xp:this.afterRenderResponse>
      <![CDATA[#{javascript:
         importPackage( ch.hasselba.xpages.xpinc );
         var exCon = facesContext.getExternalContext();
         var response = exCon.getResponse().getDelegate();

         AttachmentHelper.sendFile( response, session,
            documentAttachment.getDocument(), param.get("attachment") );
      }]]>
   </xp:this.afterRenderResponse>
</xp:view>

As you can see the main trick is to use the delegated response instead of the default XPages response object. And here comes the Java backend class, the attachment handler:

package ch.hasselba.xpages.xpinc;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import com.ibm.designer.runtime.util.MIME;
import lotus.domino.Document;
import lotus.domino.MIMEEntity;
import lotus.domino.MIMEHeader;
import lotus.domino.NotesException;
import lotus.domino.Session;
import lotus.domino.Stream;
import java.io.IOException;

public class AttachmentHelper {

   private final static String MIMEHEADER_CONTENTDISPOSITION = "Content-Disposition";
   private final static String MIMEHEADERVAL_ATTACHMENT = "attachment";
   private final static String MIMEHEADERPARAM_FILENAME = "filename";
   private final static String SPLIT_CHAR = "\"";

   public static void sendFile(final HttpServletResponse response,
      Session session, Document doc, final String attachmentName) {

      ServletOutputStream out = null;
      MIMEEntity mime = null;
      MIMEHeader mimeHeader = null;
      boolean flagConvertToMime;
      try {
         // get the output stream
         out = response.getOutputStream();

         // store MIME convert settings
         flagConvertToMime = session.isConvertMime();

         // switch MIME convert mode
         session.setConvertMIME(false);

         // convert Doc to MIME
         doc.convertToMIME();

         // process document as MIME
         mime = doc.getMIMEEntity();

         while (mime != null) {
            mimeHeader = mime.getNthHeader(MIMEHEADER_CONTENTDISPOSITION);
            if (mimeHeader != null) {
               if (MIMEHEADERVAL_ATTACHMENT.equals(mimeHeader
                  .getHeaderVal(true))) {

               // extract filename
               String fileName = mimeHeader.getParamVal(MIMEHEADERPARAM_FILENAME);

               // remove double slashes
               fileName = fileName.split(SPLIT_CHAR)[1];

               // set content type
               response.setContentType(MIME
                  .getMIMETypeFromExtension(MIME
                     .getFileExtension(fileName)));

               // check if this is the requested attachment
               if (attachmentName.equals(fileName)) {

                  // get MIME data as stream and send to output
                  Stream stream = session.createStream();
                  mime.getContentAsBytes(stream);
                  stream.getContents(out);
                  stream.close();
               }
            }
         }

         // next MIME entity
         mime = mime.getNextEntity(MIMEEntity.SEARCH_DEPTH);
      }

      // revert MIME conversion
      session.setConvertMIME(flagConvertToMime);

      } catch (IOException e) {
         e.printStackTrace();
      } catch (NotesException e) {
         e.printStackTrace();
      } finally {
        recycleObject(mimeHeader);
        recycleObject(mime);
      }
   }
   /**
   * recycles a domino document instance
   *
   * @param lotus
   *            .domino.Base obj to recycle
   * @category Domino
   * @author Sven Hasselbach
   * @category Tools
   * @version 1.1
   */
   public static void recycleObject(lotus.domino.Base obj) {
      if (obj != null) {
         try {
            obj.recycle();
         } catch (Exception e) {}
      }
   }
}

The document can contain more than one attachment at once. Now you can create links to this XPage in the format

PDF.xsp?documentId=<DOCUNID>&attachment=<NAME_OF_ATTACHMENT>

If you are clicking the link, the PDF will be displayed in the Notes Client:

*: there is no gurantee that other plugins are working correctly!

Dieser Beitrag wurde unter Allgemein, Infrastruktur, Java, ServerSide JavaScript, XPages, XPiNC abgelegt und mit , , , , , verschlagwortet. Setze ein Lesezeichen auf den Permalink.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.