Introduction
In order to develop more inline with leading web standards more and more Domino and XPages developers find themselves attracted to use JSON as the standard to describe and transport their application data.
There are many excellent JSON libraries out there. With XPages we have immediately access to com.ibm.commons.util.io.json.
I intend to write a series of posts and tell how I will rewrite an existing XPages application and introduce Java and JSON as the new working horses in this application.
JSON and XPages
More people have written about JSON in XPages so I do not have to deep dive in that. I especially like Jeff Byrd’s post on using the JSONJavaObject class to create a JSON object from an array.
A simple first example
First let me demonstrate a simple example. We setup a simple construction we will extend in the following steps of our application modernization.
Building blocks
Here is what our construction will contain:
- a Notes view with a first column for sorting and a second column containing a JSON string
- a Java class defined as a managed bean in the faces-config file
- an XPage to display the received ArrayList with JSONObjects
Notes view
Our view looks nothing spectaculair:

Basically:
- The first column is used for sorting purpose.
- The second column constructs the JSON string.
The formula for the second column can be as followed:
REM {This column builds a JSON string};
varUNID := @Text(@DocumentUniqueID);
varCategory:= Photo_Category;
varTitle := Photo_Title;
varAuthor:=Au_Author;
varDesc:=PhotoDescription;
varCreated:=@Created;
varThumb:=Photo_ThumbFilename;
jsonOpener := “{“;
jsonClosure := “}”;
jsonSeparator := “\”,”;
jsonLastItem := “\””;
jsonOpener +
“\”docUNID\”: \”” + varUNID + jsonSeparator +
“\”author\”: \”” + @Name([CN]; varAuthor) + jsonSeparator +
“\”category\”: \”” + varCategory + jsonSeparator +
“\”subject\”: \”” + varTitle + jsonSeparator +
“\”descr\”: \”” + varDesc + jsonSeparator +
“\”created\”: \”” + @Text(@Date(varCreated)) + jsonSeparator +
“\”thumb\”: \”” + varThumb + jsonLastItem +
jsonClosure
Alternatively you can use a normal view (plain column values) and construct the JSON string later, something described here.
JAVA class
Our class has one public method called loadPictures which will call a private method that will return an arraylist of jsonjavaobjects. You notice the com.ibm.commons.util.io.json library will be used.
Don’t worry about the hard-coded server and notes view references now. This will be polished later.
package com.quintessens;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Vector;
import lotus.domino.NotesException;
import lotus.domino.Database;
import lotus.domino.Session;
import lotus.domino.View;
import lotus.domino.ViewEntry;
import lotus.domino.ViewEntryCollection;
import com.ibm.commons.util.io.json.JsonException;
import com.ibm.commons.util.io.json.JsonJavaFactory;
import com.ibm.commons.util.io.json.JsonJavaObject;
import com.ibm.commons.util.io.json.JsonParser;
import com.ibm.domino.xsp.module.nsf.NotesContext;
public class SimplePictures implements Serializable{
public static final long serialVersionUID = 1L;
public SimplePictures(){
}
public ArrayList<JsonJavaObject> loadPictures() throws NotesException{
ArrayList<JsonJavaObject> PictureCollection = new ArrayList<JsonJavaObject>();
NotesContext nct = NotesContext.getCurrent();
Session session = nct.getCurrentSession();
String ServerName = “dev1”;
String DatabaseName = session.getCurrentDatabase().getFilePath();
String ViewName = “$v-pixJSONSingle”;
String Key = “”;
Integer ColIdx = 1; //0 means first column
try {
PictureCollection = loadJSONObjects(ServerName, DatabaseName, ViewName, Key, ColIdx);
} catch (NotesException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return PictureCollection;
}
private ArrayList<JsonJavaObject> loadJSONObjects(String ServerName, String DatabaseName, String ViewName, String Key, Integer ColIdx) throws NotesException {
ArrayList<JsonJavaObject> JSONObjects = new ArrayList<JsonJavaObject>();
NotesContext nct = NotesContext.getCurrent();
Session session = nct.getCurrentSession();
Database DB = session.getDatabase(ServerName, DatabaseName);
if (!(DB==null)) {
View luView = DB.getView(ViewName);
if (!(luView == null)) {
JsonJavaFactory factory = JsonJavaFactory.instanceEx;
ViewEntryCollection vec = luView.getAllEntries();
ViewEntry entry = vec.getFirstEntry();
while (entry != null) {
Vector<?> columnValues = entry.getColumnValues();
String colJson = String.valueOf(columnValues.get(ColIdx));
JsonJavaObject json = null;
try {
json = (JsonJavaObject) JsonParser.fromJson(factory, colJson);
if (json != null) {
JSONObjects.add(json);
}
} catch (JsonException e) {
System.out.println(“ERROR: PP.loadJsonObjects 1: colJson “);
}
ViewEntry tempEntry = entry;
entry = vec.getNextEntry();
tempEntry.recycle();
}
luView.recycle();
}
DB.recycle();
}
return JSONObjects;
}
}
Managed Bean
We register the class as a managed bean so we can call it easily from our XPage:
<managed-bean>
<managed-bean-name>PictureProvider</managed-bean-name>
<managed-bean-class>com.quintessens.SimplePictures</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
XPage
And then last but not least our XPage. Here we will display the list. The XPage contains:
- A (Bootstrap) table.
- A Repeat control
- A Pager control.
By calculation the values for the Repeat control on page load and using a partial refresh for the pager pagination becomes really fast.
The result will be something as followed:

<?xml version=”1.0″ encoding=”UTF-8″?>
<xp:view xmlns:xp=”http://www.ibm.com/xsp/core”>
<link href=”https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css” rel=”stylesheet” integrity=”sha256-MfvZlkHCEqatNoGiOXveE8FIwMzZg4W85qfrfIFBfYc= sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==” crossorigin=”anonymous” />
https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js
<xp:pager layout=”Previous Group Next” partialRefresh=”true”
id=”pager1″ for=”repeat1″>
</xp:pager>
<table class=”table table-hover”>
<thead>
<tr>
<th>Thumb</th>
<th>Subject</th>
<th>Category</th>
<th>Description</th>
<th>Author</th>
</tr>
</thead>
<xp:repeat id=”repeat1″ rows=”15″
value=”${javascript:PictureProvider.loadPictures();}” var=”pix”>
<tr>
<td>
<xp:text escape=”false”>
<xp:this.value><![CDATA[#{javascript:/*
getAttachmentURL and getBaseURL from:
http://www.wissel.net/blog/d6plinks/SHWL-86QKNM
*/
function getAttachmentURL(docID:java.lang.String, attachmentName:java.lang.String) {
var base = getBaseURL();
var middle = “/xsp/.ibmmodres/domino/OpenAttachment”;
if (base.substr(0,4) == “/xsp”) {
middle += base.substr(4);
} else {
middle += base;
}
var result = base + middle + “/” + docID + “/$File/” + attachmentName + “?Open”;
return result;
}
function getBaseURL() {
var curURL = context.getUrl();
var curAdr = curURL.getAddress();
var rel = curURL.getSiteRelativeAddress(context);
var step1 = curAdr.substr(0,curAdr.indexOf(rel));
// Now cut off the http
var step2 = step1.substr(step1.indexOf(“//”)+2);
var result = step2.substr(step2.indexOf(“/”));
return result;
}
var thumb = pix.thumb;
var id = pix.docUNID;
return “<img src='” + getAttachmentURL(id, thumb) + “‘>”;
}]]></xp:this.value>
</xp:text>
</td>
<td>
<xp:text escape=”true” value=”#{pix.subject}”>
</xp:text>
</td>
<td>
<xp:text escape=”true” value=”#{pix.category}”>
</xp:text>
</td>
<td>
<xp:text escape=”true” value=”#{pix.descr}”>
</xp:text>
</td>
<td>
<xp:text escape=”true” value=”#{pix.author}”>
</xp:text>
</td>
</tr><!– /.row –>
</xp:repeat>
</table>
</xp:view>
Next step
In a next blog I will explain some other (basic) methods that the application will be using to generate collections of documents (by key or restrictbycategory) and based upon these methods we will reconstruct our current XPages app. Untill then.