Some notes for Domino Application Developers

I have just finished up judging all the entries for the OpenNTF Development Contest and I must say there were some great entries, it certainly wasn’t an easy job trying to pick out the best so I went about my scoring criteria slightly differently. I started by giving everybody full points in each category and then deducted points based on different things that I found. Unfortunately a lot of the apps didn’t pass some of what, in my opinion, are fundamental points when it comes to application development in Notes/Domino.

Here are some of the points that developers of full applications should look at for future contests.

Learn how to use templates
All of the entries that I looked at were NSF files that you had to copy to the server and sign. While this is no problem for the initial deployment of an application what happens when you have an upgrade? Full applications should be distributed as an NTF with all it’s template information filled in. Then your deployment instructions are copy the NTF to the server, sign and create a new database based on the template, for an upgrade it is copy to server, sign and do a refresh design of your production application.

Set a default ACL in the template
When using a template based approch for application you can set up the default ACL for databases created from the template that is different from the ACL used for the NTF file. This is done by adding your default ACL entries to the NTF but surrounding them with square brackets. So if the ACL entry -Default- needs to have no access then you would add [-Default-] to the ACL of the template with those rights. This helps the admin ensure that when a new databases is created from the template the ACL is 90% configured correctly.

Detect when your app is not configured
Some of the applications in the contest needed configuration to be done before they could be used successfully however in some cases the applications main homepage appeared with error messages instead of content. Rather then let these errors be displayed you should write some routines to detect if the configuration has been done or not. If not, redirect to a configuration page or a page explaining that the app needs to be configured. If you need a role in the ACL to configure the app then detect that also and let the person know if they don’t have the role. If an admin sees errors on the first run of an app there is a higher probability that they will just delete it as not working correctly.

Test your app in XPiNC and disable it if if you don’t support XPiNC
When you create a new application from a template the first thing that the Notes client does is try open the database. If you have set the launch options for the notes client to open your main XPage then you should test to make sure that it works in XPiNC. A few of the entries just produced an Error 500 message on screen when they initially opened in the client. My suggestion here would be to create a traditional ‘page’ design element that explains that the application should only be used from a web browser pointing to the server.

Documentation should be in the archive from OpenNTF
A number of the applications in the contest didn’t have any documentation in the file downloaded from OpenNTF. No setup instructions, no usage instructions etc. When the app was finally running on the server there was a link to the developers website where they had either documentation or a blog posting explaining the app. This is not documentation, your site could be down or you move to a different system.

These are just a few of the things that I looked for when doing the judging and I’ll be the first to admit that sometimes I cut corners and forget to do things like the default ACL on full apps but that last bit of fit and finish is all that stands between your app being used in a corporate environment or been deleted because it didn’t work immediately.

Oh and if you submitted a custom control to the contest your not going to get off easily, I’ll have some pointers for you in a following blog post.

Tagged with: ,
Posted in None

Guiding users to missing information in XPage applications

I’m currently in the process of rewriting our internal HR system in XPages, It is a typical Notes/Domino application. each employee has a single document in the system that records all their employment data. There are a LOT of fields and in the Notes Client version of the application you would be able to design your form with a tabbed panel so you don’t have lots of fields on a single page.

In XPages you have the advantage of separating the design of the application from the backend data and with that in mind I decided to break the form out into different pages in the application with each page just displaying a subset of the information required and using the Extension Library Application Layout control to manage the overall layout of the form.

In the Notes Client version of the application when the user hit the save button it would display a list of the required fields that were missing but in the XPage version of the application the missing fields could be on a different page so I had to come up with a new way to show that the record was missing some information.

What I did was in the ‘save’ event I check each of the required fields for valid data, if I found that there was missing data I would set an overall ‘incomplete’ flag and also set two other flags, one for the tab where the data was missing and one for the navigator menu option where the data was missing. Then in the PageTreeNodes that define the tabs and navigator menu options I set the image to be calculated depending on the presence of the appropriate flag.

As you can see from the screenshot if there is something missing an exclamation mark graphic is displayed in the tab/menu. This allows the HR staff to quickly see exactly where they need to click to access the page with the missing information.

Hopefully somebody will find this useful and will be able to use this design pattern in their own applications.

Tagged with:
Posted in None

Have you used StackOverflow or ServerFault yet?

