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 !

Discussion: Integration points between Domino and Connections/SharePoint?

With some days out of office due to some family extension I am a bit low profile on anything in the Yellowsphere.

So with a mini-me in one hand and the laptop in the other I try to see  stuff more in reflection. One thing that affects my future is the discussion and choice of a social platform.

I never have had a good feeling about (or received the request to investigate) the following question:

What are the integration points between Domino and Connections/SharePoint? Which platform has the most or best advantages for existing ‘Notes’ customers?