Domino Upgrade

VersionSupport end
Upgrade to 9.x now!
(see the full Lotus lifcyle) To make your upgrade a success use the Upgrade Cheat Sheet.
Contemplating to replace Notes? You have to read this! (also available on Slideshare)


Other languages on request.


Useful Tools

Get Firefox
Use OpenDNS
The support for Windows XP has come to an end . Time to consider an alternative to move on.

About Me

I am the "IBM Collaboration & Productivity Advisor" for IBM Asia Pacific. I'm based in Singapore.
Reach out to me via:
Follow notessensei on Twitter
Amazon Store
Amazon Kindle
NotesSensei's Spreadshirt shop


XPages XML Document DataSource - Take 2

For a recent project I revisited the idea of storing XML documents as MIME entries in Notes - while preserving some of the fields for use in views and the Notes client. Jesse suggested I should have a look at annotations. Turns out, it is easier that it sound. To create an annotation that works at runtime, I need a one liner only:
@Retention(RetentionPolicy.RUNTIME) public @interface ItemPathMappings { String[] value(); }
To further improve usefulness, I created a "BaseConfiguration" my classes will inherit from, that contains the common properties I want all my classes (and documents) to have. You might want to adjust it to your needs:
ackage com.notessensei.domino;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
 * Common methods implemented by all classes to be Dominoserialized
@XmlRootElement(name = "BaseConfiguration")
public abstract class BaseConfiguration implements Serializable, Comparable<BaseConfiguration> {
    private static final long serialVersionUID = 1L;
    @XmlAttribute(name = "name")
    protected String          name;

