Monday, August 4, 2008

ALUI Best Practice - Don't Hardcode ObjectIDs: Use UUIDs Instead

In ALUI, there are 2 ways to identify uniquely an object:

  • ClassID (the type of object) + ObjectID (The ID of the object within the classID family)
  • Global UUID (unique ID throughout the environment)

The ClassID/ObjectID combination is used throughout the Portal API to query/open/manage the ALUI objects, as well as navigate to communities and pages. The ALUI ADAPTIVE TAGS are no exception: you will notice that they require ObjectID / ClassID to perform their tasks, like for example the opener tag:

<pt:standard.openerlink pt:objectid="219" pt:classid="514" pt:mode="2" target="myWindow">view community page</pt:standard.openerlink>

The main problem is not in the fact the ObjectID / ClassID is a bad way to identify an object, but in the fact that the ObjectID WILL NOT NECESSARILY (very improbable actually) be the same when you migrate objects from one environment to another. And that's where it can hurt...

Indeed good practice is to test out your creation in DEV / TEST / STAGING etc... and then migrate it using the ALUI migration tool. Since objectIDs will be different after migration in the new environment, all the objectIDs used in Adaptive Tags will have to be changed...hassle indeed.

Fortunately, UUID does NOT change with migration (or very improbable) from environments to environments. So that would seem a good option if you need to hardcode IDs, especially in Adaptive Tags, and I'd recommend that option everywhere you can.

In order to make it possible, I built a Adaptive Tags that does just this: Transform a UUID into its corresponding ClassID/ObjectID pair. All you need to do is use that Adaptive Tag before using the opener link tag for example. The object and class IDs are stored in shared memory (adaptive tag framework) with the specified scope and can be reused with any other tags that require objectID / ClassID.

<pt:taglibname.convertuuidtoid pt:uuid="{UUID}" pt:objectid="objectIDKey1" pt:classid="classIDKey1" pt:scope="portlet request" />

<pt:standard.openerlink pt:objectid="$objectIDKey1" pt:classid="$classIDKey1" pt:mode="2" target="myWindow">view community page</pt:standard.openerlink>

What's even better is that you can use this tag even for your remote portlet applications, like any other tags.

The code to change a UUID to the ObjectID / ClassID pair is fairly simple. Just get the Migration manager and call the convert method UUIDToObjectID to get the job done. I created a helper method that package it altogether:

public Object[] getClassObjectID(String uuid){
        Object[] oClassIDObjectID = null;
        if (null != uuid) {
            try {
                IPTMigrationManager oPTMigrationMgr = (IPTMigrationManager) oPTSession
                        .OpenGlobalObject(
                                PT_GLOBALOBJECTS.PT_GLOBAL_MIGRATION_MANAGER,
                                false);
                oClassIDObjectID = oPTMigrationMgr.UUIDToObjectID(uuid);
            } catch (Exception exc) {
                oClassIDObjectID = null;
            }
        }
        return oClassIDObjectID;
    }

The first item in the returned array is the ClassID (oClassIDObjectID[0]), the second item is the object ID (oClassIDObjectID[1]).

You can download the code on my newly created subversion project (http://alui-toolbox.googlecode.com) on Google code (I'll be updating/maintaining this as I see fit - feel free to suggest at will :)):

svn checkout http://alui-toolbox.googlecode.com/svn/trunk/ alui-toolbox-read-only

No more mocking around with IDs during migration :)

Hope that helps!