Search

Mobile tag

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
(posts)
Skype
Sametime
IBM
Facebook
LinkedIn
XING
Amazon Store
Amazon Kindle

Twitter

Domino Upgrade

VersionSupport end
5.0
6.0
6.5
7.0
8.0
8.5
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)

Languages

Other languages on request.

Visitors

Useful Tools

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

17/04/2014

You want to move to Domino? You need a plan!

Cloud services are all en vogue, the hot kid on the block and irressitible. So you decided to move there, but you decided your luggage has to come along. And suddenly your realize, that flipping a switch won't do the trick. Now you need to listen to the expert.
The good folks at Amazon have compiled a table that gives you some idea how much it would take to transfer data:
Available Internet Connection Theoretical Min. Number of Days
to Transfer 1TB
at 80% Network Utilization
T1 (1.544Mbps) 82 days
10Mbps 13 days
T3 (44.736Mbps) 3 days
100Mbps 1 to 2 days
1000Mbps Less than 1 day
(Reproduced without asking)
Talking to customers gung ho to move, I came across data volumes of 10-400 TB. Now go and check your pipe and do the math. A big bang, just flip the switch migration is out of the picture. You need a plan. Here is a cheat sheet to get you started:
  1. Create a database that contains all information of your existing users and how they will be once provisioned on Domino (If you are certified for IBM SmartCloud migrations IBM has one for you)
  2. Gather intelligence on data size and connection speed. Design your daily batch size accordingly
  3. Send a message to your existing users, where you collect their credentials securely and offer them a time slot for their migration. A good measure is to bundle your daily slots into bigger units of 3-7 days, so you have some wiggle room. Using some intelligent lookup you only present slots that have not been taken up
  4. Send a nice confirmation message with date and steps to be taken. Let the user know, that at cut-over day they can use the new mail system instantly, but it might take a while (replace "while" with "up to x hours" based on your measurements and the mail size intelligence you have gathered) before existing messages show up
  5. When the mailbox is due, send another message to let the user kick off the process (or confirm her consent that it kicks off). In that message it is a good idea to point to learning resources like the "what's new" summary or training videos or classes
  6. Once the migration is completed, send another message with some nice looking stats and thanking for your patience
  7. Communicate, Communicate, Communicate!
The checklist covers the user facing part of your migration. You still have to plan DNS cut-over, routing while moving, https access, redirection on mail links etc. Of course that list also applies for your pilot group/test run.
As usual: YMMV

17/04/2014

Domino Design Pattern: Secret documents

Domino's stronghold is security. However security is only as good as you design it. A frequent requirement in applications is to store a data set that is partially confidential and partially available for a wider audience. When you store these 2 data sets in one document, it isn't too hard to have the confidential information slip out:
  • using the document properties in a Notes client
  • using the document rest service
  • the property control from openNTF
In a nutshell: if you have 2 sets of data with different levels of read access requirements, don't store them in one document. A well working pattern in Domino is the "Secret Document". The following picture illustrates the concept:
Use 2 documents to store 2 sets of information security requirements
The user is presented with one form, but saving the entered data is done in two documents. The documents are cross referenced using the UNID. This can happen two way (as shown in the picture): the public document's UNID is saved in the secret document and vice versa - or - one way, with only the secret ID in the public document. A few pointers:
  • Based on the application's need some of the public data get repeated inside the secret document if that needs to be displayed on its own (e.g. a salary list in an HR application)
  • To avoid data drifting apart the respective data would only get updated in the public document ever and then copied to the secret document. In classic Notes that is done using a on-change agent, while in XPages a session-as-signer code snippet will suffice.
  • For very sensitive data (like even the normal user shall not see), these data sets could be stored in their own encrypted NSF. Then the UNID might not be enough, but the full notes:// url would make more sense
  • In classic Notes the embedded form editor makes the user experience with 2 documents seamless
  • In XPages two (or more) data sources sitting on one page will do the trick
As usual YMMV

17/04/2014

SmartCloud Notes little agent helper

