RSS

Tag Archives: xpages

<xpt:….> – The XPages Tookit – Beta1 released

We have released an early beta of the XPages Toolkit, called beta1 on OpenNTF. A short time before I was going to the hospital for a heart revision task :). But the XPages Toolkit need some explanations about the why and what.

xptStartScreenshot

The XPages Toolkit (in short XPT) is a extendable Extension to the XPages Runtime and the Extension Library. The XPT contains a strong core for a programming model that we have introduced at WebGate as the ninja-style. I will blog later this week about this programming model and I will also make some snippets to this available.

But what contains the XPT:

  • The core (for the ninja-style / hope this name is not protected)
  • RSS Datasource and UIControl -> a ready to use UI-Element so display RSS Feeds
  • Read and write Access to properties files
  • Some missing OneUI Elements (like the aboutbox, the welcomebox and the tipbox)
  • And the XPages Agents with ready to use UI Elements and a replacment for the agents manager

And it is extendable. We have designed the XPT to make it easy to plugin other solutions. I will cover this topic also in a separate blog post. But in short, I think there are some many good things available under apache licence. Or think about the charting in dojox, its one of the things that I miss as a good UI Control. I know that there is a great OpenNTF project available from Julian Buss (YouAtNotes xCharting), but why not integrate the code into a plugin?

All the best
Christian

PS: Heart revision task was successfully completed and I have a good recovery time.

 
1 Comment

Posted by on September 23, 2013 in Architektur, OpenNTF, XPages, XPT

 

Tags: , ,

The odyssey of loading a class in a Eclipse plugin – or how we integrated docx4j in POI4XPages

While I was visiting the IBMConnect in Orlando, Lena investigated about how to convert Word files into PDFs. Because of licence reasons, we decide to use docx4j in conjunction with Apache FOP. Both projects are licensed using the Apache V2 license, in opposition to iText.

Lena built a prototype and tested it with Eclipse against the current JVM of the domino server. All worked fine and we started to integrate docx4j as new plugin project in POI4XPages. We also tested the plugin against a regular java programm. Everything worked fine.

The next step was to integrate the creation of the PDF into the UIDocument and the DocumentGeneration classes. This worked fine as well but when we started the conversion it seemed that docx4j has lost its ‘Focus’. The conversion failed because it could not find ‘docx4j.properties’ and ‘log4j.properties’.
After several attempts of building source code based of docx4j and debugging and patching it, I figured out the problem during the night. To make it short, here is the analysis of what had happened:

The problem:

The conversion function in the eclipse plugin was executed by a ClassLoader from Domino. This is not bad at all. But in this case, the context was absolutly relevant to find all the resource files in the docx4j.jar and all the classes. JAXB seems also to be classloading context sensitiv.

The solution:

We changed the ClassLoader context during the PDF conversion as you can see in the code below.
The red marked code does the trick. currentThread.setContextClassLoader( Activator.class.getClassLoader() ) changes the ClassLoader context to the context of the plugin.
When the conversion is done we change the ClassLoader context back to the old context.

public void buildPDF(InputStream isDocument, OutputStream osTarget)
throws PDFException {
Logger logCurrent = LoggerFactory.getLogger(this.getClass().getCanonicalName());
boolean blRC = true;
Exception eRESP = null;
Thread currentThread = Thread.currentThread();
ClassLoader clCurrent = currentThread.getContextClassLoader();
logCurrent.info(“Current thread class loader is: ” +clCurrent);
try {
 currentThread.setContextClassLoader(Activator.class
                    .getClassLoader());
logCurrent.info(“Getting WordprozessingPackage”);
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage
.load(isDocument);

logCurrent.info(“Getting PdfSettings”);
// 2) Prepare Pdf settings
PdfSettings pdfSettings = new PdfSettings();

// 3) Convert WordprocessingMLPackage to Pdf
logCurrent.info(“Getting PdfConversion”);
PdfConversion converter = new Conversion(wordMLPackage);

logCurrent.info(“do Conversion”);
converter.output(osTarget, pdfSettings);
} catch (Exception e) {
eRESP = e;
logCurrent.log(Level.SEVERE, “Error during PDF Conversion: “+e.getMessage(),e);
blRC = false;
} finally {
            currentThread.setContextClassLoader(clCurrent);
}
if (!blRC) {
throw new PDFException(“Error during FOP PDF Generation”, eRESP);
}
}

A happy ending to a long odyssey.
The new release of POI4XPages will be released later this week, together with some bug fixes and new features.

 
 

Tags: , ,

New Documentation for POI 4 XPAGES available

Today we released some howtos for POI 4 XPAGES on my.webgate.biz/poi.documentation.

Thanks Lena for sharing this with us.

 

Tags: ,

Documents and Spreadsheets with XPages – building the kernel (Part II)

