XPages101 done. (for now)

Yesterday, Ben Poole and myself presented the XPages101 course which I have designed over the last couple of months to be an introduction to developing with XPages.

Overall it seemed to go pretty well, the timings need some work, I went a little fast at some points which may have left a few people overwhelmed at the fire hose of information we got through in a short period of time! That will not happen again now that I understand how it all hangs together a bit more.

The feedback from the attendees was really gratifying...

Question Score
Overall, how would you rate the course? 95% (between Excellent and Good)
How was the course material? 86.67% (between Excellent and Good)
How was the presentation style? 86.67% (between Excellent and Good)
Would you recommend the course to your colleagues / nerdy friends? Yes: 100%

 

Obviously there's always room for improvement and there were some great feedback comments as well...

"A real eye opener for me as I've not looked XPages prior to the course."

"Excellent value for money. Pitched just right for the first steps into XPages."

"It gave me a very good understanding of XPages under the bonnet."

"It was great being here, great course, the XPages start I was looking for."

One of the things which I had consciously not done was provide lots of handout materials. The aim was to reduce the costs of the course as much as possible. From the feedback it seems people would have been happy to pay extra to get more paper based materials. So I think in future iterations of the course we'll change that around.

The other area where a couple of people expressed an interest was for an "intermediate" course. This leaves me in a bit of a quandary, as I'm not sure I know what intermediate is. So if you have any thoughts I'd love to hear them.

Overall though, as I said earlier, it was a great day. Good fun for me, and hopefully useful to everyone else.

Announcing XPages101 - An Introduction to XPages course

A few weeks ago I asked the twittersphere what people thought would be a reasonable cost for a one day long, introduction to XPages course. This was before I had investigated the cost of anything such as room hire etc, and also before I had thought about what the content for the course might be. But I liked the idea of running a single day bootcamp that will help you get started with XPages so, taking people's advice and sourcing all of the elements for the course, I'm happy to be able to open up xpages101.net today.

I've managed to find a very reasonably priced training room, and more importantly, written a sample application which includes as much of the elements of a "real world" XPages app as I could squeeze into an eight hour course. The plan for the day is that you bring along your own laptop with Domino Designer 8.5.1 installed, I give you a starting point template and then together we go through the steps to build an XPages application. As we progress we'll cover all of the major elements of XPages including the new design elements, server side Javascript, Dojo, OneUI and Themes, searching and so on. Then at the end of the day you'll have a working application (in theory at least!) and be able to go back to your office and use it as a reference point for your first real world development when you deploy Domino 8.5.1.

So please do head on over to xpages101.net, have a look at the site and if you've got any questions drop me a line, otherwise I hope to see you in London in February 2010.

Catch and Cancel Return Key Press for Safari in XPages

The solution to one of the small but annoying bugs in IQJam had eluded me for quite a while, so this morning I resolved to have another go at it after a lazy weekend of feeling ill. And, lo and behold, I managed to fix it.

So a little bit of background to the problem, when you login to IQJam we provide a login button for you to press after filling in your username and password, but most people are used to just hitting return after finishing typing their password. Unfortunately, this is a case where Safari actually implements internet standards just a little too well. What browsers are meant to do (but none of them except Safari actually do) is submit the form that a text field is in when the user presses the return key.

Now in most development environments this is pretty easy to fix, you just add a

return false;

to the onSubmit action of the HTML form that the field is located in. But with XPages we don't have access to the action, onSubmit or anything else to do with the form, as pretty much everything you click on in an XPage will want to interact with the server using code that has been generated for us rather than written by us.

In this case, I wanted to do my own AJAX post request to the server and deal with the entire interaction myself and stop anything else being submitted to the server. The problem was how? I spent ages trying to stop event bubbling to try and cancel the keypress event when the user presses return to no avail. However, I did learn, at least, that the keypress event fires before the form is submitted back to the server.

So my solution is to put this code in the keypress event of the password field:

if (thisEvent.keyCode == 13){

dojo.connect(

document.forms[0], 

'onsubmit'

null

function(e)

e.preventDefault();

return false;

}

);

doLogin("#{id:userName}", "#{id:password}")

}

Basically when the user presses the return key, using Dojo, I can re-write the form onsubmit method to prevent it posting back to the server, and instead run my own "doLogin" function.

It's important to be aware that this will effectively break the XPage for all other actions unless I re-write the original onSubmit function back to what it was after I have finished, but here, I am going to be re-loading the page anyway so it's not necessary.

Once again, we have more evidence that if you're beginning to get into XPages, it's worth spending as much time learning Dojo as it is to learn the XPages themselves.

On synchronization in XPages

The biggest issue that we had with XPages in 8.5.0 was performance, every piece of code you wrote had to be optimised to get the best performance, something which us Notes developers have spent all too little time on in the past.