    public int compareTo(BaseConfiguration bc) {
        return this.toString().compareTo(bc.toString());
    public String getName() {
    public BaseConfiguration setName(String name) { = name;
        return this;
    public String toString() {
        return Serializer.toJSONString(this);
    public String toXml() {
        return Serializer.toXMLString(this);

The next building block is my Serializer support with a couple of static methods, that make dealing with XML and JSON easier.
package com.notessensei.domino;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

 * Helper class to serialize / deserialize from/to JSON and XML
public class Serializer {

    public static String toJSONString(Object o) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            Serializer.saveJSON(o, out);
        } catch (IOException e) {
            return e.getMessage();
        return out.toString();

    public static String toXMLString(Object o) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            Serializer.saveXML(o, out);
        } catch (Exception e) {
            return e.getMessage();
        return out.toString();

    public static void saveJSON(Object o, OutputStream out) throws IOException {
        GsonBuilder gb = new GsonBuilder();
        Gson gson = gb.create();
        PrintWriter writer = new PrintWriter(out);
        gson.toJson(o, writer);

    public static void saveXML(Object o, OutputStream out) throws Exception {
        JAXBContext context = JAXBContext.newInstance(o.getClass());
        Marshaller m = context.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        m.marshal(o, out);

    public static org.w3c.dom.Document getDocument(Object source) throws ParserConfigurationException, JAXBException {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        org.w3c.dom.Document doc = db.newDocument();
        JAXBContext context = JAXBContext.newInstance(source.getClass());
        Marshaller m = context.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        m.marshal(source, doc);
        return doc;

    public static Object fromByte(byte[] source, Class targetClass) throws JAXBException {
        ByteArrayInputStream in = new ByteArrayInputStream(source);
        JAXBContext context = JAXBContext.newInstance(targetClass);
        Unmarshaller um = context.createUnmarshaller();
        return targetClass.cast(um.unmarshal(in));

The key piece is for the XML serialization/deserialization to work is the abstract class AbstractXmlDocument. That class contains the load and save methods that interact with Domino's MIME capabilities as well as executing the XPath expressions to store the Notes fields. The implementations of this abstract class will have annotations that combine the Notes field name, the type and the XPath expression. An implementation would look like this:
package com.notessensei.domino.xmldocument;
import javax.xml.bind.JAXBException;
import lotus.domino.Database;
import lotus.domino.Document;
import lotus.domino.NotesException;
import lotus.domino.Session;
import com.notessensei.domino.ApplicationConfiguration;
import com.notessensei.domino.Serializer;
import com.notessensei.domino.xmldocument.AbstractXmlDocument.ItemPathMappings;

// The ItemPathMappings are application specific!
@ItemPathMappings({ "Subject|Text|/Application/@name",
					"NumberOfActions|Number|count(//action)" })
public class ApplicationXmlDocument extends AbstractXmlDocument {

    public ApplicationXmlDocument(String formName) {

    public ApplicationConfiguration load(Session session, Document d) {

        ApplicationConfiguration result = null;
        try {
            result = (ApplicationConfiguration) Serializer.fromByte(this.loadFromMime(session, d), ApplicationConfiguration.class);
        } catch (JAXBException e) {
        try {
        } catch (NotesException e) {
            // No Action Taken
        return result;

    public ApplicationConfiguration load(Session session, Database db, String unid) {
        Document doc;
        try {
            doc = db.getDocumentByUNID(unid);
            if (doc != null) {
                ApplicationConfiguration result = this.load(session, doc);
                return result;

        } catch (NotesException e) {

        return null;

Read More


Develop local, deploy (cloud) global - Java and CouchDB

Leaving the cosy world of Domino Designer behind, venturing into IBM Bluemix, Java and Cloudant, I'm challenged with a new set of task to master. Spoiled by Notes where Ctrl+O gives you instant access to any application, regardless of being stored locally or on a server I struggled a little with my usual practise of

develop local, deploy (Bluemix) global

The task at hand is to develop a Java Liberty based application, that uses CouchDB/Cloudant as its NoSQL data store. I want to be able to develop/test the application while being completely offline and deploy it to Bluemix. I don't want any code to have conditions offline/online, but rather use configuration of the runtimes for it.
Luckily I have access to really smart developers (thx Sai), so I succeeded.
This is what I found out, I needed to do. The list serves as reference for myself and others living in a latency/bandwidth challenged environment.
  1. Read: There are a number of articles around, that contain bits and pieces of the information required. In no specific order:
  2. Install: This is a big jump forward. No more looking for older versions, but rather bleeding edge. Tools of the trade:
    • GIT. When you are on Windows or Mac, try the nice GUI of SourceTree, and don't forget to learn git-flow (best explained here)
    • A current version of the Eclipse IDE (Luna at the time of writing, the Java edition suffices)
    • The liberty profile beta. The Beta is necessary, since it contains some of the features, notably couchdb, which are available in Bluemix by default. Use the option to drag the link onto your running Eclipse client
    • Maven - the Java way to resolve dependencies (guess where bower and npm got their ideas from)
    • CURL (that's my little command line ninja stuff, you can get away without it)
    • Apache CouchDB
  3. Configure: Java loves indirection. So there are a few moving parts as well (details below)
    • The Cloudant service in Bluemix
    • The JNDI name in the web.xml. Bluemix will discover the Cloudant service and create the matching entries in the server.xml automagically
    • A local profile for a server running the Liberty 9.0 profile
    • The configuration for the local CouchDB in the local server.xml
    • Replication between your local CouchDB instance and the Cloudant server database (if you want to keep the data in sync)
The flow of the data access looks like this
Develop local, deploy global
Read More


Double-O Bike Light Review

I backed the Double-O bike light Kickstarter project and use them for a while now. This is my verdict:
TL:TR Highly functional light with clever features, some teething problems
If you like to ride through the unlit woods at night, Double-O isn't for you, but that would.
It is a commuter light with a rather clever design.
DoubleO front and back open

The Good

  • It is huge. With the LED arranged in a circle you get a big patch of light, a much bigger surface than the bike lights you commonly find in the market. That alone improves visibility quite a bit.
  • Two of the 3 light modes are what you would expect: blinking and steady. The third one I haven't seen elsewhere: the odd and even numbered LED blink alternate. This is quite clever. Someone looking at it (that's: the other traffic participants) sees something moving, creating similar attention as blinking, but for the rider it is a steady light since the same number of LED is on at any given time. That's especially useful for the front light lighting the path (to some extend) in front of you.
  • The case is sturdy and the threaded cover that you use to screw it open and close (to change batteries) reliably keeps moisture out (trust me, my environment has plenty of that
  • The rubber band mechanism and the rubberised back making fixing the light at a handlebar or a seat stem very fast and reliable. My package even included a set of spare rubbers
  • Locking the lights with your bike lock works as advertised (but someone could steal the batteries if they get what it hanging there)
  • The low power LED lights make the batteries last quite long

The Bad

The original specifications proposed to use USB chargable fixed batteries and a magnetic fix for the light. The rechargable option was abandoned in favour of longer lasting standard batteries (and rechargeable battery in the Kickstarter delivery). While I generally understand the design decision for a general market offering, I would have found USB charging suiting my personal style (I'm used to have a zoo to be charged after my rides: The Garmin, the Bluetooth entertainment, the phone and the helmet).
The rubber band to fix the light at the bike works and it more efficient to produce, but the magnet solution has a way bigger cool factor. Also: When there's no pipe (read saddle stem) available or you want to fix it at your pannier rack, the rubber isn't the best fit. Eventually Double-O might release the fixtures design files, so I can print one for my purpose.

The Ugly

The battery holding mechanism (see the picture above) is flimsy. For a hipster ride that might be sufficient, but in a little rugged environment where I ride (kerbstone jumps, potholes, very uneven surface, the occasional trail) the vibrations make the batteries move, in my case even to the extend of bending the electrical contract latches. The batteries loose contact and the light goes off (or won't switch on).
I haven't found a solution, but I'm contemplating using a rubber ring around battery and latch or hold the pieces in place using a little dense sponge rubber.


Now that the client is gone - what to do with all that notes:// links?

In your mind you drank the cool-aid and got onto IBM Verse or went to the dark side. You web enabled all of your applications (smartly) and you are ready to turn off the Notes clients.
But then you realize: there are notes:// URLs (or their file equivalents ndl files) and doclinks spread all over your organisation: in eMails, in office documents, in applications in personal information vaults.
So you wake up and go back to the drawing board.

What is the issue at hand?

Lotus Notes was one of the first applications (as I recall, the first commercial) that made large scale use of Hyperlinks (Yep, hyperlink doesn't mean it starts with http).
Creating, storing and exchanging links to information was one of the key success components of groupware and later the world wide web (which Notes predates). A hyperlink is unidirectional, so the link target has no knowledge where hyperlinks are located pointing to it. So inspecting a target gives no indication of a potential source.
When you move a target, e.g. change or decomission the server, then you create Link Rot, the digital equivalent of Alzheimer's disease.
Removing the Notes client adds a second problem. Each Hyperlink not only has a target, but also a protocol. That is the part in front of the colon.
Most of the time you think you deal only with http or https, but there are many more: mailto (for eMail), ftp (for file transfer), cifs (for file servers), ssh (for secure shell connections), call (for VoiP), chat (for chat), sap (to call the SAP client).
Each protocol has a handler application. When you don't have a handler application for a specific protocol installed, your operating system will throw and error when you try to use it.
Like a Demo? Try it for youself!
So to replace a protocol handler application (in our case the Notes client)


You need to do 2 things:
  1. In your web enablement / data migration project capture all source and target mappings. For some stuff simple formulas (regex) might do, but in most cases a key value store is required. Playing with different web technologies on and, but rendering the same content, I tested the hypothesis and found key value stores suitable.
    In a nutshell: links need to live forever, come sing along
  2. Create a replacement for the notes:// URL handler (and the ndl file type), so any link starting with notes:// will then be looked up in your key value store and rendered by the appropriate application.
    The little special challenge here: when you web enable applications over a period of time, you still might have a Notes client, but that specific URL is gone. When you keep your NSF and just add the webUI, this won't be an issue. But it is a problem you will face when switching the platform


Alternatively you can claim ignorance is bliss and succumb to digital dementia. The usual aguments not to act:
  • the information is old, nobody needs it
  • we have great search in the new application, so users will find it
  • it is a waste of money and time
  • We have it archived, so what's the problem
  • We keep one machine with a client around, so users can look it up
If that's the prevalent line of thought in the organisation, wecome to binary lobodomy, if not, read on.
Read More


View driven accordeon

The Extension Library features a Dojo Accordion control. In the sample application the panels and their content are created static using xe:basicContainerNode and xe:basicLeafNode. A customer asked: "Can I populate the accordion using view entries?"
Working my way backwards I first designed the format for the SSJS I need for the menu and then how to generate this format from an categorized view. The format that suited this need looks like this:
   { name : "Level 1"; items : ["red 1":"blue 1":"green 1"]},
   { name : "Level 2"; items : ["red 2":"blue 2"]},
   { name : "Level 3"; items : ["red 3":"green 3"]}

In a live application, the items rather would be objects with a label and an action (items : [{"label": "red 2", "action" : "paintred"}:{"label" : "blue 2", "action" : "playBlues" }]) or URL, but for the demo a string is sufficient. I created a accordeon with a xe:repeatTreeNode containing a xe:basicContainerNode as sole child element (which would repeat).
This child then contains one xe:repeatTreeNode that would again contain one xe:basicContainerNode as sole child (which again would repeat).
In theory that all looks brilliant, except the inner repeatTreeNode would not get access to the repeat variable from the parent basicContainerNode.
This has been accnowledged as a bug and is tracked as SPR # MKEE9SKENK
(I'm, inside IBM, outside the development team, the undisputed XPages SPR champion).
So a little hack was necessary to make that menu work.
Read More


How to stiffle innovation in IT

Innovation drives change, innovation improves productivity. Both are scary, so you might want to embark on a strategy to prevent innovation. Cutting your R&D spending along isn't enough, since determined minds will find a way around it (BYOD anyone). So here is my sure fire receipt how to get rid of innovation. It is not a list of "pick one", but step by step instructions to "kill the beast":
  1. Split your IT department into two. A small group of business facing analysts and consultants, lets call them "owner" and the larger group of the rest, lets call them "service"
  2. Enshrine the communication between the two into written rules, also known as Service Level Agreements (SLA)
  3. Describe your current environment in detail, make sure the description is void of terms like "regular update", "benchmark to industry standards" and other forward pointing phrases
  4. Keep the owner group small and appoint their leader from the outside. This prevents career paths from forming. Decree that there is no switching from service to owner. Available career paths only attract talent
  5. Make the owner own all the systems, product decisions and architectural directions
  6. Make the service responsible for the flawless operation of you your IT
  7. Freeze the architecture and never ever let experts review it for optimisation potential. If that happens, often driven by senior management unaware of the "no-innovation" program, use risk assessments to prevent implementation of finding or simply sit it out
  8. Important: compensate the service per user in your organisation, but not for the number of systems they run. It is crucial to decouple funding computation from system needs, this allows for a better kill. With a fixed budget, you will see replacement investments (e.g. contemporary servers, firewalls, appliances) shrink to a minimum, leading to the need to constantly focus on "keeping the lights on" since aging systems lead to service degradation
  9. Leave all decisions about software, processes, maintenance, uptimes etc. to the owner, but make the service fully responsible to execute. This allows to shut down any suggestion for improvement originating from service by simply not approving it
  10. Slap huge penalties onto the service for not meeting any of the enshrined SLA. Since innovation always carries a risk of failure or temporary service degradation during adoption, this effectively shuts down the mere idea of suggesting an innovation
  11. In a rapid changing environment make sure, you are on back versions, this prevents taking advantage of new capabilities - a nasty source of innovation
  12. Make risk the golden calf you dance around. Enjoy the puzzled faces from external consultant when you demand a risk assessment for fixing a flaw in your settings. Deny that there is something like "Risk of ignoring"
  13. The finest: after you ensured that the service has no influence how to conduct their work, implement an automatic budget cut annually, since they "got better at it and have probably optimised their operation by now"
  14. Constantly compare the service, with all the constraints and customisation enshrined, with consumer grade offerings and how great they are. This generates the perception of inferiority, so nobody dares to use the dreaded "I..." word
So in short: make sure not to attract talent, keep the systems outdated and penalise any deviation from an ambitious SLA.
Any similarities with common legal contracts are not purely incidental


Document dependent inline forms

In Notes client applications we are used to opening any document from a view and get it redered with the form specified in the Form (or the view's form formula). XPages behaves in a similar fashion when using the view control. However both approached open a new page (a tab in the Notes client, replaceing the current window in a browser).
Modern applications however expect a Single page application behavior, where only parts of the screen are replaced with new information. The XPages Extension library makes this easy, by providing the InPlace Form custom control.
Looking at the source code of the example page, it looks easy enough. However a real life application needs a few more considerations:
  • I want to open a (different) form depending on the current document
  • That form needs to be stored in its own control, so it can be reused
  • It is OK to enumerate the possible forms in the page (not fully flexible)
  • When saving an edit the form needs to disappear
With the help of the devine Maire Kehoe, this is the solution I came up with:
<xp:eventHandler event="onclick"
    submit="true" refreshMode="partial"
	<xp:this.action><![CDATA[#{javascript:var formId = getSubform(aViewEntry);

The code above is the event handler that goes into the link or button that triggers the edit action. In my case inside a repeat based on a view. The code to find the form is simple.
function getSubform(ve:NotesXspViewEntry) {
	// Put real logic here, like looking at the form
	// var form = ve.getDocument().getItemValueString("Form");
	// return "inPlace"+form;
	var fruit = ve.getColumnValue("Subject");
	var subform = ("Durian"===fruit) ? "inPlaceDurian" : "inPlaceFruit";
	return subform;

Read More


The engineered society

While waiting at my favourite tailor, a fellow Singaporean chalked up a conversation. Unsurprisingly education became a topic. Singapore regularly scores in the top bracket in the PISA test (probably empowered due to lots of homework) and the US is adopting Singapore math.
However my counterpart highlighted a different aspect: "The Singapore school system drills you to build an ever growing portfolio of problem solutions and hone the skill to match any occurring challenge to this portfolio" he continued "Devising new solutions is not part of the package".
I hear the howling, that creativity is a much honoured skill in Singapore. Sit back for a moment and muse my (admitting biased) thoughts on the fabric of Singapore:
In its oldest part Singapore is a trading post. It has deal makers (traders) and kulis (fulfilment, carrying merchandise from and to ships). This old structure shines through until today, where "becoming rich" is the ultimate Singaporean achievement, enshrined in the 5 C. Deal maker is the most revered profession. Contemporary Singapore however is different. It is essentially an

Engineered Society

What does that mean: everything is planned out, desired outcomes are executed diligently, known solutions are applied to apparent issues, quality is controlled, margins for errors are specified and tolerance is a measured quantity.
It seems that approach has worked out very well for Singapore so far (even when some dislike it). Let me backup this claim:
  • Being land and resource scares, the founding fathers designed a system where service excellence made a difference: engineering, a world class port, a swift and impartial legal system for trade disputes, an educated workforce, a secure environment and top financial institutions. All this was planned, it didn't just grow
  • Few genuine inventions originated from Singapore (not surprisingly due to the limited size of available R&D budget), but the, relative to the country, huge budget has been spent to excel in engineering disciplines. Point in case: Singapore stands out in water treatment, land reclamation, airlines and aviation support industry, defence industry and specialty electronics
  • The system of Pension Fund and Public Housing with its racial quotas ensures a standard of living that is worth working for. The prevention of the formation of "cultural living quarters" supports the idea of a harmonious multi-racial society. Good education helps too. And from what I see: it's working
  • The world class tuition industry can only exist when the mode of examination is "pattern matching" - recognise the given question and match it to the pool of known solutions. The tuition centres cater to the perceived need of expanding the pool of known solution (a trade seemingly shared with Korea).
  • Even the maker movement has been integrated into government planning and startups are catered for in Block 71 (more on that later this year)
  • Political engineering: To ensure minority representation, some districts elect a group of members of parliament instead of electing individuals. (You wouldn't suspect other motives, would you?)
Engineering however has its limitations. As my friend Alvin reminded Dr. Balakrishnan: "Progress needs the square pegs in round holes, the misfits, the odd ones, the different thinkers, the experimentors, the tinkerers".
The biggest challenge ahead could be the very fact, that made it so successful in the past: the engineering mind set. As the joke goes: "We love the latest and greatest, bleeding edge. Just provide us three reference cases where this has been successfully implemented for at least 3-5 years".
Engineers identify challenges, apply and optimise known solutions. Engineers don't venture into the unknown (Scientist and artists do). The future however is unknown, the flying car thing didn't really work out. So the challenge ahead (can we engineer a solution for that?) is to reconcile the engineering with the early Singapore spirit: venturing into the unknown.
As Antoine de Saint Exupéry would remind us: "
Your task is not to foresee the future, but to enable it "

Happy future to everybody!


Command line mail merge

As shown before mail merging with Notes and {{mustache}} is simple and easy to code. To be able to run merging on the command line, I modified the bean and removed the XPages dependency and added a static main function. Now you can run it off the command line easily. It requires 5 parameters:
  1. the database name
  2. the CSV file
  3. a file with a HTML message including {{mustache}} tags
  4. a file with a Text message including {{mustache}} tags
  5. The senders eMail

Read More


Mail Merge with XPages

Being able to have individualized letters based on a template was one of the drivers to make Word processors popular. In the age of mass-communication of one. This tasks falls no longer to the printer, but your eMail processor. For a complete solution, check out Chris Toohey's excellent Mailer application, that is yours for USD 5.00 only.
I was wondering what it would take to build something similar, minus the address management, in XPages. I defined a few constraints:
  • I don't want to store the address list or the raw message
  • I need to be able to send images
  • I need to be able to fine tune the HTML
  • No sending of attachments required
  • Message needs to be individual using parameters (in the Body only), list of parameters will be flexible supplied together with the eMails as CSV data
So I created the MergeManager Java bean. Along the way I made a few experiences:
  • When bound to a bean the XPages RichText control wants a data type of
  • The IBM Image upload doesn't work with a bean bound RichText control, but dragging and dropping works. I got rid of the button with a single line of code:
    config.removeButtons = 'IbmImage';
  • When adding the Dropdown for the variables, a simple change allowed me to show the View source button:
    {"name" : "mustache", "items" : ["mustache","Source"] });
  • I reused parts of Toni's eMail bean, which I stripped of the attachment function and added direct deposition into the Works like a charm
  • There are lots of loose ends to consider: using the OpenNTF Domino API to gain easy access to theads to send the messages in the background would be top on the list. Allow template storage, different messages for HTML and Text (and EE), eMail preview some of the others. But that's a story for another time
The result is a reusable bean for custom mass eMails.
Read More


This site is in no way affiliated, endorsed, sanctioned, supported, nor enlightened by Lotus Software nor IBM Corporation. I may be an employee, but the opinions, theories, facts, etc. presented here are my own and are in now way given in any official capacity. In short, these are my words and this is my site, not IBM's - and don't even begin to think otherwise. (Disclaimer shamelessly plugged from Rocky Oliver)
© 2003 - 2015 Stephan H. Wissel - some rights reserved as listed here: Creative Commons License
Unless otherwise labeled by its originating author, the content found on this site is made available under the terms of an Attribution/NonCommercial/ShareAlike Creative Commons License, with the exception that no rights are granted -- since they are not mine to grant -- in any logo, graphic design, trademarks or trade names of any type. Code samples and code downloads on this site are, unless otherwise labeled, made available under an Apache 2.0 license. Other license models are available on written request and written confirmation.