Send a message from your XPage application to a Slack channel


While everyone is ‘waiting in vain’ for the delivery of Project Toscana organizations have start using Slack as a modern way to send messages within departments.

For an example a operation team is using an instructions quality book build on XPages and it would be great to get notified in your Slack channel when new instructions come in or have been updated. Or you want to highlight a specific instruction just to create extra attention to it (e.g. an increasing number of incoming incidents).


Be creative with use-cases🙂

Slack integration points

Incoming Webhooks are a simple way to post messages from external sources into Slack. They make use of normal HTTP requests with a JSON payload, which includes the message and a few other optional details described later.

JSON, HTTP request… this sounds doable with XPages! So what are the steps you must take?

Setup your integration

Go to and click on Incoming Webhooks, then select a channel or user you want to post your messages to.

Setup your message

You have two options for sending data to the Webhook URL above:

  • Send a JSON string as the payload parameter in a POST request
  • Send a JSON string as the body of a POST request

Simple message

For a simple message, your JSON payload could contain a text property at minimum. This is the text that will be posted to the channel e.g.:

payload={"text": "This is a line of text in a channel.\nAnd this is another line of text."}

You can decorate your message with text formatting. You will find descriptions in the custom integration page on Slack.

Message attachments

To display a richly-formatted message attachment in Slack, you can use the same JSON payload as above, but add in an attachments array. Each element of this array is a hash containing the following parameters:

	"fallback": "Required text summary of the attachment that is shown by clients that understand attachments but choose not to show them.",

	"text": "Optional text that should appear within the attachment",
	"pretext": "Optional text that should appear above the formatted data",

	"color": "#36a64f", // Can either be one of 'good', 'warning', 'danger', or any hex color code

	// Fields are displayed in a table on the message
	"fields": [
			"title": "Required Field Title", // The title may not contain markup and will be escaped for you
			"value": "Text value of the field. May contain standard message markup and must be escaped as normal. May be multi-line.",
			"short": false // Optional flag indicating whether the `value` is short enough to be displayed side-by-side with other values

Send the message

With a simple post request you send the message in JavaScript:

function postMessageToSlack(url){
webhook_url = url;
payload= JSONStr;
var xmlhttp = new XMLHttpRequest();'POST', webhook_url, false);
xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');


This whole approach I have added as an XSnippet on OpenNTF:

You can customize it to your needs. Basically I have a script block and a button on a custom control. Via the Property Definition tab you can set the desired values. In my example I am sending a message to a Slack channel about a picture / document in my Bildr application (shameless plug).

Here is how the message could look like:


Since my XPages app is running on a local development machine it is of no use to send sampel thumbnails of the page, but I could. This also refers to the user icon, which could be the icon of the application.

So grab the snippet and start integrating your XPages with Slack (untill Toscana arrives) !

FYI: I am not aware of any restrictions on the number of message you may send to Slack. Please let me know if you have details on this.

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: and get in contact.

I am happy to work WITH you !


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.


Threads and Jobs on release 9

On OpenNTF you can find a project called Thread and Jobs:

This project contains samples showing how to create threads and Eclipse jobs from XPages to run longer taking operations asynchronously without blocking the XPages user interface or to run scheduled tasks.

It turns out that there have been updates in Release 9 in the ThreadSessionExecutor class and no longer a Status object is returned.

So if you want to have the example application working on your Domino 9 server you should remove the Status/iStatus library import and change the return type from Status to Object as followed:

* © Copyright IBM Corp. 2012
* Licensed under the Apache License, Version 2.0 (the “License”);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an “AS IS” BASIS,
* implied. See the License for the specific language governing
* permissions and limitations under the License.
package org.openntf.samples.thread;

import java.util.Date;
import lotus.domino.Database;
import lotus.domino.Document;
import lotus.domino.NotesException;
import lotus.domino.Session;

* Thread sample
* @author priand
* @author Niklas Heidloff (simplified sample)
* Updated 2016-10-18 Patrick Kwinten

public class ThreadSample {

private static MyThread myThread;

public static boolean isRunning() {
return myThread != null;

public static void startThread() throws NotesException {
if (myThread != null) {
try {
synchronized(ThreadSample.class) {
if (myThread == null) {
myThread = new MyThread();
System.out.println(“Thread started”);
} catch (Throwable t) {

public static void stopThread() {
if (myThread != null) {
synchronized(ThreadSample.class) {
if (myThread != null) {
myThread.stopRequest = true;
myThread = null;
System.out.println(” >> Thread stopping”);

private static class MyThread extends Thread {
boolean stopRequest;
private ThreadSessionExecutor < Object > executor;
MyThread() throws NotesException {
this.executor = new ThreadSessionExecutor < Object > () {
protected Object run(Session session) throws NotesException {
try {
System.out.println(” >> Thread running”);
Database db = session.getDatabase(null, “ThreadsJobs.nsf”);
if (db != null) {
if (!db.isOpen());
if (db.isOpen()) {
System.out.println(” >> Database opened: ” + db.getTitle());
Document doc = db.createDocument();
try {
doc.replaceItemValue(“Form”, “ThreadTest”);
doc.replaceItemValue(“DateTime”, session.createDateTime(new Date()));;
} finally {
} catch (Throwable ex) {
if (!stopRequest) {
try {
Thread.sleep(5 * 1000);
} catch (InterruptedException ex) {
//return Status.OK_STATUS;
return “probably OK”;

public void run() {
while (!stopRequest) {
try {;
} catch (Exception ex) {}
System.out.println(“Thread left”);

I have not yet managed how to fix the JobScheduler class…

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

//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 =)

Using IBM Cloudant with XPages

Last evening I started a little couch development project, in front of the TV. The data I am used to work with is mostly in JSON format already so I read a bit on couchDB. Since my use-case allows storage in the cloud I was curious about Frank van der Linden’s cloudant-connector plugin so I gave it a swing.

Cloudant is the cloud version of CouchDb. Which is invented by Damien Katz, who also was involved by the creation of the NSF.

I found on the internet a very nice easy to use open source project, Java-cloudant, who is doing the heavy lifting in the interaction with Cloudant.

I guess for an XPages developer this is the easiest way to get started with Cloudant. You can also load the libraries yourself as Stephan Wissel describes. At this point I am not sure what option I like best.

It turns out with Frank’s plugin you can develop really fast rapid. If you look at the HR-assistant application he has worked on you find some great examples how to use it. Nevertheless that project was too sophisticated for me to adapt in my 2hr sample app. My goal was to learn more about couchDb and IBM Cloudant and working with documents & views in general and not (yet) building applications around it.

So this is the result I achieved in my restricted time:


Nothing much sophisticated, but a good learning experience which I would like to take with me in my next “couch” project🙂 The code is available in a Github repo.

In a month Frank is holding a presentation at SUTOL concerning using developing with Cloudant so I am looking forward to hear what he has to say and show there🙂

Recently(?) IBM Cloudant on Bluemix has a “Lite” pricing plan which is free with restrictions so it’s developers friendly:



Feeds highlights (video)

I noticed that I had a enormous backlog in my feedreader (feedly) starting from around September (pre IconUK). Allthough the amount of blogposts in the Yellow Bubble is declining (fast) I just did not have the time to keep up with it untill now.

I thought it would be a great idea to consume the feeds in a different matter so the idea came up to take a weekly ‘snapshot’ and mention some of this weeks most interesting posts. The result is a short video which is easy to consume. Probably a demo or two of the highlights would have made things much more clear, but hey I am not Niklas Heidloff nor do I reside in some form of organ of an open source community.

I apologize for the bad quality since I used the internal microphone of my PC and there are constructions taking place in the street I live. At least I am rid off the many unread blog/news items🙂

I made it to NotesIn9

I remember a phrase in a song from an old punk band:

If you want to have a scene

then you have to create a scene

So after some dark words from David Leedy I created a video about using some tooling to tackle the problem with using Font-Awesome in XPages. These tools (Node, Bower, Grunt) you could also use in other situations. Another use-case could be the AMD loading conflict with Dojo.

So I would like to thank David Leedy for granting me the opportunity to talk technical outside the Yellow Bubble. I also thank Oliver Busse, who did a great job in his first time appearance as host.

My video you can watch via this link.

Setting up a boilerplate for Angular 2


I guess we all say amen to the following quote:

“The Only Thing That Is Constant Is Change” – Heraclitus

Working with XPages / IBM Notes you get scare-mongered a couple times a year thatthe whole thing is dead. With the Java vs JavaScript deathmatch not decided yet as ICS developer you might wonder on what train to jump next.

In the past I have been looking at Angular but never took it to the next level. With Angular 2 recently official released the cards might be different this time. Just look at the job vacancy sites and Angular specialists are searched after everywhere.

So I took a course Angular 2 and now I am migrating an XPages app to Angular 2 to see if the love is both directions.

Angular 2 boilerplate

A big difference with the previous version of Angular is the preparation. Angular 2 requires some sort of boilerplate, which I will describe how to build in this post.


I will be using Domino as the HTTP server, since my data still resides in NSF. So for now my Angular app will live in the WebContent folder, so that is the working directory of my application. For ease of working I have setup a Github project. Added an ODP folder and synched my NSF with that.

In the WebContent folder in my ODP I will create the following documents:

  • tsconfig.json
  • typings.json
  • package.json
  • app/app.component.ts
  • app/main.ts
  • index.html

If you want you can just download a quickstart somewhere.


Create this file in the root of your project. In my course Typescript is used, but you could also script in Angular with JavaScript of course.

tsconfig defines the compiler configuration, here we say that our target code is JavaScript.

“compilerOptions”: {
“target” : “es5”,
“module” : “system”,
“moduleResolution” : “node”,
“sourceMap” : true,
“emitDecoratorMetadata” : true,
“experimentalDecorators”: true,
“removeComments” : false,
“noImplicitAny” : false
“exclude” : [


Also place this file in the root of your project. In this file you define the Typescript declarations. It turns out that the Typescript compiler does not recognize several libraries…

“ambientDependencies”: {
“es6-shim”: “github:DefinitelyTyped/DefinitelyTyped/es6-shim/es6-shim.d.ts#7de6c3dd94feaeb21f20054b9f30d5dabc5efabd”,
“jasmine” : “github:DefinitelyTyped/DefinitelyTyped/jasmine/jasmine.d.ts#7de6c3dd94feaeb21f20054b9f30d5dabc5efabd”


This file will also be stored in the root of the project. In this file all dependencies and it’s versions are registered, which we will install with NPM.



An Angular 2 app needs at minimum 1 component, the root component. Components are the basic building blocks of Angular applications. A component controls a portion of the screen—a view—through its associated template.

import {Component} from ‘angular2/core’;

selector: ‘hello-world’,
template: ‘<h1>Hello World</h1>’
export class AppComponent {
// … here we will add our logic later

So first you define a component, and then you make it available for export so you can import it into the application.


This file is the bootstrapper in our app. Since our boilerplate is simple it does not contain so much yet:

import {bootstrap} from ‘angular2/platform/browser’
import {AppComponent} from ‘./app.component’


Note: At this moment we do not have declared to use any module so we do not have to create an app/app.module.ts file.


The index file contains out of 2 sections, the first is the header, the other one the body. The header can be divided into 3 steps:

  • add styling
  • load the libraries
  • configure our main.js


The second part is the body content of the HTML file:



We’re done!

With this in place we have our boilerplate in place. Run “NPM install” and thereafter “NPM start” or open the index.html file on your domino server (after you have synced the files back to the NSF (this might take a while).

Also notice how the Typescript files are compiled to JavaScript files:


And finally “surprise-surprise” the result:



Starting developing with Angular 2 is a bit different in comparison with version. Backward compatibility has always been strong for IBM Notes/Domino.

TypeScript is another opportunity for developers. I intend to blog more about my Angular journey and we’ll see how long the love will last🙂

Here are some links of interest:

Typescript – Quick start

Angular – Quickstart