With 8.5.1 everything is faster from DDE onwards, but there are some code changes that we can take advantage of to make things even better. Most important of these is synchronization. For those of you who know Java this will be a familiar concept that has just been implemented into Server Side JavaScript (SSJS). But for the LotusScript developer, here is my quick attempt at explaining it...

If you have a commonly used piece of code, it will be called by multiple different areas of the system at the same time (or at least very close together) and return the same result. If you're doing some expensive piece of work (such as a DbLookup) then all of the calls to that code will run and there will be an inevitable performance hit.

By adding the synchronize wrapper around the "expensive" code what will happen is that all of the calls to that code will queue up behind each other, so that code can only run once at a time. We can then cache the results of the code so that all of the queued up calls can just get that result from memory (the applicationScope for example) rather than having to go off and calculate it again and again. A very simple concept but one which saves a huge amount of processing time.

But what will our code look like? Well here is a sample function from the upcoming IQJam application that will be launching later this week.

function getControlPanelFieldString(fieldname){

synchronized(applicationScope){

if(isCacheInvalid("controlpanel_" + fieldname, 600)){

var controlPanels = database.getView("lookupControlPanel");

var controlPanel = controlPanels.getFirstDocument();

applicationScope.put("controlpanel_" + fieldname, controlPanel.getItemValueString(fieldname));

controlPanel = null;

controlPanels = null;

}

  return applicationScope.get("controlpanel_" + fieldname);

}

/**

A generic caching mechanism for each key will check to see if it is 'n' seconds

since it was last updated. Use for things that change relatively infrequently  

*/

function isCacheInvalid(key, cacheInterval){

var currentTime = new Date().getTime();

if (!applicationScope.containsKey(key + "_time")){

applicationScope.put(key + "_time", currentTime);

  return true;

}

var diffInSecs = Math.ceil((currentTime - applicationScope.get(key + "_time")) / 1000);

if (diffInSecs < cacheInterval) {

return false;

} else {

applicationScope.put(key + "_time", currentTime);

return true;

}

}

We store lots of tiny variables about the application in a "Control Panel" document and then read them as needed into the applicationScope. The nature of the variables is that they don't change much so we can cache them for long periods of time (10 minutes in this case).

As with lots of XPages code, the idea for this came from the Discussion template (which is quite dramatically different under the covers in 8.5.1), so I'd highly recommend digging through the code in there to get an idea of what you can do with XPages. And of course we have to offer thanks to Thomas Gumz and the other XPages developers in IBM who write the code that the rest of us can then re-use for our own dastardly ends.

Disclaimer: Notes/Domino 8.5.1 is beta software and no features are guaranteed until release.

Sessions, sessions, sessions

When is a session not a session?

Most Domino web sites these days will be running some form of session authentication which stores a cookie on the user's browser and a tiny piece of memory with details about the user on the server. This has always worked fine, and of course these sessions can time out (by default after 30 minutes).

But with the advent of XPages we now also have the sessionScope variable container which allows us to store information about a user's session (whether they are authenticated or not). This offers us huge opportunities for performance improvements as it means we don't need to keep on doing @DbLookups to get user specific information for every page load. But it does introduce some potential issues if the authentication session timeouts are different to the sessionScope timeouts.

Basically the server needs to be able to clear out sessionScope variables after an amount of time, otherwise the server would run out of memory very quickly indeed. But in a recent project we had users who would open a page and then come back to it 2 or 3 hours later and then wonder why everything had stopped working. This is because the default timeout for sessionScope variables is something around 30 minutes and our session timeouts were set to 2 hours.  So once the page had been left inactive for half an hour it effectively lost all of the background information that drove how it should act when the user pressed the save button for example.

The solution is very simple, but very important. In the application properties for your database (opened in Domino Designer these days remember), go to the XPages tab and make sure to set the Session timeout field to be more than the authentication Session Timeout (which you set in the server or website document). The rule of thumb that we have come to (in the absence of any official guidelines from IBM) is that if you have a 2 hour authentication timeout for your website, then set the XPages Session Timeout to 3 hours.

Generally the application timeout is less important for this sort of thing, but we took the opportunity to also set that to 3 hours in this case as I knew it wouldn't be too large.

There are, of course, caveats here. If your server has memory issues then this is only going to exacerbate them as for each user (remember a user is just a visitor to the website, not necessarily someone who logs in) is going to take up some memory from the server for a minimum of 3 hours, but for us it solves more problems than it causes.

Of course, if you are not using the sessionScope to store any page sensitive data then you can just ignore all of this, but once you start using the sessionScope, it does become rather addictive, so I suspect you will get some benefit from setting this variable. Either way if you start to see completely bizarre errors, this may be a good first port of call.

Hopefully this article will save someone the pain of trying to debug seemingly un-reproducible errors in a dev environment where you don't have the time to leave pages inactive for hours on end!