XPages sufficient for line of business type of applications?

Hi there, currently I am following another Angular course since it seems to have become the leading development framework at work. So back to learning all the rules within Angular.

At the moment I am modernizing a Domino application with the help of XPages which:

  1. Implements Model-View-Controller architecture, mostly inspired by the guys at Pipelia since IBM never told us to do so.
  2. Is written in Java to support the MVC architecture and to have close integration with XPages runtime.
  3. Is using Expression Language wherever possible to avoid usage of SSJS.
  4. Uses the lifecycle of JSF in XPages at the max.
  5. To cover support for different devices I am using Bootstrap as front-end framework. So I miss some native behavior which I do not tend to cover-up.

So far so good and I think I have come quiet long in my project so I still dare to call it rapid application development.

The code-base has been reduced dramatically and all exotic upcoming JavaScript libraries from the early 2000 I have been able to replace with just XPages. With my latent UX skills and extending the out of the box Bootstrap I might now even call this application ‘sexy’ 🙂

I know I haven’t touched many areas discussed in the XPages community such as:

  • Websockets (I do not see a use-case yet).
  • Writing Java servlets (please pass me a demo NSF).
  • Watson services (cloud is still a sensitive topic).
  • set up micro-services with smartNSF and consume them in my Java code with an mapper library (requires changes in the environment).
  • Integration with IBM Connections.
  • Redefining my data with the help of a Graph DB.

Either I see little usage, it is not possible or there is no-one to guide me (the information is certainly not provided by the vendor).

So now back to Angular. Learning all these rules, technologies and new tools setup I was wondering what new technical options this framework will bring me at work. Reflecting on the type of customer-orders I receive I am wondering:

Is XPages not sufficient for most of your line of business apps?

Perhaps you have a though about this?

Happy development & enjoy your summer 🙂

Display JSON pretty in a textarea control

In an application I am using heavily JSON default as the data-format. To make debugging a bit more easy I am working on a toolbar to be able to check the content of the JSON objects.

Normally I use JSONLint most of the time to prettify (and validate) the JSON so it becomes a bit easier to read and check. But this copy and paste habit becomes more and more obnoxious so there I wanted to have a toolbar (like the debug toolbar) to have a good overview of the JSON objects.

However if you write the JSON object to a computed field or text area field (inputTextarea control in the XPages world) it is just plain, unformatted text. Not pretty for the eye and not much helpful for the brain.

So I tested a simple approach which turns out to run just fine. I display the json object in a textarea input control and then with CSJS I format the content. Here is some sample code:

