RAD Table walker

For a project I received some very unclear description for a change. After a conversation I came up with the suggestion to rebuild the UI and present a Bootstrap table with add and delete buttons. Something what developers would call a table walker.

So how did I do this?

First I had to extend the Model object of my MVC model. The table repeats rows with persons details so I added:

The Person class is simplified as followed:

On my model object I also added getters and setters and and an add method:

Then I had to build the table with the following important elements:

  • a repeat control to represent my arraylist of Person objects
  • input fields bounded to the Person name and email
  • a button for each row to remove the Person from the arraylist
  • a button to display a new blank row to register a new Person

The code is not that long or complicated. I highlighted the important parts with bleeding yellow:

In the next phase I decided to replace the input field the name field with namespickers (by first name or by last name) wrapped as Bootstrap field add-ons. Here is the rough code:

This all resulted in a nice BS table with add / remove buttons:

Now I am just waiting for customer approval. That is mostly the longest part in Rapid Application Design.

Getting the Select2-to-Tree working in XPages

In a modernization project (increase browser compatibility) I needed a more simple solution for a custom value picker. The less design elements the merrier 🙂

Another highly desired feature was to have a search function within the picker because there are a lot of values to choose from.

So my initial though was to present the options in a listbox and wrap the select2 plugin around it. Well it turned out the customer found the categorization of options a need to have, including collapse and expand options (who has not grown up with twisties?).

Next attempt was to implement the Select2-to-tree plugin since it presents a hierarchy of links in a select2 object

Looks familiar like a Notes view right? Luckily my Notes view only got one level of categorization and my skills with transforming Notes view data into other objects came in handy. So in a short time I have my data providing REST service setup .

Here is the initiation script for the plugin:

Then I tried to send the selected value to the server to check the value but I was not able to. The XPage did not send a message but the page just frooze.

So to avoid to spend a lot of time on finding and fixing the bug I decided to run the alternative route and use SELECT element instead of the xp:listBox and write the value from csjs to the server via a RPC service (hence the change listener)


The RPC service has nothing special, just setting a viewScope variable:

So that is basically it. With a minimum of design elements / coding I got my Notes view data in a treeview presented in a select2 component:

One item to be removed from my back-log. Happy development 🙂

Data for Bootstrap Treeview from a Notes View?

In a modernization project (increase of browser compatibility) I needed to find a solution for a list of links, categorized and sorted like a Notes View.

Since I already use Bootstrap as CSS framework I decided to check the following Bootstrap Treeview project: https://github.com/jonmiles/bootstrap-treeview .  I was satisfied with the following example(s):


The initialisation is pretty simple:


Now I just needed to set up a REST service to provide me the data. The service is setup on an XPage and bounded to a Java class:


The Java class I will reuse for providing multiple data streams so it detects the different method parameters:


As mentioned the data for the list comes from a Notes View. As you all know views entries have different characteristics which I have to bear in mind:

  • Documents can land anywhere in the view since it is categorized on a text field where the multiple levels can set individually eg Europe\\Sweden\\Stockholm or Afrika\\Johannesburg.
  • The view also holds links for other menus organized under a category so I decided to us a viewnavigator and start collecting data from a specific category.
  • For each entry in the view I have to check what type it is: category, document or total. The last one is not of my interest so I have to skip if that option occurs.
  • The columnindentlevel tells me all about where I am in the view in comparison with the columnindentlevel of the previous entry. Here are the scenarios:

// case 1: current indent level < columnindentlevel
// -> new category, propobably start situation
// case 2: current indent level = column indentlevel
// -> new category (sibling) but close the previous
// one first (just one level)
// case 3: current indent level > column indent
// level -> new category but closes the previous
// one(s) first. how many depends on difference curr
// and column level

Ofcourse categories behave different that documents.

So here is the code:


