Using Apache POI to create Presentations from your XPages application

Introduction

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?

sample_layout

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:

ref_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) {
System.out.println(docId);
try {

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

XMLSlideShow ppt;
try {
ppt = new XMLSlideShow( NAPIUtils.loadBinaryFile( session.getServerName(),session.getCurrentDatabase().getFilePath(), “Duffbeers.pptx”));
//System.out.println(ppt.getProperties());
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()) {
System.out.println(layout.getType());
}
}

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);
title01.setText(doc.getItemValueString(“refName”));

/*
* 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);
title02.setText(“Strength”);
XSLFTextShape body02 = slide02.getPlaceholder(1);
Vector < String > strength = doc.getItemValue(“refStrength”);
for (int i = 0; i < strength.size(); i++) {
body02.addNewTextParagraph().addNewTextRun().setText(strength.get(i));
}

/*
* Add another slide based on TITLE_AND_CONTENT layout
*/
XSLFSlide slide03 = ppt.createSlide(defaultLayout);
XSLFTextShape title03 = slide03.getPlaceholder(0);TutorialsPoint
title03.setText(“Weakness”);
XSLFTextShape body03 = slide03.getPlaceholder(1);
Vector <String> weak = doc.getItemValue(“refWeakness”);
for (int i = 0; i < weak.size(); i++) {
body03.addNewTextParagraph().addNewTextRun().setText(weak.get(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);
body04.clearText();

XSLFTextRun textRunLine2 = body04.addNewTextParagraph().addNewTextRun();
textRunLine2.setText(doc.getItemValueString(“refLinkLabel”));
XSLFHyperlink link04 = textRunLine2.createHyperlink();
link04.setAddress(doc.getItemValueString(“refLinkURL”));

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

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.setContentType(“application/vnd.openxmlformats-officedocument.presentationml.presentation”);
response.setHeader(“Cache-Control”, “no-cache”);
response.setHeader(“Content-Disposition”, “inline; filename=” + filename);
response.setDateHeader(“Expires”, -1);
ppt.write(writer);
writer.flush();
writer.close();
fc.responseComplete();
} catch (Exception e) {
e.printStackTrace();
}

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

doc.recycle();

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

 

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:

<managed-bean>
<managed-bean-name>Presentation</managed-bean-name>
<managed-bean-class>org.quintessens.Output</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>

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”>
<xp:this.action><![CDATA[#{javascript:Presentation.createPptx(ReferenceController.objectId);}]]></xp:this.action>
</xp:eventHandler>
</xp:button>

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!

result

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 !

new release XPages OpenLog Logger and custom runtime error page

Introduction

Good news for me! In an XPage application I wanted to provide an error logging function and preferably to OpenLog. I had problems with implementing the previous version of OpenLog logger but yesterday a new version is released on OpenNTF which took away that pain.

OpenLog logger

The OpenLog logger has some powerful features:

  • It can be used in your managed beans and other Java classes.
  • It can be used directly from SSJS with as little as openLogBean.addError(e,this);.
  • From SSJS all caught errors on the page are logged out together, at the end of the request.
  • Only two method names are used from SSJS, one to add an error, one to add an event, making it easy to pick up
  • From SSJS you only need to pass the information you wish. There is no need to pass nulls or empty strings.
  • From SSJS only one unique error per component is logged, regardless of how many times the error is encountered during the refresh lifecycle.
  • In SSJS, if you use a custom error page, uncaught errors will also be logged.
  • Uncaught errors will be logged for the page the error occurs on, not your custom error page.
  • You can define the OpenLog path and a variety of other variables without needing to change the code.
  • The functionality and code are available as an OSGi plugin (the best practice approach) but can also be included in individual NSFs.

Custom Runtime Error Page

In case you want to implement such functionality then I recommend you also take a look at how to define a custom run time error page. In my project I am using Bootstrap for UI look & feel, so I followed the steps Erick McCormick provides in this blog post.

code-prettify

In Erick’s post you will find that he uses Google’s code-prettify project. A nice feature is to ability to set a skin for the error message box. There are plenty of color themes available for the prettify project but if you use Bootstrap like I do you could try this theme.

A big thank you to the OpenLog logger project members and Erick!

custom_error_page

 

Demo of the Single Page Application Wizard control

You can bring a IBM Notes application without much work to the web browser via the Notes Browser plugin. But since Mobile is the standard nowadays that plugin seems to be obsolete almost. So what other options do you have for your enterprise apps?

  • You can introduce a mobile application platform, if you have the time and the money.
  • You can migrate your whole collaboration platform in exchange for something less, similar or not similar at all. And prey for mobile tools on that platform.
  • You can rewrite your apps and deliver them with the help of frameworks as mobile web application or in between solution.

Or… you save yourself the time & bucks and install the Extension Library version that contains the Single Page Application wizard from OpenNTF.

I have made a video in which I demonstrate how to mobilize the fakenames application in a couple of minutes. First I will describe the wizard and how the process for mobilizing an app looks like. Then I demonstrate the actual development which will take about 8 1/2 minutes.

Update – watch on Vimeo

Video on Vimeo: http://vimeo.com/99537780 in case you experience the message ‘This video is not available in your country’.

Youtube

Enjoy the video!

In case you want to contact me on mobilizing your Notes app, just send me an email.

 

Distribution of the extension library

I have written a document on the distribution of the extension library. I have compared Upgrade Pack installation option with using an Update Site. You may guess who has become the winner. If there is anything incorrect stated in the document please let me know.

PDF: Distribution Extension Library

Contents

  • Introduction. 2
    • Description. 2
    • Upgrade Pack. 2
    • Update Site database. 2
  • Discussion. 3
    • Physical installation versus runtime installation. 3
    • Administration overhead. 3
    • IBM support. 3
    • Speed in delivery of new functionality. 4
    • Proven technology versus Experimental phase. 4
  • Comparison. 4
    • Winner. 4
  • References. 5
    • XPages Extensibility API Developers Guide. 5
    • Installing and administering the XPages Extension Library. 5
    • XPages Extension Library Deployment in Domino 8.5.3. 5

Introduction

This document discusses the (recommended) way the extension library is distributed within Organization X.

Description

Based on the XPages Extensibility API, the Extension Library provides a set of new artifacts, including controls, which introduces extended capabilities to supplement XPages.

At the moment we see the library distributed in 2 ways:

  • Upgrade Pack.
  • Update Site database.

Upgrade Pack

The Upgrade Pack is an installation package that contains new features and improvements in Domino Designer.

The main functionality highlights of this upgrade pack include the following:

  • XPages Extension Library.
  • Domino Designer tooling plug-in.
  • Domino Data Services.
  • Updated TeamRoom and Discussion templates.

The XPages Extension Library provides additional controls that are ready to use.

The Upgrade Pack is restricted to a specific release of Domino. Currently there is 1 version released which is dedicated to Domino 8.5.3.

The Upgrade Pack 1 is supported by IBM.

Update Site database

An Eclipse update site is a repository for features and plug-ins and it follows a standard format. In IBM Notes the update site is an NSF application where OSGi bundles are dynamically contributed to the OSGi runtime of the Domino server.

The Extension Library will be uploaded to the Update Site application from where it is made available.

A great advantage of this approach is that plugins are not physically installed on the server but started up on HTTP startup of the Domino server.

The Domino OSGi launcher will automatically detect which version of a plugin it should use. Multiple versions of the Extension Library can be hosted by an update site. This increases the delivery of new functionality.

The Extension Library for an Update Site is distributed via OpenNTF at http://extlib.openntf.org/.

Discussion

There should be a discussion what the preferred way to distribute the extension library is. Each method has its advantages and disadvantages:

  • Physical installation versus runtime installation.
  • Administration overhead.
  • IBM support.
  • Speed in delivery of new functionality.
  • Proven technology vs. Experimental phase.

Physical installation versus runtime installation

The installation (and de-installation) via an Upgrade Pack is a physical installation and demands that a server must be shut down. The installation via an Update Site is not a physical installation and the server does not have to be shut down, only the HTTP task has to be restarted on the server.

The Update Site can be installed on multiple servers via replication and hereby the installation of the Extension Library on multiple servers can be accelerated.

There is a downside to the runtime installation. A Notes server has to have defined in the Notes.INI settings that dynamic bundles can be installed in OSGI via HTTP reset:

http://www-10.lotus.com/ldd/ddwiki.nsf/dx/XPages_Extension_Library_Deployment#Set+the+Notes.INI+variable+-+OSGI_HTTP_DYNAMIC_BUNDLES

In order to have this Notes.INI setting in place the server has to be restarted once.

Administration overhead

The Extension Library provided via OpenNTF has continuous new releases. Most of these releases are bug fixes and the others provide new functionality.

It is likely that developers demand after the installation of latest release via an Update Site, in order to have access to the new functionality. This will create extra requests and administration overhead.

On the other side the physical downtime of a server has a very high impact also on the administration side (announcements, change requests, fall back servers, incident reports sent by ignorant users).

IBM support

Upgrade Pack is “supported” by IBM. You can discuss what that means. For certain you can make a PMR (problem management record) but it is not known if IBM is providing hotfixes for bug fixes for the Upgrade Pack.

Experiences in other PMR’s on Notes software (NTF templates for Notes) have not been positive always.

On the other hand one cannot really say that distribution of the Extension Library from OpenNTF via an Update Site is “not supported” by IBM. Since the release of the Extension Library there have been multiple releases (over 30) of the Extension Library. Most of these releases are bug fixes assumed.

There is a lively discussion on the Extension Library on OpenNTF http://www.openntf.org/internal/home.nsf/discussions.xsp?action=openDocument&name=XPages%20Extension%20Library&documentId=523C4281B0889F12862577910060E232 which makes the necessity of support from IBM less.

Speed in delivery of new functionality

In Today’s world software suppliers provide more often software updates silently on the background to boost security or to provide new functionality. In the browser world this seems almost to have become a standard.

Being able to deliver new functionality more quickly can bring extra value to the business.

An Upgrade Pack has only been released once until now. The announced Upgrade Pack 2 seems only to be focused on Notes Traveller. In the meantime more than 30 releases are available for the Extension Library on OpenNTF.

Proven technology versus Experimental phase

Upgrade Pack 1 contains only a stable version of the Extension Library.  The Extension Library on OpenNTF contains also experimental features (e.g. Social, RDBMS support). These features will someday reside in the ‘ordinary’ Extension Library.

The features are collected in an Extended Components library. This Extended Components library must be installed via an Update Site. From discussions on the internet it seems to be possible to install this library on top of an Upgrade Pack via and Update Site. But why use 2 methods to distribute functionality when you can combine them via one (via Update Site)?

Comparison

Based upon the previous discussion we will compare the two methods.

Upgrade Pack Update Site
Installation Physical Runtime
Administration 1 version Multiple versions
Support IBM (PMR) OpenNTF (defect, discussion)
New functionality New Upgrade (once 2 years?) New Release (each 2 months)
Proven vs Experimental Proven Proven + Experimental

Winner

The overall ‘winner’ in this comparison is the distribution via an Update Site. A runtime installation offers a lot of benefits above a physical installation:

  • Quick installation.
  • Availability server.
  • Replication option installation software.
  • New functionality.

There are some drawbacks:

  • A server needs to have the OSGI_HTTP_DYNAMIC_BUNDLES Notes.INI property which requires a restart of the server.
  • Installed versions of the Upgrade Pack should be removed first.

References

XPages Extensibility API Developers Guide

http://www-10.lotus.com/ldd/ddwiki.nsf/dx/Master_Table_of_Contents_for_XPages_Extensibility_APIs_Developer_Guide

Installing and administering the XPages Extension Library

http://www-10.lotus.com/ldd/ddwiki.nsf/xpDocViewer.xsp?lookupName=Domino+Designer+XPages+Extension+Library#action=openDocument&res_title=Installing_and_administering_the_XPages_Extension_Library_ddxl853&content=pdcontent

XPages Extension Library Deployment in Domino 8.5.3

http://www-10.lotus.com/ldd/ddwiki.nsf/dx/XPages_Extension_Library_Deployment