Just when I thought I got readers/authors fields all figured out

The case seemed simple: I had a document that may only be edited by a bunch of people. So I added an authors field. Only that group (and application administrators) are allowed to view that document. So I added a readers field for the administrators role. I don’t need to add the group from the authors field to the readers field, since author access also allows reader access. All good.

The admins wanted an option to disallow editing the document for the people in the authors field, so I added a function that changes the authors field into a readers field. Simple. On the document I simple called:


Didn’t work…

Result was that the people in the (former) authors field could still edit the documennt. What?

It turned out that calling setReaders(true) on an authors field creates a field that is a readers field as well as an authors field! I never knew that was even possible and I wonder who does/ did. I know that it can’t be done in the Designer UI.

With this you can have a single field on a document that restricts reader access to the people in it AND allows that people to also edit the document. This isn’t how a (normal) authors field works: it can extend the readers, but an authors field on its own doesn’t restrict reader access.

You might think: great, lets use this. Well… I wouldn’t recommend that. I never read anything about this and don’t know if it’s supported (probably isn’t). Also, this requires further testing. What will happen if you edit the document using a form in the Notes client? (UPDATE: the field remains a combined readers/ authors field after editing a document through the Notes client, it doesn’t seem to matter if the field is or isn’t on the form or what the type is set to – text, readers or authors).

Want to try it out? Use this (don’t forget to add you own name to that field – got me the 1st time 😉 )

  Document doc = dbCurrent.createDocument();
  Item name = doc.replaceItemValue("name", "Mark Leusink");

BTW: the fix in my app was easy: call a setAuthors(false) as well as a setReaders(true).

(this is either an actual field type on an actual document or I’m pretty good with Photoshop)

Debugging and designing at the BLUG 2013

I got back yesterday from an excellent 2 days in Leuven where I spoke at the BLUG 2013 (where the B as of this year stands for BeNeLux). This was actually my first visit to the event and I enjoyed every bit of it. The location was impressive: the “Grand BĂ©guinage of Leuven“, a former community for unmarried, semi-religious women (the BĂ©guine), dates back to the 13th century and is on the UNESCO World Heritage list.


Theo Heselmans did an amazing job in organizing the event and spoiled us with lots of Belgian chocolate. The attendance was again higher than last year and I heard that the BLUG is now the worlds largest LUG.


I did 2 sessions at the event: one semi-non-technical on design frameworks together with Martin Vereecken, Matt White and Mark Myers. Read the slides if you want to know how that relates to the missionary position 🙂

I did a second session on my own titled “Stop (de)bugging me!”. It was the last session of the event but still very well attended. I talked about the (SSJS and Java) debuggers in Notes 9 and my XPage Debug Toolbar.

See you hopefully next year in Breda (but probably sooner)!

Awesome new release of the XPage Debug Toolbar!

A couple of months ago I set a goal: I wanted to release a new version of the one tool every XPages developer needs (well… besides Designer of course): the XPage Debug Toolbar. I had a couple of great ideas and started working on them. And here we are: just in time for IBM Connect I bring you… version 3 of the toolbar! I’m pretty excited about this new version: check it out and hopefully you’ll be too.


So what’s new?

If you clicked the image above you might have noticed a new tab: files. It allows you to view server-based log files (inspired by the XPages Log File Reader).


I added the option to store messages from the toolbar in documents (“persistent logging”), independent from displaying the toolbar. This allows you to configure the toolbar to store, for example, error and warning messages for all users (including those that don’t have access to the toolbar) in a database you can specify. The document/ field format used is that of OpenLog. The persistent logging feature can also store runtime errors thrown by the server if you set a custom error page in your application’s properties. Have a look at the sample database in the release: it is configured to store warnings and errors in the current databases and contains a sample form/ view.

I’ve completely redesigned the inspector: it is now a lot more user friendly, easier to work with and gives a much better overview of all the (declared) methods/ fields in a class.