<xp:inputTextarea id=”input-fieldx” defaultValue=”#{javascript:App.currCollection}”>
<xp:button value=”Make Pretty” id=”button1″>
<xp:eventHandler event=”onclick” submit=”false”>
<![CDATA[var name = x$(‘#{id:input-fieldx}’).attr(“name”);
<xp:scriptBlock id=”scriptBlock1″>
<![CDATA[function prettyPrint(id) {
var obj = dojo.byId(id);
var ugly = obj.value;
var json = dojo.fromJson(ugly);
var pretty = JSON.stringify(json, undefined, 4);
obj.innerHTML = pretty;

Here is what it looks like:


The content how it looks initially.


The content how it looks like after running the code.

Note I had to include the [ ] signs in my code to make the JSON valid due to circumstances in my code, I removed it from the sample code above.

At least now I understand my JSON objects again and I can avoid some copy and paste to JSONLint 🙂

This is probably my last blog of this year so I would like to wish you some wonderful Christmas days. Take care and best wishes for a healthy 2017!



Update on my Cloudant sample XPages application

I made some additions to my XPages sample app that I am using to understand and demonstrate the usage of IBM Cloudant within XPages.

I am not fully there yet where I want to be, but it is a work in progress. During development I noticed a couple of things:

  • Cloudant’s Lite Pricing Plan has its limitations 🙂
  • Migrating Notes documents to Cloudant goes fast enough. A set of 10 thousands of simple, small documents takes just a couple of seconds.
  • Loading the same amount of documents into XPages e.g. a Repeat Control and navigate between sets via a Pager control has some delay time. This could be due the limitations of my local application server.

The code is available on Github.


MapReduce views


Frank van der Linden posted he made an update to his Cloudant connector plugin, so from now it should be possible to manage design documents.

To become more familiar with couchDB’s design documents I can recommend reading ‘Writing and Querying MapReduce Views in CouchDB‘.

Design documents

Design documents you mostly manage in CouchDB / Cloudant are documents that describe views of documents. Great if you can manage them via http and not as in IBM Notes via the Domino Designer client 😉

You could store other documents in your couchDb which are part of the design of your application (e.g. html, css, js files but that is another story).

Design documents are nothing more than JSON documents which are stored under the convention: must start with the _design/ pattern followed by the identifier e.g.: _design/default.


Views in couchdb are based on the MapReduce principle:

A MapReduce program is composed of a Map() procedure that performs filtering and sorting (such as sorting students by first name into queues, one queue for each name) and a Reduce() procedure that performs a summary operation (such as counting the number of students in each queue, yielding name frequencies).

This video explains it by using playing cards.


The filtering and sorting are defined by a JavaScript function. You can state conditions in the function to return the documents you are interested in e.g.:

function(doc) {
if (doc.labels) {
for (var idx in doc.labels) {
if (doc.labels[idx] === “organic”) {
emit(doc._id, doc.name);

//docs have to have the field doc.labels and only the id and name from the ones that have the label organic are returned


Reducing is optional and results in a summary operation. The options in couchDb are:

  • _sum
  • _count
  • _stats

Count is probably the most common function to use. Notice that the returned key value might be null if values appear in multiple documents. The key is no longer unique and therefor null.

“rows”: [{
“key”: null,
“value”: 7

If you apply the group parameter in the requested url the values will be grouped so the response could look like:

“rows”: [{
“key”: “appel”,
“value”: 3
}, {
“key”: “banaan”,
“value”: 2
}, {
“key”: “peer”,
“value”: 2

Sum works only on numeric values (of course) so if your mapping functions looks like:

function(doc) {
if (doc.fruits) {
for (var i in doc.fruits) {
emit(doc.fruits[i], doc.calories);

with the _sum reduce option the response could look like:

“rows”: [{
“key”: “appel”,
“value”: 720
}, {
“key”: “banaan”,
“value”: 1368
}, {
“key”: “peer”,
“value”: 320

The _stats option returns a JSON object containing the sum, count, minimum, maximum, and sum over all square roots of mapped values. So for the mapping function above the response could be:

“rows”: [{
“key”: “appel”,
“value”: {
“sum”: 720,
“count”: 2,
“min”: 272,
“max”: 448,
“sumsqr”: 274688
}, {
“key”: “banaan”,
“value”: {
“sum”: 1368,
“count”: 3,
“min”: 272,
“max”: 648,
“sumsqr”: 694592
}, {
“key”: “peer”,
“value”: {
“sum”: 720,
“count”: 2,
“min”: 272,
“max”: 448,
“sumsqr”: 274688

With this knowledge fresh in mind you can use them in your view(s) setup. Remember the design documents can be managed via CRUD operations, e.g. on address http://localhost:5984/veganstore/_design/default

“_id”: “_design/default”,
“language”: “javascript”,
“views”: {
“store”: {
“map”: “function(doc) { if (doc.label) { emit(doc.label, doc.origin); }}”,
“reduce”: “_stats”

In one design document you can define multiple views…

You can query your views by a set of parameters:

  • conflicts (boolean) – Includes conflicts information in response. Ignored if include_docs isn’t true. Default is false
  • descending (boolean) – Return the documents in descending by key order. Default is false
  • endkey (json) – Stop returning records when the specified key is reached. Optional
  • end_key (json) – Alias for endkey param
  • endkey_docid (string) – Stop returning records when the specified document ID is reached. Requires endkey to be specified for this to have any effect. Optional
  • end_key_doc_id (string) – Alias for endkey_docid param
  • group (boolean) – Group the results using the reduce function to a group or single row. Default is false
  • group_level (number) – Specify the group level to be used. Optional
  • include_docs (boolean) – Include the associated document with each row. Default is false.
  • attachments (boolean) – Include the Base64-encoded content of attachments in the documents that are included if include_docs is true. Ignored if include_docs isn’t true. Default is false.
  • att_encoding_info (boolean) – Include encoding information in attachment stubs if include_docs is true and the particular attachment is compressed. Ignored if include_docs isn’t true. Default isfalse.
  • inclusive_end (boolean) – Specifies whether the specified end key should be included in the result. Default is true
  • key (json) – Return only documents that match the specified key. Optional
  • keys (json-array) – Return only documents where the key matches one of the keys specified in the array. Optional
  • limit (number) – Limit the number of the returned documents to the specified number. Optional
  • reduce (boolean) – Use the reduction function. Default is true
  • skip (number) – Skip this number of records before starting to return the results. Default is 0
  • sorted (boolean) – Sort returned rows (see Sorting Returned Rows). Setting this to false offers a performance boost. The total_rows and offset fields are not available when this is set to false. Default is true
  • stale (string) – Allow the results from a stale view to be used. Supported values: ok and update_after. Optional
  • startkey (json) – Return records starting with the specified key. Optional
  • start_key (json) – Alias for startkey param
  • startkey_docid (string) – Return records starting with the specified document ID. Requires startkey to be specified for this to have any effect. Optional
  • start_key_doc_id (string) – Alias for startkey_docid param
  • update_seq (boolean) – Response includes an update_seq value indicating which sequence id of the database the view reflects. Default is false

With this summary on views in couchDBcloudant fresh in mind let’s try to create some views programmatically in Cloudant with Frank’s updated plugin =)

Build JSON from NotesView, support for multiple value fields

The problem

An old-fashioned NotesView can be a fast way to define JSON objects. Here is a xsnippet that give you some inpsiration.

If you have fields with multiple values then the formula does not work anymore. You want to store an array in the JSON.

The fix

The following formula checks if the desired output fields contains more than 1 value  and if so transforms it to an array if not, then you get a normal key:value pair returned.



@For(n :=1; n<=@Elements(_fld); n:= n + 1;

json := json + @Transform ( _fld[n]; “_fn” ; “\”” + _fn + “\”:”) + “[” + @Implode(@Transform( @GetField(_fld[n]) ; “_fn” ; “\”” + _fn + “\”” ) ; “,”) + “],” ;
json := json +
@Transform (
_fld[n]; “_fn” ; “\”” + _fn + “\”:\”” + @Text ( @GetField ( _fn) ) + “\”” + “,”)
“{ \”unid\”:\””
+@Text(@DocumentUniqueID)+”\”,” + @LeftBack(json;1) + + “}”


I added my formula to a column and calling several single and multiple text fields. Here is my output in a browser:


If I validate the json it says it is valid:


I added my code to the XSnippets database.

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 !

Building a search function with DataTables plugin


In Domino you have multiple options how to provide a search function for an application. I have seen many examples where a FT search query is build for a database, where the form type is defined, which fields should be used in the search etcetera. Most of them are a maintenaince nightmare, layout is little flexible and usability is lacking (e.g. perform a search towards a query which will result in zero hits).

What if you make it easier to maintain, more flexible for user specific desires and add facetted search principles? A win situation?


In the following posts I will write how to use the jQuery DataTables plugin to provide a quick search function for your Domino apps. I assume you use XPages.

Stage 1 – Getting & presenting the data

In the initial stage we just try to get and present the data we need. As example I will be using the FakeNames application. I have created a public repo which has at the moment:

  • an xpage to present the data (dtPersons.xsp)
  • an xpage (api.xsp) which will contain rest services
  • a Java class that generates the data in JSON format
  • a CSJS library to transform the HTML table on dtPersons.xsp to  DataTables object
  • the required resources from DataTables.net
  • a Theme resource to have the resources available
  • a Notes view to use as data source.

In order to create some fake documents I have set up an LS agent to do so.

If you bind this all together, you have already a search function:


Right on top you have a search field where you can query the columns in the table. The columns are sortable too. Probably it is matching most of the search functions you have seen for Domino. But wait! There is more possible…


Working with JSON in your XPages application – Refined view

In a previous post I wrote how you could use a Notes view as the data source for JSONObjects. In a recent project I needed to minimize the data amount to transfer so I had to exclude the fields that contain no value. Here is the @formula I can up with for the column value:

REM { Patrick Kwinten

Quick way to deliver ‘cached’ JSON objects from Notes documents


REM {JSONObject bricks};

jsonOpener := “{“;

jsonSeparator := “,”;

jsonClosure := “}”;

REM {String helper};

src := “\\”:”‘”:@NewLine:”\””;

dst :=  “\\\\”:”\\'”:”\\n”:”\\\””;

REM {Define which fields to exclude/include in JSON object};

REM {“Idea taken from http://www.eknori.de/2012-06-01/use-transform-to-build-json-and-consume-the-output-in-an-xagent/&#8221;};



REM {Output for “custom” fields. Empty values are excluded};

_fldOutput := “”;


n := 1;

n <= @Elements(_fld);

n := n + 1;


_fldVal := @Text ( @GetField ( _fld[n] ) );

@If(_fldVal != “” ; _fldOutput := _fldOutput + “\”” + _fld[n] + “\”:\”” + @ReplaceSubstring( _fldVal; Src; Dst )  + “\”” + @If(n != @Elements(_fld); jsonSeparator;””); “”)



REM {Prepare output};

outputStr := “”;

outputStr := outputStr + jsonOpener;

REM {Output for “default” fields};

tmpUNID:= @Text(@DocumentUniqueID);

outputStr := outputStr + “\”docUNID\”:\”” + tmpUNID  + “\”” + jsonSeparator;

outputStr := outputStr + _fldOutput;

REM {Finalize JSONObject};

outputStr := outputStr + jsonClosure;

REM {Return output};


As a result I have “lesser” JSON Objects in my view:

Screen Shot 2016-03-01 at 10.20.40

Bildr 5 released on OpenNTF


Today I released a new version of Bildr on OpenNTF ! There have been spent quiet a few long evenings coding but it was fun (I may drink at home) and interesting!

So just before the holiday season and January’s  IBM Connect buzz I thought it would be a proper moment for a release. So consider it my Xmas present to the community 🙂


I label this version 5.0 since I (almost) completely rewrote the application from scratch. Lot of the logic I have placed in Java classes and the data format is mainly JSON.

I also separated the design from the data so in principle you should be able to place the app in the IBM Bluemix environment.

Because of these decisions there is no backward compatibility so a simple replace design will not work for your existing installation.

Below you can find some screenshots of the new interface. I hope you like it.




Thank you

I would like to thank all the teachers in our community who post their presentations, code samples and answers on the platforms out there.

I have tried to post the code on Github but this failed with the Github desktop client. If some can get me started with that I will distribute the project there too.

For now:

A Merry Christmas and fortune in 2016 !

Carousel with dynamic content


For an application I needed a carousel to display images on the frontpage. Since we go “all-in” Bootstrap the “natural choice” would be the Carousel component from the Extension Library. Unfortunately that control currently only accepts “static” slideNodes so I had to come up with something similar.

In the beginning…

First I just took the sample code from W3schools how to setup a basic Bootstrap Carousel component.


Second I set up a Notes view that contains the data I need for my carousel. This view will be the source for an XPages Rest Service control (PDF alert) which I call after page load with an Ajax call using jQuery’s getJSON.



As you can see I update the Bootstrap sample code with the received result(s).

As a result I get the Carousel component from Bootstrap but now with ‘dynamic content’.


(for those who have never seen a Carousel)

The only complication I experienced was due to the fact that I separate the design from the data and accessing the data is easier in SSJS/Java then CSJS.

Here is the code: Link Dropbox

Happy development =)

Working with JSON in your XPages application (3) – getEntriesByKey


In our third example we will extend the loadPictures method in the first blog entry in this serie to detect whether or not we want to load just all the entries in a view or entries that match a key in the first sorted column.

Use case

In the following simple scenario a user makes an selection (e.g. from a combobox) and corresponding picture documents will be displayed, as in the image:


Whenever a different value is selected the list with corresponding documents will be updated.

So how do we do this?

Switch between Notes views

The main difference is the key send if we do or don’t (empty value) want a filtering of the result list. To collect this key we provide a combobox:


The loadCategories method provides an ArrayList of String values:

public ArrayList<String> loadCategories(String ViewName) throws NotesException{
System.out.println(appRef + “.loadCategories()”);

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

String ServerName = “dev1”;
String DatabaseName = session.getCurrentDatabase().getFilePath();
Database DB = session.getDatabase(ServerName, DatabaseName);

View luView = DB.getView(ViewName);
ViewNavigator vwnav = null;
ViewEntry vwentry = null;
ViewEntry vwentrytmp = null;

// all results will be added to this
ArrayList<String> categories = new ArrayList<String>();

// disable autoupdate

vwnav = luView.createViewNav();

// setting buffer for fast view retrieval

// perform lookup
vwentry = vwnav.getFirst();
while (vwentry != null){

// Get entry and go recycle
vwentrytmp = vwnav.getNext(vwentry);
vwentry = vwentrytmp;

return categories;

The xp:Combobox control is bound to a viewScope variable and it’s onChange event triggers a partial refresh on a panel:

<xp:panel id=”pictures”>
<xp:pager layout=”Previous Group Next” partialRefresh=”true” id=”pager1″ for=”repeat1″></xp:pager>
<table class=”table table-hover”>
<xp:repeat id=”repeat1″ rows=”15″ var=”pix”>

<xp:this.value><![CDATA[#{javascript:var active = viewScope.get(“activeCategory”);
if (active == “All”){
<xp:text escape=”false”>
getAttachmentURL and getBaseURL from:

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.imgthumb;
var id = pix.docUNID;

return “<img src='” + getAttachmentURL(id, thumb) + “‘>”;
<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>
</tr><!– /.row –>


Depending on the value in the viewScope we call the loadPictures method empty or with a key.

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.getAllEntriesByKey(Key, true);

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) {

} catch (JsonException e) {
// TODO:

ViewEntry tempEntry = entry;
entry = vec.getNextEntry();
return JSONObjects;

Similar as in the previous examples the JsonJavaObject class from the com.ibm.commons.util.io.json package is used to return an arraylist of json objects.

In the next post I will describe how we can manipulate the JSON objects.