Pages

Sunday, July 29, 2012

What's in a Portal URL?

I've been working with WebSphere Portal for many years and I always wondered about the format of the URL, but never took the time to track it down. Last week I stumbled on this interesting document that laid it all out.

The short if it is that the typical URL
http://localhost:10039/wps/portal/!ut/p/b0/04_Sj9CPykssy0xPLMnMz0vMAfGjzOKd3R09TMx9DAwsTC0MDTwdPULNzYJdjAxczfXD9aPwKnE0hiowwAEcDfT9fPLT01NT_EtL9Auys9McHRUVAdjo3OY!
is an XML representation of the portal page compressed and encoded with a proprietary algorithm. It turns out there are several alternate URL schemes for WPS, but this one is the most common variation that everyone is familiar with.

No need for me to go into details - the document explains it quite well.


EDIT 09/30/2013: Here's a URL that describes REST services which will encode/decode portal URLs:

http://www-10.lotus.com/ldd/portalwiki.nsf/dx/IBM_WebSphere_Portal_Remote_State_Service_and_Fragment_Service

Tuesday, July 24, 2012

A Lotus Notes Calendar Widget

Most of my blog entries reflect some challenging task that I helped my client complete, this latest one was particularly interesting because there was little documentation to guide us. In fact I'm going to blog about something that I wouldn't recommend to anyone but sometimes there are no easy ways out.

The Requirement for a Calendar
My client wanted to expose their user's lotus notes calendar entries into a JSR 286 portlet but we couldn't find any easy out of the box solutions for this. Since I don't know anything (at all) about lotus domino I turned to a resident expert for advice on how to get my hands on the calendar data. We appeared to have two options:

  • Develop a custom lotus form that would require replicating every user's mailbox
  • Re-purpose an existing form to suit our needs

After much discussion we decided to pursue the second option since we had little time to roll out the portlet and we didn't want to alter the mailbox database of thousands of users.

Tapping into ReadViewEntries
The domino mailbox supports a URL command named ReadViewEntries that can be used to retrieve calendar entries as JSON data. The URL looks something like this
http://yourbox.com/mailServer/mailbox.nsf/Calendar?ReadViewEntries&outputformat=JSON
This request returns calendar entries for a given date range, more details can be found on this cheat sheet. Unfortunately we quickly realized that ReadViewEntries is not really designed for retrieving calendar entries formatted the way we needed. I'm not sure about the real purpose of this form, but I had to reverse engineer the results by creating a test sampling of all the different types of calendar entries (anniversary/meeting/reminder/repeated entries....) and then looking at the result set. Below is the javascript that I created to parse out the data feed
function populateCalendarData(viewentries) {

 var jqueryData = [];

 for ( var x = 0; x < viewentries.viewentry.length; x++) {
     var entry = {};
        entry.type = "meeting";

  var cday = null;
        if (viewentries.viewentry[x].entrydata[0].datetime != undefined){
            cday = viewentries.viewentry[x].entrydata[0].datetime[0];
        }
        else {
            // repeating item shows up with datetimelist
            cday = viewentries.viewentry[x].entrydata[0].datetimelist.datetime[0][0];
        }

  var sd = cday;

  // all day events don't have start dates
        if (viewentries.viewentry[x].entrydata[2].datetime != undefined){
            sd = viewentries.viewentry[x].entrydata[2].datetime[0];
        }
        else {
            entry.type = "all-day";
        }

        var ed = sd;

  if (viewentries.viewentry[x].entrydata[4].datetime != undefined){
      ed = viewentries.viewentry[x].entrydata[4].datetime[0];
  }
  else {
         // appointments don't have end dates
            entry.type = "appointment";
  }

  var startDate = getDate(sd);
  var endDate = getDate(ed);
  var moderator = "";
  var subject = "";
  var location = "";
  
  if (viewentries.viewentry[x].entrydata[5].textlist == undefined){
       // not a meeting type entry. This could be reminder or appointment
      subject = viewentries.viewentry[x].entrydata[5].text[0];
  }
  else{
      // check if a location was provided
      if (viewentries.viewentry[x].entrydata[5].textlist.text.length > 2){
          subject = viewentries.viewentry[x].entrydata[5].textlist.text[0][0];
          location = viewentries.viewentry[x].entrydata[5].textlist.text[1][0];
          moderator = viewentries.viewentry[x].entrydata[5].textlist.text[2][0];
      }
      else {
          subject = viewentries.viewentry[x].entrydata[5].textlist.text[0][0];
          moderator = viewentries.viewentry[x].entrydata[5].textlist.text[1][0];
      }
  }

  // create jquery calendar entry

  entry.date = startDate.getTime().toString();
  entry.title = subject;
  entry.description = "no description available at this time";
  entry.url = "no url";
  entry.end = endDate.getTime().toString();
  entry.location = location;
  
  jqueryData.push(entry);
 }
 
 return jqueryData;
    
}
The result is neatly populated into an array of javascript objects with the following structure
{"type":"meeting","date":"1343138400000","title":"Project A meeting","description":"no description available at this time","url":"no url","end":"1343142000000","location":"Huddle room 5"}
This data construct was then fed into a jquery widget to produce this interface


The result looks pretty good - thanks to Rick Taylor for helping me out with the lotus domino stuff.