Let us begin with building the kernel for the document processing. This kernel is also a part, which we have used as proof of concept. In the previous post (https://guedebyte.wordpress.com/2012/09/07/documents-and-spreadsheets-i/) our focus was on the idea. This entry is about the main processing.

If you want to try this in your own project, please perform the following steps:

  1. Download Eclipse Indigo

  2. Download Apache POI 3.8

  3. Prepare a project based on the following instructions of René Winkelmeyer: http://de.slideshare.net/muenzpraeger/uklug-2012-xpages-extensibility-api-going-deep (starts at page 23)

The first step is, create a “lib” directory in your project and add the apache-poi libraries to this directory.

Add the libraries to the build-path (without the commons-log and log4j), by selecting the libraries: Left click and select “Build-Path/add to build-path”.

Commons-log and log4j are not needed because the extensible API delivers his own implementation of log4j. If you need a dedicated version of those libraries, it is recommended to encapsulate the code in a separate plugin, which exports only the functionality to the plugin, which extends the api. Both plugins have to be in the same feature (we will come back to this later).

We can now build an interface, witch represents the bookmarks.

package biz.webgate.dominoext.poi.component.data.document;

public interface IDocumentBookmark {

    public String getName();

    public String getValue();

}

Programming against an interface will definitely safe time. While I was building the prototype of this application for a proof of concept, I had to build my own implementation of IDocumentBookmark, because it was not possible to solve all dependencies of the Xpages Framework. See the difference. The first sample is my prototype implementation, the second one is my library implementation:

1. Prototype implementation

import biz.webgate.dominoext.poi.component.data.document.IDocumentBookmark;

public class BMImplementation implements IDocumentBookmark {

private String m_Name;
private String m_Value;

public BMImplementation(String name, String value) {

super();
m_Name = name;
m_Value = value;

}

@Override

public String getName() {

returnm_Name;

}

@Override

public String getValue() {

return m_Value;

}

}

2. Library implementation:

package biz.webgate.dominoext.poi.component.data.document;

import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import com.ibm.xsp.complex.ValueBindingObjectImpl;

public class DocumentBookmark extends ValueBindingObjectImpl implements IDocumentBookmark {

private String m_Name;
private String m_Value;

public String getName() {

if (m_Name != null) {

return m_Name;

}

ValueBinding vb = getValueBinding(“name”);

if (vb != null) {

return (String) vb.getValue(getFacesContext());

}

return null;

}

public void setName(String name) {

m_Name = name;

}

public String getValue() {

if (m_Value != null) {

return m_Value;

}

ValueBinding vb = getValueBinding(“value”);

if (vb != null) {

return (String) vb.getValue(getFacesContext());

}

return null;

}

public void setValue(String value) {

m_Value = value;

}

@Override

public void restoreState(FacesContext context, Object value) {

Object[] state = (Object[]) value;
super.restoreState(context, state[0]);
m_Name = (String) state[1];
m_Value = (String) state[2];

}

@Override

public Object saveState(FacesContext context) {

Object[] state = new Object[3];
state[0] = super.saveState(context);
state[1] = m_Name;
state[2] = m_Value;
return state;

}

}

Now let’s build the kernel. We do a simple 3 step approach.

  1. Building a XWPFDocument (from a InputStream)

  2. Replacing all Bookmarks in the document

  3. Writing the XWPFDocument to a ByteArrayBuffer

Here is the code to build a XWPFDocument

public XWPFDocument getDocument(InputStream inDocument) {

try {

XWPFDocument dxReturn = new XWPFDocument(inDocument);
return dxReturn;

} catch (Exception e) {

e.printStackTrace();

}
return null;

}

The bookmark replacement is little bit harder. Let’s begin with the main entry:

publicint processBookmarks2Document(XWPFDocument dxProcess, List<IDocumentBookmark> arrBookmarks) {

// First Prozessing all paragraphs.

for (XWPFParagraph paraCurrent : dxProcess.getParagraphs()) {

processBookmarks2Paragraph(arrBookmarks, paraCurrent);

}

// All Tables

for (XWPFTable tabCurrent : dxProcess.getTables()) {

processBookmarks2Table(arrBookmarks, tabCurrent);

}

// All Headers

for (XWPFHeader headCurrent : dxProcess.getHeaderList()) {

for (XWPFParagraph paraCurrent : headCurrent.getParagraphs()) {

processBookmarks2Paragraph(arrBookmarks, paraCurrent);

}

for (XWPFTable tabCurrent : headCurrent.getTables()) {

processBookmarks2Table(arrBookmarks, tabCurrent);

}

}

// All Footers

for (XWPFFooter footCurrent : dxProcess.getFooterList()) {

for (XWPFParagraph paraCurrent : footCurrent.getParagraphs()) {

processBookmarks2Paragraph(arrBookmarks, paraCurrent);

}

for (XWPFTable tabCurrent : footCurrent.getTables()) {

processBookmarks2Table(arrBookmarks, tabCurrent);

}

}

return 1;

}

First we process all paragraphs in the document, followed by all tables. Then we do the same with the headers and footers. They do also contains tables and paragraphs. So let’s see how we process the paragraphs:

private void processBookmarks2Paragraph( List<IDocumentBookmark> arrBookmarks, XWPFParagraph paraCurrent) {

for (XWPFRun runCurrent : paraCurrent.getRuns()) {
processBookmarks2Run(runCurrent, arrBookmarks);
}

}

Paragraphs contain “Run” elements, which contain a text, that has the same styling and formatting. These run elements are processed in the following function:

public int processBookmarks2Run(XWPFRun runCurrent, List<IDocumentBookmark> arrBookmarks) {

String strText = runCurrent.getText(0);

if (strText != null) {

for (IDocumentBookmark bmCurrent : arrBookmarks) {

String strValue = bmCurrent.getValue();
strValue = strValue == null ? “” : strValue;

if (bmCurrent.getName() != null) {

strText = strText.replaceAll(“<<“ + bmCurrent.getName()+ “>>”, strValue);

}

}

}

runCurrent.setText(strText, 0);
return 1;

}

Our tables also contain paragraphs and run elements. We will also reuse this method. Tables are built on rows and cells, see how we browse that:

private void processBookmarks2Table(List<IDocumentBookmark> arrBookmarks, XWPFTable tabCurrent) {

for (XWPFTableRow tabRow : tabCurrent.getRows()) {

for (XWPFTableCell tabCell : tabRow.getTableCells()) {

for (XWPFParagraph paraCurrent : tabCell.getParagraphs()) {

processBookmarks2Paragraph(arrBookmarks, paraCurrent);

}

}

}

}

That’s all you need for the kernel. The full class will be available with the source code later this year. The next step is to build the UI for the domino designer. Watch out for the next episode.

 

Tags: , , , ,

JSON Arrray parsing with com.ibm.commons.util.io.json.JsonJavaFactory

I’m currently developing the backendservices for our new absenceplanner. We submit all data to a rest service (CustomRestService in the ExtLib). So this service should be able to parse an array of json data. The data has the following format:

{
“dates”:[
{“div”:”dt20120827″,”dt”:”27.08.2012″,”metadata”:{“absenceType”:”Holiday”,”allDay”:true}},
{“div”:”dt20120829″,”dt”:”29.08.2012″,”metadata”:{“absenceType”:”Compensation”,”allDay”:true}}
],
“reqTitle”:”meine wohlverdienten ferien”,
“method”:”request.submit”
}

To parse the stream in to a JsonJavaObject I’ve used:

JsonJavaFactory factory = JsonJavaFactory.instanceEx;
Reader r = request.getReader();
json = (JsonJavaObject) JsonParser.fromJson(factory, r);
String strMethod = json.getString(“method”);

It’s very easy to extract all properties. An object can also be accessed with json.getJsonObject(“name”) . But no arrays. There is no getter.

But, how did others (like the ExtLib programmers) solve this? With this question I’ve read the code of the “twitter parsing” in the sbt of the ExtLib. And I found the solution in the com.ibm.xsp.extlib.sbt.services.client.DataNavigator class, which guides me to the following code:

 

Object arrDates = factory.getProperty(json, “dates”);
for (Iterator<Object> itDate = factory.iterateArrayValues(arrDates); itDate.hasNext();) {

JsonJavaObject jsDate = (JsonJavaObject)itDate.next();
//-> here do all the funny stuff with the jsDate object.
}

Thanks to Philippe Riand (IBM) for sharing your code. Its so inspiring to read your code.

 
6 Comments

Posted by on September 11, 2012 in Java, XPages

 

Tags: , , , ,

Documents and Spreadsheets with XPages – the Idea (Part I)

In several projects we are faced with the request to export data to a spreadsheet (mostly excel) or build a document for ms-word. So our development team requested the following: “Build an extension that helps us generate word documents or export datasets to spreadsheets”.
After some research, I found a project called Apache POI.

Apache POI covers all the stories, which we try to implement. So let’s begin with the first story: “Generating a new ms-word document”.
The story is very simple, but also very powerful. In our example the starting point is a document like the OpenNTF Contributor License Agreement. This document is needed for a company to contribute code to OpenNTF. Typically, this document has some lines (fields), which you have to fill in with your values.  Let’s try to automate this process. We will build a form in the XPages application, where you can fill in your company name, address and other things. Then we modify the standard OpenNTF form a little bit, as you can see on the screenshot below:


In your XPages form we implement the new POI Document element and then we do some wiring:

  1. We define where the modified OpenNTF Licence Agreement is. This could be a file resource in the application, or a document accessible via view and a predefined key.
  2. Defining “Bookmarks”:
    As you see on the word document, we have defined several “<<NAME OF BOOKMARK>>” tags in the text. This text must be in the same style, so they are in the same “run” Element on the document.
  3. In our “POI Document” – Control could we now define a bookmark for each <<…>> element, which contains the name and a value.
  4. As you see, the value can be computed (so a binding to a viewScope variable is possible)
  5. We define a “download” button and connect the onClick event on a new action called “Generate Document”

The user can now fill in their values on the page and generate a customized word document.  Developers are able to build in applications to produce customized documents in a very short time.
In the next blog entries, we will show you how we have build an extension of this function.

 

Tags: , , , ,