Now that we all drank the Cloud Computing CoolAid, we need to make it work. IBM's SmartCloud Notes looks enticing, since it offers 25G of eMail storage, way beyond what IT departments usually want to commit.
SmartCloud Notes even allows you customisation albeit within clear limits. So before you upload your extension forms you need to plan well.
One of the most unpleasant restrictions is: "No customer agents or scripts will be executed on server ", so no agent, no DOLS tasks. However you can run an agent (or other code) on an on-premises server. The interesting question is: when and how to trigger such code. Looking at the basic iNotes customization article you can find the Custom_Scene_PreSubmit_Lite JavaScript function. This could be the place to launch such a trigger. More on that in the next installment.
This article outlines the receiving end - the stuff that runs on your on-premises server. Instead of running agents, I'll outline a plug-in that allows to process the document submitted. The interface between SCN and this service is a JSON submission in the form of:
{
  "userName": "TestUser@acme.com",
  "action": "DemoTask",
  "unid": "32char-unid"
}

Once the plug-in receives this data, processing can commence. Of course the server (that's the ID the plug-in runs with) needs to have access to the mail file at the task required level. Let's get started:
In a plugin project we define a new servlet:
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
   <extension
         point="org.eclipse.equinox.http.registry.servlets">
      <servlet
            alias="/scntask"
            class="com.notessensei.cloudproxy.TaskServlet"
            load-on-startup="true">
      </servlet>
   </extension>
</plugin>

Then our servlet looks like this:
package com.notessensei.cloudproxy;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import lotus.domino.Base;
import lotus.domino.NotesException;

public class TaskServlet extends HttpServlet {

	private static final long		serialVersionUID	= 1L;

	// Number of threads allowed to run concurrently for data sync
	private static final int		THREADPOOLSIZE		= 16;

	// The background executor for talking to the cloud
	private final ExecutorService	service				= Executors.newFixedThreadPool(THREADPOOLSIZE);

	// The Cache where we keep our user lookup objects, handle with care!
	private final UserCache			userCache			= new UserCache();

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// Takes in a JSON String and makes a task object
		InputStream in = req.getInputStream();
		CloudNotesTask it = CloudNotesTask.load(in);
		String result;

		if (it != null) {
			it.setUserCache(this.userCache);
			DocumentTaskFactory.getDocumentTask(it);
			this.service.execute(it);
			resp.setStatus(HttpServletResponse.SC_OK);
			result = "{\"status\" : \"task accepted\"}";
		} else {
			resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
			result = "{\"status\" : \"task failed\"}";
		}

		// Prepare the reply back
		resp.setContentType("application/json");
		PrintWriter out = resp.getWriter();
		out.println(result);
		out.close();

	}

	/**
	 * Get rid of all Notes objects
	 * 
	 * @param morituri
	 *            = the one designated to die, read your Caesar!
	 */
	public static void shred(final Base... morituri) {
		for (Base obsoleteObject : morituri) {
			if (obsoleteObject != null) {
				try {
					obsoleteObject.recycle();
				} catch (NotesException e) {
					// We don't care we want go get
					// rid of it anyway
				} finally {
					obsoleteObject = null;
				}
			}
		}
	}
}


Read More

14/04/2014

Mustache and CKEditor - Round two

Having just a few static values in the CK Editor drop down list really doesn't cut it. So we extend the bean today to have more flexible options. There are a few that spring to mind:
  1. List of all items in a given document
  2. List of all fields in a form (including subforms), eventually with or without the $ fields
  3. List of provided field names