The timers tab is gone. I’ve added an option to the messages tab to also show milliseconds with every message. I also improved the layout of the toolbar so it’s better readable if you’re using jQuery Mobile or Bootstrap. There are a couple of other usability changes you’ll discover soon enough if you start working with it.

A video on all the new features is on my todo list and will come (I think). In the meantime, check out this video on NotesIn9 I did on the toolbar basics. If you have any questions about my toolbar, you can also catch me at IBM Connect next week in Orlando. I’ll tell you everything you want to know over a beer 🙂

You can get the toolbar in 2 different ways: from the project site on OpenNTF or from my public repository on GitHub. You can also preview it online on this demo server.

Oh and by the way: if you’re into mobile XPage development with Teamstudio’s Unplugged, check out the mobile version of the Debug Toolbar I built for the new (and free) Unplugged Mobile Controls on OpenNTF.


IBM Champion for 2013 and my appearance on NotesIn9

The new IBM Champions group for Collaboration Solutions for 2013 was announced yesterday and guess what: just as in 2012 I’m on the list! Big thanks to the people that nominated me (Patrick Kwinten, Wim Jansen) and the IBM selection committee for selecting me again. I’m honoured to be amongst that group of great people.

On a side note: as part of the “Drive To 99” I recently recorded a video for NotesIn9 talking about my XPage Debug Toolbar. If you haven’t watched it yet: go watch it here (tip: subscribe to the NotesIn9 podcast on iTunes for easy viewing)! Although recording my first screencast was difficult at first, in the end I found it fun to do and a great way to bring information across  Oh, and stay tuned for an amazing new release of the toolbar coming in a couple of weeks…

Importing an entire JavaScript library into a database

If you want to import JavaScript and/or CSS files from a library like Bootstrap or JQuery Mobile (or any other file) into your application you can do so in the Resources section. Problem is that such libraries probably rely on a fixed (relative) folder structure. Although you can also create that in the Resources section I find it to be quite a hassle.

Luckily there is a whole lot easier and faster solution:

  • Open the Package Explorer
  • Drag the entire folder you would like to import from your computer to the WebContent folder.
  • Done!

The files and folders you imported can now be referenced using a URL that’s relative to the root of the application/ database.


XPage Debug Toolbar v2 released!

A few minutes ago I uploaded v2 of my (prize winning) XPage Debug Toolbar to OpenNTF. This version has quite some changes in it. The biggest being that the toolbar was rewritten using Java/ managed beans.

Here’s a list of what’s new in this release:

  • The toolbar now uses a managed bean (and only a little SSJS). Biggest advantage of the bean approach is that you can now easily log messages from about anywhere with no restrictions.
  • Added the option to remove a (scoped) variable.
  • Added the option to easily inspect any scoped variable using the API Inspector (Tip: very handy for beans!).
  • When logging an error using dBar.error(), a full stacktrace can be included that can be shown in the Messages tab.
  • Added an error page: include it in a database (and set it in the application properties) to log errors to the debug toolbar instead of a dump on screen.
  • The toolbar now shows the Java heap size and allows you to run the server’s garbage collector
  • “importlist.xml” file updated for the OpenNTF import/export tool.
  • Option added to change the color of the toolbar (who hasn’t been waiting for it!)
  • Icons added for the toolbar custom control.
  • And of course (like any release list includes): “various performance and stability improvements”.

The new version can be downloaded from the project site on OpenNTF.

Have fun with it and let me know what you think!

RESTless getting data from XPages to IBM Connections and back again

Recently I was working on getting data from IBM Connections in and out of an XPages application using the IBM Connections API. The API was great to work with: it is pretty good documented and easy to understand. It uses Atom feeds and RESTful calls to communicate.

I needed to implement the data read/write ‘barebones style’. No HTTPClient and no Abdera. Don’t ask me why. but it’s not because I like to torture myself. In the beginning that actually worked quite well: I was able to implement and parse the GET, PUT and DELETE calls without any big problems.