The StackOverflow site ( part of the StackExchange family ) has been around for a couple of years now but it is only starting to get noticed within the Lotus Community. Since the beginning of the year the number of XPage related questions has now reached over 400 and looking at the stats for the XPages tag you will see lots of well known names.

XPages is not the only areas of interest for the Lotus Community on Stackoverflow. Looking at other tags you will find questions on LotusScript, Formula Language and even some in relation to customizing IBM ConnectionsSameTime etc.

While StackOverflow is aimed at developers who need assistance with code issues there is another site that is part of the StackExchange family that is just for the administrators out there called ServerFault. It hasn’t had as much interest from the Lotus Community yet, there are currently only 36 questions in the Lotus-Domino tag.

So come on over to StackOverflow and ServerFault and ask your questions or answer anything you know.

Tagged with:
Posted in None

Using a valueChangeListener to build an Audit Trail

A few weeks ago Tony McGuckin posted a new XSnippet on how to use a valueChangeListener bean in XPages to detect when a value was changed in a field on an XPage and it got me thinking, how can I make use of this to create an audit trail/edit log for an application.

There are lots of different methods for creating an audit trail for a Notes/Domino application, the most common is to take a copy of all the editable fields when the document is opened and then when the user hits the save button ( and all validation has passed ) compare the old field values to the new field values. Anything that is different must be an edit so you can add something to your audit trail.

My first attempt at using the valueChangeListener for my audit trail was a bit of a disaster because it was recording changes before the document would even be saved, this is because the valueChangeListener event is fired during the PROCESS_VALIDATIONS phase, anything on the form that would trigger a partial refresh could potentially trigger validation and thus would result in items saved to the audit log. The issue with this is that if the user decided not to save the document those items would already be in the audit log for an event that didnt actually happen.

After discussing the concept with a few other XPagers Nathan T Freeman suggested recording the changes into the view scope and then doing something in the save event to move it to the audit log. I played around with this for a while and I managed to get it working.

In the valueChangeListener bean I added the following to the //do something useful block. This uses two java hashmaps to store the old value and the new value, the key for both hashmaps is the name of the field that was changed. If the hashmaps already exist in the viewScope then it will update that hashmap, if not it will create a new hashmap. This allows for multiple changes to be recorded on a single XPage.

UIComponent c = valueChangeEvent.getComponent();

String changedExpression = c.getValueBinding("value").getExpressionString();
int firstDot = changedExpression.indexOf(".") + 1;
int closingBracket = changedExpression.indexOf("}");
String changedField = changedExpression.substring(firstDot,closingBracket);

String oldValue = valueChangeEvent.getOldValue().toString();
String newValue = valueChangeEvent.getNewValue().toString();

Map<String,Object> viewScope = ExtLibUtil.getViewScope();
HashMap<String,Object> oldValuesMap = new HashMap<String,Object>();
HashMap<String,Object> newValuesMap = new HashMap<String,Object>();

if (viewScope.containsKey("oldValues")){
    oldValuesMap = (HashMap<String, Object>) viewScope.get("oldValues");
    newValuesMap = (HashMap<String, Object>) viewScope.get("newValues");
}

oldValuesMap.put(changedField, oldValue);
newValuesMap.put(changedField, newValue);

viewScope.put("oldValues", oldValuesMap);
viewScope.put("newValues", newValuesMap);

For the save event I added the following script, it checks to see if the hashmap exists in the viewScope and if it does it will loop through all the keys in one of the hashmaps and record the keyname, old value and new value to the audit trail. In my case I’m just calling another function that does the job of creating a new document in a different database, recording the users name and timestamp and then recording the ‘audit note’ that I’m passing into the function.

if (viewScope.containsKey("oldValues")){
	var oldValues:java.util.HashMap = viewScope.get("oldValues");
	var newValues:java.util.HashMap = viewScope.get("newValues");

	for (key in oldValues.keySet()) {
		// Record Audit Trail Documents
		recordAuditTrail("Changed The Field " + key + " from " + oldValues.get(key) + " to " + newValues.get(key))
        }
}

While this method works very well and is easy to implement, just add the valueChangeListener to each field you need it on, it is not perfect. It only works for a single datasource and it has a few issues with Date/time fields that I need to sort out, but it is a good starting point for anybody who needs to implement an audit trail in their Xpage applications.

Tagged with: , , ,
Posted in None
Archives