So here we go:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
	<xp:scriptBlock id="scriptBlock1">
		<xp:this.value><![CDATA[#{javascript:mustache.getFormFields(database, "Memo,Person", false);}]]></xp:this.value>
	</xp:scriptBlock>
	<h1>Mustache and CKEdit demo</h1>
	<xp:inputRichText id="inputRichText1">
		<xp:this.dojoAttributes>
			<xp:dojoAttribute name="extraPlugins" value="mustache">
			</xp:dojoAttribute>		
		</xp:this.dojoAttributes>
	</xp:inputRichText>
</xp:view>

The big change here is the replacement of the EL Expression mustache.sampleData with a SSJS expression, so we can hand over all needed parameters. The pattern is the same for the other variations, so I won't repeat it further onwards. The interesting part is the Java method. Since a form might contain subforms you are interested it, I use an array like sting, that I'll split and a boolean parameter to include system fields. Of course one could vary the approach and automatically figure out the subforms in use (have fun with that once it is conditionally computed) or first present a list of forms and then the respective fields. Also, not to depend on some magic, I add the database dependency as parameter. So you have options to play with.
@SuppressWarnings("unchecked")
    public String getFormFields(Database db, String formNameString, boolean includeSystemFields) {
		StringBuilder result = new StringBuilder();
		// Get a sorted set first
		Set fieldNames = new TreeSet();
		String[] formNames = formNameString.split(",");
		for (String formName : formNames) {
            try {
	            Form form = db.getForm(formName);
	            if (form != null) {
	            	Vector fields = form.getFields();
	            	for (int i = 0; i < fields.size(); i++) {
	            		String curField = fields.get(i).toString();
	            		if (includeSystemFields || !curField.startsWith("$")) {
	            			fieldNames.add(curField);
	            		}
	            	}
		}
	            form.recycle();
            } catch (NotesException e) {
	           // Too bad
            }
		}
		result.append(this.preText);
		// Now the content
		for (String f : fieldNames) {
			this.add(result, f);
		}
		result.append(this.postText);
		return result.toString();
	}


Read More

10/04/2014

Lotus de la Mancha

One of my personal heroes is Don Quixote de la Mancha. He is a bat-shit crazy knight, who is true in his courtship of his Lady Dulcinea and never tired to pick a fight with a giant (windmill). His charge against the windmills, is regarded as a result of his craziness, but digging deeper you will find a nobility, worthy of a true knight: stand in for what you deem is right, regardless of the odds of success.
Being true to your calling resonates with me. Wikipedia has an image of the crest of La Mancha.
Based on it I hereby present the coat of arm of Lotus de la Mancha
Lotus de la Mancha - Crest of arms

09/04/2014

CKEditor and Mustache become friends

In the beginning there was WordStar and CSV. The possibility of (then printed) personalized mass-communication had arrived in the form of mail-merge. For Notes eMails that is still a challenge (the latest version of OpenOffice now seems to have a reasonable eMail-Merge, but that's off topic here) since creating the template message with variables to be filled is kind of fuzzy (a.k.a usually out of the reach of mere mortal users).
XPages, Mustache and CKEditor to the rescue! The CKEditor shipping with XPages can be easily customized, so adding a dropdown that inserts Mustache markup shouldn't be too hard. To allow easy reuse of the code, I created a bean than contains all needed components. Add it to a page and simply call the bean functions. The first sample, using only uses static therefore is quite simple:

<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
	<xp:scriptBlock id="scriptBlock1" value="#{mustache.sampleData}">
	</xp:scriptBlock>
	<h1>Mustache and CKEdit demo</h1>
	<xp:inputRichText id="inputRichText1">
		<xp:this.dojoAttributes>
			<xp:dojoAttribute name="extraPlugins" value="mustache">
			</xp:dojoAttribute>		
		</xp:this.dojoAttributes>
	</xp:inputRichText>
</xp:view>

The variable mustache is configured as a managed bean in faces-config.xml:
<managed-bean>
	<managed-bean-name>mustache</managed-bean-name>
	<managed-bean-class>com.notessensei.xpages.MustacheWrapper</managed-bean-class>
	<managed-bean-scope>session</managed-bean-scope>
</managed-bean>

While it seems a little overkill to move the JavaScript into a Java function, we will see that the bean, once completed, is quite useful and keeps what we need in one place.
Read More

01/04/2014

MongoDB to switch to IBM storage backend

One of the rising stars in NoSQL land is MongoDB. It is prominently featured in IBM BlueMix and in conjunction with Node.js the darling of the startup scene.
However it isn't trouble free, has been called broken by design, bad for data and a folly.
In a bold move to silence all critiques, the makers turned to IBM to get access to a distributed, robust and secure backend storage engine: the venerable NSF. As Bryce Nyeggen clearly stated:"But actually, that’s the Tao-like genius of MongoDB – having absolutely nothing new ", this move fits nicely into the all over strategy. On top of that thousands of XPages developers get instant access to MongoDB's APIs and coolness. Clearly an industry wide win-win!

01/04/2014

Communicate with a German

It was going around for a while, how to decode what an English man actually means when he says something. A Harvard Business Review article attributes the insights to Nannette Ripmeester's research and insights. What I was missing in all those tables is the reverse translation. So here it goes:
What a German saysWhat the British should hearWhat the German meant
Bad idea!Please think about that some moreBad idea! But I will still drink beer with you
This won't workInteresting approach, quite innovativeThis won't work, but I will still drink beer with you
I like itThat's not badI like it and I want to drink beer with you
What a crapThat is interestingWhat a crap, but I will still drink beer with you
Du bist ein Idiot
(You are an idiot - informal addressing)
With respect...You are not thinking straight today, but I will still drink beer with you
Sie sind ein Idiot
(You are an idiot - formal addressing)
With the greatest respectYou are an idiot, go away!
You are insaneThat is a very brave proposalYou are insane, but I will still drink beer with you
This is nonsenseVery interestingThis is nonsense, but I will still drink beer with you
Shut up and go away!I hear what you sayStop talking, you can't convince me, let's drink beer instead
As usual: YMMV

28/03/2014

On a quest for the best biking application

Preparing for my June adventure, I'm tracking my cycling progress. So far I tried Endomondo, RunKeeper and had a look at Strava. They all have their ups and downs:
  • Endomondo doesn't provide a open data API and I never got the live broadcast working, but the UI is readable on a bike
  • RunKeeper UI is too tiny for cycling mount, but live broadcast works nicely and the data API is open
  • Strava doesn't seem to provide live updates, but rather tracking after the tour
  • Battery live sucks for all of them
A cycling screen (quite close to what Endomondo does) ideally could look like this:
A UI I would like to see for my cycling app
The big numbers are augmented with subtle hints on median performance using a bar display. Would be nice to see an app like that

28/03/2014

Learning a new language or platform

The first programming language I learned was COBOL both using a Microfocus compiler (with an innovative tool called Animator, today commonly refered to as "Source level debugger") and on an IBM System /36. Until today I think Cobol is cool, not at least since you can reuse its source code, read aloud, as tranquiliser and only in COBOL this compiles without error:
PERFORM makemoney UNTIL rich.
You have to read "full stop" at the end to get all COBOL nuts laughing, because when you missed it, the compiler would mess up (they guy who invented automatic semicolon insertion in JavaScript must have been traumatised by that).
After that dBase, Clipper, Foxpro followed and soon VisualBasic. My early dBase very much looked like a COBOL program, while you could discover both dBase and COBOL thinking in my VB and LotusScript.
It is actually fun to look at source code and guess what was the previous language of the coder. It takes quite a while until old habits do die.
In case of COBOL, they never do, since we cleverly camouflaged the DATA DIVISION. as XML Schema to retain thinking in structured, hierarchical data.
So when you look at moving your applications to XPages, as a classical Domino developer, you are faces with quite some challenge:
Approaching a new platform requires skills
A common approach for skill acquisition is to entrust the very first introduction to a training or coaching session, in the vague hope that everything will sort out, right at the beginning. IMHO that is a waste of everybody's time, once a language or platform has been established for a while.
It is like signing up for a "Business Chinese conversations" class when you haven't mastered a single word yet (In case you want to learn Chinese, check out Chineasy).
A more sensible approach is to work through the basics and then discuss with a trainer or coach the best approach. This holds especially true in XPages, where some of the advanced stuff (ExtLib and beans, to name two) make development so much more easy, but scare off the novice developer.
So with 40h of video (yes, that's a whole work week - for normal mortals, for geeks, that's until Tue evening) there is little reason to join a class blank and slow everybody down.
Most developers I guided towards XPages had to (re)learn the mobile interaction patterns and the idea of a stateful web server (a.k.a JSF - not this JSF disaster).
The fastest transition to XPages and mobile apps happen, when the developers spend time on their own with the core platform, to then cross their swords with experienced designers. That's how it is done - so say we all.

Disclaimer

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 - 2014 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.