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!