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!