Some notes:

  • I have set the header of the REST service to text/html and the plugin needs a JavaScript object. Therefor capture my data response in an eval() method.
  • A target attribute is not provided by the plugin, so I add one myself. Categories have the # as href so based on that info I include a target attribute or not. I do this via a function:
  • If the treeview is collapsed there is no anchor element for underlying list-items so you cannot add the target for all links.
  • Also when collapsing and expanding a category the added target attributes are gone. So for opening of every category you need to re-apply the href attribute for underlying anchors.
  • A category can be opened via a ‘twistie’ image or the text link so we need to register an action on these onclick events

The result is a nice looking ‘Notes View data-driven’ treeview with Bootstrap styling:


Happy coding 🙂

PS. I noticed I have a lot of unused local variables in my code, you may clean that up 🙂

Debugging utility in XPages

Time to re-open an previous XPages project and add some new functionalities for the users. When I did this today I noticed some programming that I never wrote about before, so I do this now 🙂

In an application I wanted to monitor individual classes and write the findings to the console or OpenLog. All managed from a web UI 🙂

The printing method in this app is pretty simple:

public void printToConsole(String msg){
String callerClassName = getCallerCallerClassName();
if (debugClasses.containsKey(callerClassName)){
if (false != debugClasses.get(callerClassName)){
if (true == this.openLog){
OpenLogUtil.logEvent(new Throwable(), msg, Level.INFO, null);

The getCallerClass method identifies which class is calling this method:

public static String getCallerCallerClassName() {
StackTraceElement[] stElements = Thread.currentThread().getStackTrace();
String callerClassName = null;
for (int i=1; i<stElements.length; i++) {
StackTraceElement ste = stElements[i];
if (!ste.getClassName().equals(KDebug.class.getName())&& ste.getClassName().indexOf(“java.lang.Thread”)!=0) {
if (callerClassName==null) {
callerClassName = ste.getClassName();
} else if (!callerClassName.equals(ste.getClassName())) {
return ste.getClassName();
return null;

Here is the KDebug class :

package com.wordpress.kwintessential.myproject.utils;

public class KDebug {
public static String getCallerClassName() {
StackTraceElement[] stElements = Thread.currentThread().getStackTrace();
for (int i=1; i<stElements.length; i++) {
StackTraceElement ste = stElements[i];
if (!ste.getClassName().equals(KDebug.class.getName()) && ste.getClassName().indexOf(“java.lang.Thread”)!=0) {
return ste.getClassName();
return null;

debugClasses is declared as followed:

private HashMap<String,Boolean> debugClasses = new HashMap<String,Boolean>();

And it is set when I initiate my utility class that contains the printing method:

public void setDebugClasses(){

try {
Properties debugs = this.getDebugProperties();
Enumeration<String> enums = (Enumeration<String>) debugs.propertyNames();

while (enums.hasMoreElements()) {
Boolean boolean1 = false;
String key = enums.nextElement();
String value = debugs.getProperty(key);
boolean1 = Boolean.valueOf(value);
debugClasses.put(key, boolean1);
} catch (IOException e) {


method getDebugProperties reads a properties file that is stored in the WebContent directory:


public Properties getDebugProperties() throws IOException {
InputStream input = FacesContext.getCurrentInstance().getExternalContext().getResourceAsStream(“monitor.properties”);
Properties debugs = new Properties();
return debugs;

Note that I have to place the file in the WebContent folder and I could not place it as a Resource design element.

The monitor.properties file contains key values pairs e.g.:


So with this code above I can:

  • check which class is calling the print method
  • check if this class should be monitored (read: print data to the console or OpenLog)

So all great! But in my case I wanted to prevent that the design had to be opened and rebuild every time the monitor settings should be altered.

So in this project I created a web UI (XPage) to read and change the monitor.properties file:

<?xml version=”1.0″ encoding=”UTF-8″?>
<xp:view xmlns:xp=”http://www.ibm.com/xsp/core”&gt;

<xp:this.beforePageLoad><![CDATA[#{javascript:var file = param.get(“filename”)
if (null == file || file == “”){
ctx = facesContext.getExternalContext();
ctx.redirect(facesContext.getExternalContext().getRequest().getRequestURL() + “?filename=monitor.properties”);
<xp:panel styleClass=”container”>

<h1>Debug <small> Monitor Java classes</small></h1>

disabled=”true” />
<xp:br />

cols=”80″ />
<xp:br />
<xp:panel styleClass=”btnBar”>
<xp:button value=”Load” id=”buttonLoad”
<xp:eventHandler event=”onclick” submit=”true”
refreshMode=”complete” action=”#{fileBean.loadData}”>
<xp:button value=”Save” id=”buttonSave”>
<xp:eventHandler event=”onclick” submit=”true”
refreshMode=”complete” action=”#{fileBean.saveData}”>

Here is how it looks in a browser:

web ui initial.JPG

When I press the Load button the content of the monitor.properties file get’s loaded:

web ui loaded

And of course when I press the Save button the monitor.properties file get’s updated 🙂

Now where is the magic in this? I got two methods fileBean.loadData and fileBean.saveData.

Here is what the fileDataBean class looks like:

import java.io.IOException;
import java.io.Serializable;
import java.util.Properties;

import lotus.domino.NotesException;

import com.paulwithers.openLog.OpenLogUtil;

public class FileDataBean implements Serializable {

private static final long serialVersionUID = 1L;
private String fileName;
private String fileData;
private String dbPath;
private String dbServer;

private Utils utils;
Properties props;

public FileDataBean() throws NotesException{
utils = new Utils();
utils.printToConsole(this.getClass().getSimpleName().toString() + ” – FileDataBean() // constructor”);
try {
props = utils.getDataSourceProperties();
dbServer = props.getProperty(“server_namis_notesname”);
dbPath = utils.getSession().getCurrentDatabase().getFilePath();
} catch (IOException e) {

public String getDbPath() {
return dbPath;

public void setDbPath(String dbPath) {
this.dbPath = dbPath;

public String getDbServer() {
return dbServer;

public void setDbServer(String dbServer) {
this.dbServer = dbServer;

public void setFileData(String fileData) {
this.fileData = fileData;

public String getFileData() {
return fileData;

public void setFileName(String fileName) {
this.fileName = fileName;

public String getFileName() {
return fileName;

public void loadData() {
this.fileData = NAPIUtils.loadFile(this.dbServer, this.dbPath, this.fileName);

public void saveData() {
NAPIUtils.saveFile(this.dbServer, this.dbPath, this.fileName, this.fileData);

The NAPIUtils looks as followed:

import java.io.InputStream;
import com.ibm.designer.domino.napi.NotesAPIException;
import com.ibm.designer.domino.napi.NotesDatabase;
import com.ibm.designer.domino.napi.NotesNote;
import com.ibm.designer.domino.napi.NotesObject;
import com.ibm.designer.domino.napi.NotesSession;
import com.ibm.designer.domino.napi.design.FileAccess;
import com.paulwithers.openLog.OpenLogUtil;

public class NAPIUtils {

* loads a given WebContent file and returns the result as String
* @param serverName
* the server to use
* @param dbPath
* the database path
* @param fileName
* the file to load
* @return the file data as String
static public String loadFile(final String serverName, final String dbPath, final String fileName) {
NotesSession nSession = null;
NotesDatabase nDatabase = null;
NotesNote nNote = null;
try {
nSession = new NotesSession();
// open database
nDatabase = nSession.getDatabaseByPath(serverName + “!!” + dbPath);
// load existing data
nNote = FileAccess.getFileByPath(nDatabase, fileName);
// get Filedate and return String
InputStream is = FileAccess.readFileContentAsInputStream(nNote);

return convertStreamToString(is);
} catch (NotesAPIException e) {
} finally {
// recycle NAPI objects
recycleNAPIObject(nNote, nDatabase, nSession);

return fileName;

* loads a given WebContent file and returns the result as String
* @param serverName
* the server to use
* @param dbPath
* the database path
* @param fileName
* the file to load
* @param fileData
* the data of the file
static public void saveFile(final String serverName, final String dbPath, final String fileName, final String fileData) {

NotesSession nSession = null;
NotesDatabase nDatabase = null;
NotesNote nNote = null;

try {
nSession = new NotesSession();
// open database
nDatabase = nSession.getDatabaseByPath(serverName + “!!” + dbPath);
// load existing data
nNote = FileAccess.getFileByPath(nDatabase, fileName);
// store them to note
FileAccess.saveData(nNote, fileName, fileData.getBytes());
} catch (NotesAPIException e) {
} finally {
// recycle NAPI objects
recycleNAPIObject(nNote, nDatabase, nSession);

* converts an input stream to a string
* @param is
* the input stream to convert
* @return String
static String convertStreamToString(java.io.InputStream is) {
java.util.Scanner s = new java.util.Scanner(is).useDelimiter(“\\A”);
return s.hasNext() ? s.next() : “”;

* recycleNAPIObject helper method for recycling NAPI objects
* @param nObjects
* the NAPI objects to recycle
static void recycleNAPIObject(NotesObject… nObjects) {
for (NotesObject nObject : nObjects) {
if (nObject != null) {
try {
} catch (NotesAPIException ne) {

From this class I use the loadFile and saveFile methods. Look at the import of the com.ibm.designer.domino.napi classes which enables me to access files within the NSF!

Hopefully this writing gives you some new ideas for your development projects. Happy coding 🙂

Quickly adding localization to an XPages app

I needed to quickly make an application available in multiple languages. Luckily I had all strings already gathered in a properties file. So the following things I needed to add:

  • A translated version of the strings properties file
  • Some sort of navigation to choose another language than the browser default one.

For the first step Google Translate was my friend. Step two was not so hard either:


So a couple of minutes work and a surprised customer 🙂


A generic approach to display Notes data via a Bootstrap table

This week I became inspired by a question I noticed on Stackoverflow regarding collecting values from Java objects.

For a project we were discussing what to use for display “Notes View data”:

  • jQuery DataTables plugin and use a customRestService via a Java class as data provider for the JSON.
  • a Repeat control and display an Arraylist of Java objects.

Some of the participants liked the jQuery approach because it provides a lot of functionality out of the box (sorting, search, responsiveness,…) and their lack in knowledge regarding Java.

Others were questioning of the Repeat control approach would be flexible enough so we could display easy different sets of data with different number of columns.

So… to the drawing board.

Mostly in Notes views (e.g. via the View Panel control) one column serves as link (often the first) and all others just display data of all kind. In the DataTables plugin the display is flexible because you can define a custom render function for each column which is great. So you could display a button that will call a dialog to interact with the underlying document for example. However this custom render definition resides in a CSJS library so becomes part of the design.

I had already a custom control that could consume properties for the data and how to set a fixed set of columns. So the last part I needed to make flexible.

Because I have an arraylist of Java objects as source for my Repeat control I need to access the fields “on the fly” when rendering the column values. This turned out to be quiet simple because the fields are already in my Java object.

In my approach I provide the columns via a JSON object that could look as followed:



And for my columns I repeat it and collect the value from my underlying Java object:


Note: my code is not final, I would to define more types of data and the option to provide a custom render function for each column. So far I only have computation for string and date fields.

I also applied some basic functionality as Pager controls (top + bottom), a Page Sizer control, icon display and row numbering.

Here is what a result might look like:


Nothing special but now now I have just one custom control to display 80% of my tables/views.

Here are the GIST files for the custom control and its configuration xml file.

IBM Champion Nomination

Is this blog-article useful to you? Perhaps you can nominate me as IBM Champion.

Using the beanNamePicker dataProvider for a namepicker

For an application I needed to provide a namepicker with data from a NotesView. Unfortunately I could not use the default dominoViewNamePicker option as the data provider because the column to select from may not be a multi-value field or contain multiple fields. 😕

A search on google provided me an example how to use a beanNamePicker that will read the data from Domino Directories.

I created a GIST for the XPage: https://gist.github.com/PatrickKwinten/0bcc951a8eb1f5ef287c0c9b05a535a3 and for the Java class it uses: https://gist.github.com/PatrickKwinten/4aa15ea09717833bcc9fd1a941d9e5a8 .

Basically here is how you set it up:

<xe:namePicker id=”npDomino” for=”person1″>
<xe:beanNamePicker dataBean=”org.wordpress.quintessens.demo.app.NamePickerDirectory”

Key is that you return an object of type SimplePickerResult containing a list of objects of type <IPickerEntry>.

For my case I needed to go to a view where all the activities for users for the application where logged. Again I used a similar setup:

<xe:namePicker id=”npDomino” for=”person1″>
<xe:beanNamePicker dataBean=”org.wordpress.quintessens.demo.app.NamePickerView”

But now I go to a different class which I created a Gist for: https://gist.github.com/PatrickKwinten/c3580344a48704b3589251c0d5bbb8e5 .

Key difference is that my data source has become a Notes view and I check the type of column (columnValue instanceof String, ArrayList, Vector) because I have different type of fields and values in my first column.

So once you understand how you can extend the basic functionality within XPages you gain much flexibility and new opportunities with out of the box controls.

Please IBM provide us with more examples!!!

IBM Champion Nomination

Is this blog-article useful to you? Perhaps you can nominate me as IBM Champion.



Java and XPages

I still meet Domino developers who want to use XPages in the way IBM told them how to use it. Completely wrong I would say. Now that you have to chance to learn Java skills – EMBRACE IT!

Okay the other way around is sometimes a pain in the ass and complete examples are scarce but it gives you a better way to control your application and it’s behavior. After a while you get better understanding of the underlying technique and there is nothing wrong with that.

At the end it is mostly about creating, reading, updating and deleting stuff.

So for those developers I have setup a simple presentation to get a better understanding of JSF, Java and XPages:

Send a message from your XPage application to a Slack channel


While everyone is ‘waiting in vain’ for the delivery of Project Toscana organizations have start using Slack as a modern way to send messages within departments.

For an example a operation team is using an instructions quality book build on XPages and it would be great to get notified in your Slack channel when new instructions come in or have been updated. Or you want to highlight a specific instruction just to create extra attention to it (e.g. an increasing number of incoming incidents).


Be creative with use-cases 🙂

Slack integration points

Incoming Webhooks are a simple way to post messages from external sources into Slack. They make use of normal HTTP requests with a JSON payload, which includes the message and a few other optional details described later.

JSON, HTTP request… this sounds doable with XPages! So what are the steps you must take?

Setup your integration

Go to http://yourteam.slack.com/apps/build/custom-integration and click on Incoming Webhooks, then select a channel or user you want to post your messages to.

Setup your message

You have two options for sending data to the Webhook URL above:

  • Send a JSON string as the payload parameter in a POST request
  • Send a JSON string as the body of a POST request

Simple message

For a simple message, your JSON payload could contain a text property at minimum. This is the text that will be posted to the channel e.g.:

payload={"text": "This is a line of text in a channel.\nAnd this is another line of text."}

You can decorate your message with text formatting. You will find descriptions in the custom integration page on Slack.

Message attachments

To display a richly-formatted message attachment in Slack, you can use the same JSON payload as above, but add in an attachments array. Each element of this array is a hash containing the following parameters:

	"fallback": "Required text summary of the attachment that is shown by clients that understand attachments but choose not to show them.",

	"text": "Optional text that should appear within the attachment",
	"pretext": "Optional text that should appear above the formatted data",

	"color": "#36a64f", // Can either be one of 'good', 'warning', 'danger', or any hex color code

	// Fields are displayed in a table on the message
	"fields": [
			"title": "Required Field Title", // The title may not contain markup and will be escaped for you
			"value": "Text value of the field. May contain standard message markup and must be escaped as normal. May be multi-line.",
			"short": false // Optional flag indicating whether the `value` is short enough to be displayed side-by-side with other values

Send the message

With a simple post request you send the message in JavaScript:

function postMessageToSlack(url){
webhook_url = url;
payload= JSONStr;
var xmlhttp = new XMLHttpRequest();
xmlhttp.open('POST', webhook_url, false);
xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');


This whole approach I have added as an XSnippet on OpenNTF:


You can customize it to your needs. Basically I have a script block and a button on a custom control. Via the Property Definition tab you can set the desired values. In my example I am sending a message to a Slack channel about a picture / document in my Bildr application (shameless plug).

Here is how the message could look like:


Since my XPages app is running on a local development machine it is of no use to send sampel thumbnails of the page, but I could. This also refers to the user icon, which could be the icon of the application.

So grab the snippet and start integrating your XPages with Slack (untill Toscana arrives) !

FYI: I am not aware of any restrictions on the number of message you may send to Slack. Please let me know if you have details on this.

Add 20 years of experience to your workforce

You can 20 years of experience within IBM Notes and Web development to your workforce by hiring me.

Interested? Read my curriculum vitae on LinkedIn: http://www.linkedin.com/in/patrickkwinten and get in contact.

I am happy to work WITH you !


Using Apache POI to create Presentations from your XPages application


Apache POI is perhaps THE Java API for Microsoft Documents, if you do not live in the Microsoft bubble. It inspired people to build the Poi4XPages plugin to easily generate Word and Excel Files out of XPages (using data from Notes documents).

Yeah but Microsoft Office has so many other great types of documents you might think. Take for example PowerPoint presentations. Have you ever met a sales guy without one?


It turns out that it not that hard to use Apache POI to create powerpoint slides. I will describe how you can start developing your own solution in a few steps.

Step 1 – Download and install Apache POI

You have the link so download the library. While I was developing my application a new release (v3.15, September 21) came out so this project is alive an kicking.

I added the following jar files to my webcontent/web-inf/lib folder and added them to the build path so they appear as referenced libraries:


Step 2 – Write some code

In my application I want to use data that is stored in Notes documents in the presentation slides. I also want to import a template first, so I have some styling for the slides e.g. background image.

Note that I am not a PowerPoint export, so my template might be far from correct. I store the presentation in my NSF so in order to import it into my PPT object I am using Sven Hasselbachs Domino Napi Utility class. For this class I need to add the lwpd.domino.napi.jar file on my Domino server to the build path of my application,

With this in place I could write my Output class:

package org.quintessens;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Vector;

import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.ServletOutputStream;
import lotus.domino.NotesException;
import lotus.domino.Session;
import lotus.domino.Document;

import org.apache.poi.xslf.usermodel.SlideLayout;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFHyperlink;
import org.apache.poi.xslf.usermodel.XSLFSlide;
import org.apache.poi.xslf.usermodel.XSLFSlideLayout;
import org.apache.poi.xslf.usermodel.XSLFSlideMaster;
import org.apache.poi.xslf.usermodel.XSLFTextBox;
import org.apache.poi.xslf.usermodel.XSLFTextRun;
import org.apache.poi.xslf.usermodel.XSLFTextShape;

import com.ibm.domino.xsp.module.nsf.NotesContext;
import com.ibm.xsp.webapp.XspHttpServletResponse;

import ch.hasselba.napi.NAPIUtils;

public class Output {

NotesContext nct = NotesContext.getCurrent();
Session session = nct.getCurrentSession();

public void createPptx(String docId) {
try {

Document doc = session.getCurrentDatabase().getDocumentByUNID(docId);
DateFormat dateFormat = new SimpleDateFormat(“yyyy/MM/dd HH:mm:ss”);
Date date = new Date();

XMLSlideShow ppt;
try {
ppt = new XMLSlideShow( NAPIUtils.loadBinaryFile( session.getServerName(),session.getCurrentDatabase().getFilePath(), “Duffbeers.pptx”));
int slideCounter = ppt.getSlides().size();
System.out.println(“contains ” + slideCounter + ” number of slides”);
// first see what slide layouts are available :
System.out.println(“Available slide layouts:”);
for (XSLFSlideMaster master: ppt.getSlideMasters()) {
for (XSLFSlideLayout layout: master.getSlideLayouts()) {

XSLFSlideMaster defaultMaster = ppt.getSlideMasters().get(0);
XSLFSlideLayout defaultLayout = defaultMaster.getLayout(SlideLayout.BLANK);

* Add a slide based on TITLE_ONLY layout
defaultLayout = defaultMaster.getLayout(SlideLayout.TITLE_ONLY);
XSLFSlide slide01 = ppt.createSlide(defaultLayout);
XSLFTextShape title01 = slide01.getPlaceholder(0);

* Add a slide based on TITLE_AND_CONTENT layout
defaultLayout = defaultMaster.getLayout(SlideLayout.TITLE_AND_CONTENT);
XSLFSlide slide02 = ppt.createSlide(defaultLayout);
XSLFTextShape title02 = slide02.getPlaceholder(0);
XSLFTextShape body02 = slide02.getPlaceholder(1);
Vector < String > strength = doc.getItemValue(“refStrength”);
for (int i = 0; i < strength.size(); i++) {

* Add another slide based on TITLE_AND_CONTENT layout
XSLFSlide slide03 = ppt.createSlide(defaultLayout);
XSLFTextShape title03 = slide03.getPlaceholder(0);TutorialsPoint
XSLFTextShape body03 = slide03.getPlaceholder(1);
Vector <String> weak = doc.getItemValue(“refWeakness”);
for (int i = 0; i < weak.size(); i++) {

* Add another slide based on TEXT layout
defaultLayout = defaultMaster.getLayout(SlideLayout.TEXT);
XSLFSlide slide04 = ppt.createSlide(defaultLayout);
XSLFTextShape title04 = slide04.getPlaceholder(0);
title04.setText(“Link(s) of interest”);TutorialsPoint
XSLFTextShape body04 = slide04.getPlaceholder(1);

XSLFTextRun textRunLine2 = body04.addNewTextParagraph().addNewTextRun();
XSLFHyperlink link04 = textRunLine2.createHyperlink();

// 0-based index of a slide to be removed
for (int i = 0; i < slideCounter; i++) {

String filename = doc.getItemValueString(“refName”) + “.pptx”;

TutorialsPointFacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ex = fc.getExternalContext();
XspHttpServletResponse response = (XspHttpServletResponse) ex.getResponse();

try {
ServletOutputStream writer = response.getOutputStream();
response.setHeader(“Cache-Control”, “no-cache”);
response.setHeader(“Content-Disposition”, “inline; filename=” + filename);
response.setDateHeader(“Expires”, -1);
} catch (Exception e) {

} catch (NotesException e1) {
// TODO Auto-generated catch block
} catch (IOException e1) {
// TODO Auto-generated catch block


} catch (NotesException e2) {
// TODO Auto-generated catch block


In this example I am creating new 4 slides, with different layouts and content. You can be creative as you like and for example format text and present them as hyperlinks or include images.

Step 3 – Register a managed bean and call the code

With the java class Output written I can register it as a managed bean in the faces-config file:


This makes it easy to call the code from anywhere. The only think I need to provide is an universal ID of a document:

<xp:button id=”button4″ value=”Download as Presentation” styleClass=”pull-right btn-primary”
style=”margin-right:5px;”><i class=”fa fa-slideshare” aria-hidden=”true”></i>

<xp:eventHandler event=”onclick”
submit=”true” refreshMode=”complete”>

In my button the ReferenceController.objectId will provide the universal Id of a Notes document. I am using a controller class to get the value from a document, instead of a DominoDocument data-soruce.

With this in place. We are basically good to go! With just 1 click any sales guy can now create a corporate presentation from a Notes document and start spreading the word!


If you want to know more about Apache Poi, Powerpoint files and XPages I am happy to answer your questions. I can also recommend to read the XSLF Cookbook or the Apache Poi PPT tutorial on TutorialsPoint.

Add 20 years of experience to your workforce

You can 20 years of experience within IBM Notes and Web development to your workforce by hiring me.

Interested? Read my curriculum vitae on LinkedIn: http://www.linkedin.com/in/patrickkwinten and get in contact.

I am happy to work WITH you !