Thursday, December 9, 2010

My first request to the XPages Extension library - userScope

I was planning on making a caching mechanism on a user by user basis in SSJS (think userScope)/post it on my blog, but while I sketched the API, I ran into some issues.

In SSJS you have no way to bind callbacks (think event handlers) to the XPages life cycle. This can make the API quite IO heavy on servers with many users.

I've implemented something similar in Domino applications, and have gotten a big boost in performance. The current applicationScope makes it a little cumbersome (not a lot.. you have to write a wrapper for gets/sets that includes username in the scoped field) to cache lookups in applications with Readers fields. Another thing that I miss in the scopes as a caching mechanism is that the scoped variables only live as long as the application is active. In regards to performance/scalability, it would be nice to have caching mechanisms that lives beyond the applicationScope.

I posted a feature request on the XPages Extension Library's project page on OpenNTF.

If this is something that you would like/you have comments, please leave a response on the request, and maybe IBM will implement it :)

Wednesday, December 8, 2010

Spending the holidays in Singapore

I decided I wanted to do something different this christmas/new years. Ever since I went to Korea in 2007, I've wanted to travel to Asia again. Most of my (single) friends travel to some place in Europe when they go on vacation, so I seldom have the opportunity to travel to Asia, unless I travel alone.

A couple of friends recently moved to Singapore. I contacted them and asked if they wanted company in the holidays. Luckily they did, so this holiday season I'll be halfway around the world in a very different climate than I'm used to this time of year :)

Saturday, December 4, 2010

Favorite Applications repository v0.1 Alpha

I've started working on an application heavily inspired by Tim Tripconys PIM Slap application.

I've made it document based, so that you can easily add more applications (in PIM Slap, you had to add them in Domino Designer).

In the config, you can specify the servers you have your apps on:


In the application documents, you select the server, and write the path to the application.
Save the document, and the other "required" fields are set through code. Once the document is saved. Click refresh on the framesets. Some apps require you to select a frameset, or they'll open in a separate tab. If there aren't any framesets in the app, leave it empty.

If you have an app spread across several servers, and want the possibility to open the app on those servers, click refresh below the "Servers with.." table. The code will then look through all your configured servers for the application, both by path and by replica.


Once you've configured the applications, you can click in the left menu, on the little icon to the left of the application title. This should open the app in the main frame. On the top of the app there's a dialog list that lets you switch servers for the app.

My motivation for making this app is that I have several OpenLog implementations spread across several servers, and I'm tired of opening them manually. The reason I don't have any other screenshots is that they would show the server names of my company, and I've heard that's a no no.

I decided to post this very early version of the app so that I might get feedback on wanted improvements early on (apart from poor usability, it does what I needed). One of the first things I'll implement next is a Database Browser-button, so that you don't have to remember the path of every app you want to configure.

Hopefully I'll get around to comment the code the next time I get my hands dirty with the app again.

My brain is now fried after trying to get around all the quirks of Notes development, so no more development tonight. :)

>> Download Demoapp

Share and enjoy!

Thursday, December 2, 2010

New and improved EventDelegator with InViewEdit demo

In may 2010, I posted about server side event delegation. The demoapp was from my (current) point of view very messy and hard to use for any other purpose than the demo.

I've improved the EventDelegator code at work, and made it more general purpose. The client side script can be used for event delegation in the browser, or if you want to, use it in combination with server side event delegation.

On the client side, you should be able to delegate most events (I haven't implemented onChange).

This demoapp implements the same functionality as the previous, with a couple of additions. There's an edit icon on every editable area. When you click to edit a name, the field gets focus. If you press escape while in the field, the edit is cancelled, same as if you click the cancel button. The code is also a lot better documented through comments.

Here's the video from the previous app:





A screenshot from the new demoapp:


>> Download Demoapp

Debugging traditional WebQueryOpen/WebQuerySave code

I just had a eureka moment when it comes to debugging WQO/WQS code. Once upon a time I decided it was impossible to debug code that required NotesSession.DocumentContext, through the (local) Domino Debugger. It's not :)

You need a global NotesDocument variable that you can bind the DocumentContext to. The reason that it has to be global is that it has probably has to be available across multiple methods/scopes. It should be put inside a script library that doesn't use other script libraries. In most of my apps, I have a script library stack, where the most general code is put inside a script library that most other script libraries use (either through "inheritance" or through Use). This is where I put the global declarations.

Then you need a function that returns either NotesSession.DocumentContext, or a temporary document. This should be put inside the same script library as the aforementioned global declaration.
Function getDocumentContext() As NotesDocument
On Error GoTo returnEmptyDocument
'// Returns NotesSession.DocumentContext if availabe, else a temporary document
Dim s As New NotesSession()
Set getDocumentContext = s.documentContext
If getDocumentContext Is Nothing Then GoTo returnEmptyDocument

Exit Function
returnEmptyDocument:
If contextDoc Is Nothing Then Set contextDoc = s.currentDatabase.createDocument()
Set getDocumentContext = contextDoc
Exit Function
End Function
contextDoc is declared as a global variable.

Wherever in your code where you fetch NotesDocument.DocumentContext, you have to change that to call the above function, getDocumentContext().

To test code, all you have to do is to create an agent, bind getDocumentContext to a NotesDocument variable (or modify the global var), set the needed fields, and you're ready to debug the code.

E.g.
Call getDocumentContext()
Call contextDoc.replaceItemValue( "someNeededField", "someTestValue" )
Call methodThatsDesignedForWQOOrWQS()
Share and enjoy!