Until… I tried to create a File in Connection. According to the API this can be done in two ways: either by sending multipart form-data (including the encoded file) or just the file using a POST request. Since the multipart form-data option returns a JSON object (and everywhere else I worked with XML/ Atom), I went with the option to just post the file.

To test my calls and the API I was using the Dev HTTP Client Chrome plugin (which I can highly recommend!). Using that I could simulate the request: make a POST to the correct Files URL, select a file and of we go. Response code: 201. All fine.

I then tried the same in SSJS: create a HTTPUrlConnection, set the method to POST and write the file to an output stream. Response code: 503 (“service unavailable”). No matter what I did.

So I searched. And searched. And tested. And couldn’t figure out why it failed. Until I had a bright moment: check what actually’s being sent (headers and body) and compare it with the output of the Dev HTTP Client. For the plugin that was easy: F12 in Chrome and you’ll have all the information you need. For the server-to-server call it was more difficult. I ended up installing Wireshark to inspect the network traffic.

After I found the POST request (in the enermous amount of data Wireshark generates) I noticed something strange and was sure I didn’t add: a Content-Type header with the value application/x-www-form-urlencoded. That is obviously wrong: I’m sending a binary file. It shouldn’t add that header. There was a bug in Java that describes the same behaviour, but that was supposed to be fixed in a later 1.5 version. I (now) know that the Java 1.6 version in Domino is not Oracle’s one so might that explain why this issue (or is it a feature?) still exists.

The solution was easy: override that header with the correct one. I used the URLConnection.guessContentTypeFromName() function (yes, that really exist) and added the header. Response: 201. Every time. Happy Mark and client.

Send a serverside redirect to a new window

Redirecting a user on an XPage server side can be done by calling one of the context.redirectTo() methods or by using the facesContext.getExternalContext().redirect() method. But what if you want to open that page in a new window/ tab?

The only way to open a link (AFAIK) in a new window/tab is by making a clientside JavaScript window.open(”) call. There are a couple of ways to send that call to the browser (using the onComplete event or a conditionally rendered outputScript control), but the XPages engine also has a little known method called view.postScript(“”). Anything you add there is send to the browser upon completing the eventhandler as clientside script.

Using that, opening the result of an eventhandler in a new window/ tab can then be accomplished by writing:

<xp:link escape="true" text="Start" id="link2">
  <xp:eventHandler event="onclick" submit="true"
    refreshMode="partial" refreshId="link2">
      //execute server side code here to determine a target url
      var target = "http://www.nu.nl";
      view.postScript("window.open('" + target + "')");}]]>

Showing real progress in XPages

One of the actions in an XPage application I’m building might take some while to complete. The action is triggered by a button so I added a loading indicator image that is shown on the button’s onStart event and hidden in the onComplete event. The problem with this was that it gives me no clue as to how long it will take and if it’s making any progress at all. So I searched for a way to display a real progress bar.

I investigated a solution involving a partial refresh of a part of the page while another partial refresh is running. This seemed a no-go: the 2nd partial refresh will not start/ complete until the first is finished. I also looked into threads and Eclipse jobs: but found that too complex for just a simple progressbar.

The solution I came up with includes a couple of components. In the (long-running) code I store the current progress (a number from 1 to 100) in a variable in the sessionScope. When the long-running code is started I use the onStart event to call a client-side function that uses the JavaScript setInterval() function to periodically call another XPage using a dojo.xhrGet(). That second XPage (getProgress.xsp) has only one purpose: it returns the progress from the variable in the sessionScope as JSON to the browser. This progress is then used to display a dijit.ProgressBar() with the updated progress. In the onComplete event of the long-running eventHandler I cancel the periodic checking.

Enough talk: demo or it didn’t happen.

You can download the demo database here. As far as I know the code will only work on 8.5.3. The demo page uses the built-in Dojo Claro theme. Oh,  and the messages are optional!