Computing a document UNID

Monday, October 20, 2014 at 12:02 PM UTC

Prerequisites: this example uses the OpenNTF Domino API

I went into some trouble the past weekend so I decided to blog about on how to compute a valid document UNID when opening a document from e.g. a view control or other repeating controls you have in XPages.

Imagine your application that has some data stored. Beside the fields that contain your main data you have other system information available such as the NoteID and maybe fields that contain unique values to identify your document. The most common way to store a unique value in one dataset maybe a field that holds a value computed via a simple formula like @Unique. This value is unique within the database and should not be re-computed during the lifecycle of the document. You may want to use a "computed when composed" field for that.

This is about how to access your document via an XPage associated with a form and/or via some URL parameters and it is separated in 4 sections:

  • open the document with default settings
  • open the document via a custom page and document id
  • open the document via a custom page and a custom URL parameter
  • open the document via a custom page and a custom URL parameter that fetches a cached UNID

Sure there are other ways to compute the UNID but these are the most common scenarios IMHO.

The application uses simple view controls to display view data and there is one column defined as clickable. The value for the target is set to default and computed targets as well. The datasource for that view control is a simple view in the database,

1. Opening a document "as is" in the default way

The clickable column is defined as follows:

<xp:viewColumn columnName="lastname"
id="viewColumn1" displayAs="link" openDocAsReadonly="true">
<xp:viewColumnHeader value="Lastname"
id="viewColumnHeader1">
</xp:viewColumnHeader>
</xp:viewColumn>

This will present the document with the corresponding XPage with an URL like this:

.nsf/%24%24OpenDominoDocument.xsp?documentId=34F30F2D72593AA5C1257D7700595637&action=openDocument

Look at the part after the .nsf/: it opens the document "as is" with the pseudo XPage that was associated with the document via the form's property.

2. Opening the document via an URL parameter "documentId"

You've seen this before: the view column was computed to open a specific page and a document given by it's ID like this:

.nsf/name.xsp?action=openDocument&documentId=34F30F2D72593AA5C1257D7700595637

Notice the action paramater that says: please open the document only in read mode and not in edit mode. This would be the way to open it in edit mode if you specify the parameter "action=editDocument" instead.

3. Opening the document via a custom URL parameter

In this case you have to compute the real UNID via SSJS. The URL might look like this:

.nsf/name_1.xsp?pid=34F30F2D72593AA5C1257D7700595637

The parameter "pid" isn't a known one so you have to compute the UNID in your datasource via SSJS like this:

<xp:this.data>
<xp:dominoDocument var="document1" formName="fUserName"
action="openDocument" documentId="#{javascript:return param.pid}">
</xp:dominoDocument>
</xp:this.data>

4. Using a managed bean to compute the UNID

This is the "hard" one. You may want to compute the UNID via a managed bean if

  • documents are maintained by different users
  • you need to compute if the document should be accessible or not
  • load other stuff to your document like responses

The goal is use an URL like this:

.nsf/name_1.xsp?foo=ABOU-C5A6D

Step 1: create a managed bean

To provide an application scoped cache for all your documents you have to create a managed bean class like

package org.openntf.demo;
 
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
 
import org.openntf.domino.ViewEntry;
import org.openntf.domino.ViewEntryCollection;
import org.openntf.domino.utils.XSPUtil;
 
public class DocumentCache implements Serializable {
 
/**
* Members
*/
private static final long serialVersionUID = 1L;
private Map<String, String> names;
 
public DocumentCache() {
init();
}
 
public void init() {
names = new HashMap<String, String>();
ViewEntryCollection col = XSPUtil.getCurrentDatabase().getView("ByName").getAllEntries();
for (ViewEntry ent : col) {
names.put(ent.getDocument().getItemValueString("unique"), ent.getDocument().getUniversalID());
}
}
 
public synchronized Map<String, String> getNames() {
return names;
}
 
}

Step 2: define the bean

The code assumes that your documents contain a field called "unique" computed initially to a value of @Unique. Then you create an entry in your faces-config.xml to setup the bean:

<!-- names cache -->
<managed-bean>
<managed-bean-name>cache</managed-bean-name>
<managed-bean-class>org.openntf.demo.DocumentCache
</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
</managed-bean>

The bean is application scoped, that means it loads when the application is running the first time!

Notice the init() method: this method has to be called whenever the data may change, e.g. in a "postSaveDocument" event of your datasource that this bean provides. Just call the

cache.init()

method.

To compute the UNID of a document via an URL parameter you can do it like this:

return cache.names.get(param.foo)

This works if your view contains a column like this:

<xp:viewColumn columnName="lastname"
id="viewColumn1" displayAs="link" openDocAsReadonly="true">
<xp:this.pageUrl><![CDATA[#{javascript:"name_2.xsp?foo="+doc.getDocument().getItemValueString("unique")}]]></xp:this.pageUrl>
<xp:viewColumnHeader value="Lastname"
id="viewColumnHeader1">
</xp:viewColumnHeader>
</xp:viewColumn>

Notice the parameter called "foo". It doesn't matter how the parameter is named, just provide it in your SSJS code correctly.

I hope you get the idea of how to deal with UNIDs to open a document. This example uses the fake names data and the views that ship with the database. I uploaded the whole database (without the data though) to Bitbucket. Just copy the documents from the fake names into that database, run the Agent "setId" to fill the "unique" item in all documents and play around with it.

The source can be found here: https://bitbucket.org/zeromancer1972/computeunid

I also provided a live demo as usual here: http://notesx.net/projects/comp_unid.nsf/index.xsp

You may also want to look at this post from Brad Balassaitis.







Leave a comment right here