Latest Updates

Products & Applications

Showtime
My Blackberry Enterprise Server Push Utility for the Lotus Notes Client, allows you to create Jobs for individual Channel, Message, and Browser Content Pushes, as well as allows you to delete Pushed Channel Icons from defined recipient devices.

Time Tracker
The idea is simple. At the start of your day - upon completion of your first task - create an entry highlighting what you did and whether you feel it was an efficient or inefficient use of your time. Based on several requests, you can also select the priority, apply categories, or even align your time against a project.

For Lotus Notes Client v8.0 and above, you can use the Time Tracker Widget to make this process even easier!

Zephyr
My Configuration-based Rich Text Mail Merge and Emailing Utility, Zephyr allows you to create rich, data-driven emails to support automated workflow - all via Microsoft Word Mail Merge-like architecture. Dear <firstname> allows you to personalize each email message not only to the individual recipient, but also to the individual application workflow event!

xCopy
xCopy is a simple configurable xCopy client for the Lotus Notes client. By creating and defining xCopy Profiles, you can batch process your file backup or remote upload jobs. With the addition of the xCopy sidebar widget, you can easily kick-off these jobs, and modify both the xCopy Profiles and xCopy itself.

Community & Resources

Lotus Technical Information & Education Community

The Lotus Technical Information & Education community is comprised of IBM, business partner, and customer subject matter experts who use product wikis, published articles, white papers, community blogs and the latest in social media to build and share high quality technical content.

OpenNTF.org - Open Source Community for Lotus Notes Domino

OpenNTF is devoted to enabling groups of individuals all over the world to collaborate on IBM Lotus Notes/Domino applications and release them as open source.

developerWorks Lotus : Wikis

Share your deployment experiences and best practices in our wikis and help IBM to create scenarios for successful deployments. Contribute to the community by collaborating on shared content and leverage the shared knowledge from that community.

Welcome to dominoGuru.com!

Focused on being the go-to resource for the IBM Lotus Notes Domino developer, dominoGuru.com delivers introductory-level best practices and advanced development deep dives for the IT professional, book and gadget reviews, and technical weblog, and more!

Domino URL Schemas for Domino CRUD API READ States

06/04/2009 12:59:41 PM by Chris Toohey

I posted a question yesterday across the various social networks (Facebook, MySpace, Twitter, LinkedIn, BrightKite, etc.) asking the following:

Do you prefer db/view/doc or db/doc?open&UNID=X architecture for the front-end of the Domino CRUD API & web development?


... and I got some amazing feedback. Before I go into the feedback on the idea - which I'll admit 140 characters didn't quite do justice - I'll elaborate.

The Thinker Every Domino Web Application Developer has used the db/view/notesdocument URL Schema for accessing a NotesDocument in a Domino-based NotesDatabase. That's the standard usage scenario. It's what we have all been taught. It's how Domino RAD drives us to develop.

But I'm curious... is there a better way? Specifically, does the db/Page_or_Form?open&UNID=X URL Schema, when combined with @URLQueryString and @GetDocField, lend to a better NotesDocument and NotesData access scenario?

No, I haven't done benchmark testing yet on this, but avoiding a View Design Element that does nothing at times but add bloat to a NotesDatabase - to me - is just one of the many potential benefits to this approach.

Now, a few things that people brought up and that I think definitely should be mentioned:

  1. This can impact/break URL Walking
    Simply put, you can't delete the NotesDocument and expect to see the View.

  2. Most Domino Web Application Usage Experiences warrant Views
    ... so why not just use the View.

  3. This can impact URL Permalinking
    Basing the URL up a NotesDocument UNID is easy, but it breaks any permalinking functionality, which can cause problems for bookmarking content or Search Engine Optimization.

Now, I have an address for each of these items:

  1. This really depends on the expected usage experience. Do I want to return - potentially - a listing of all content if I navigate away from a specific content entry (NotesDocument)? Depending on the application, I might not want to. As for this "breaking", you can handle a missing UNID and where to redirect in that event in the design architecture.

  2. Again, depends on what you need the application to do. For an application like Email, this meta-viewing of entries makes sense. For an application like a requisition, helpdesk, or jobs database, I don't think you'd want to return the customer back to a listing of all entries.

    As far as rendering a NotesDocumentCollection in the UI, some could argue that unless there is a continuous update on View Entry contents, using a View can be unnecessary overhead. For example, if I were to render an entire "View Index" into a single NotesDocument as JSON and return those contents, I'm getting the exact functionality I would require without that overhead... but I'm getting ahead of myself here.

  3. This... this I'm working on.

For that last one, consider a technique that I've mentioned in the past (Nathan T. Freeman's Andrew's Allusion (or Creating Primary Keys in NSFs)), where with db/Page_or_Form?open&UNID=X, X is something like index.html. The content - when created - is assigned a plain-text UNID by the customer (ie., index.html). Post submission, the NotesDocument UNID is set to @ReplaceSubString(@Password(UNID); "(":")":":";""). This hash - for those curious - would result in a completely valid UNID (3A8A735F029991B9844D181AE297DDDE).

But I'm again getting ahead of myself.

Back to the original question: which method works best? I personally think that - once you have a handle on the UNID, @GetDocUNID would return a NotesDocument much faster than lookup via NotesView. Why? Well, consider this:

When you access a NotesDocument by it's UNID from the Web Browser Client via the db/view/UNID URL schema, the view simply becomes a placeholder, and is quite frankly ignored. Next time you see a Domino Web Application that uses this UNID URL schema, replace the view with either a 0 (zero) or thisviewdoesnotexist. Both will result in the NotesDocument being rendered. The View however is considered for things like Form Formula etc., as long as you don't use a zero or a non-existing element name.

I dunno, that sounds more dangerous to me than breaking the URL Walking and could potentially be another feather in the cap for the db/Page_or_Form?open&UNID=X URL Schema.

But like I said, I've yet to do any real benchmarking on this to see which is indeed faster or weigh the true benefits of one approach over another. For that, I'll open up the comments. Weigh in and let us know what you're thinking. If we get enough interest, I'll update the Understanding the Domino CRUD API Example Database to use both techniques.

Understanding the Domino CRUD API: non-Domino Form CRUD Basics - Part 1

04/17/2009 02:30:17 PM by Chris Toohey

In previous entries, we've discussed how to use the Domino CRUD API in the following ways:

Now I'll show how you can create your own non-Domino Form Design Element-based XHTML Form Elements that use the Domino CRUD API for NotesDatabase Data Management. In this, the Part 1 in a smaller part of the overall Understanding the Domino CRUD API series, I'll show you how you can create a simple Domino Page Design Element that can be used to Create and Update NotesDocument data.

NOTE: I'm opening up the Domino CRUD API Example NotesDatabase to Anonymous access having Editor w/ Delete. I'll keep it that way as long as we all play nicely. Someone playing script-kiddie and putting some cross-browser attack or posting inappropriate content will ruin this for everyone (as well as give me the burded of shutting things down). Should go without say, but...

First thing first, we'll talk about the ingredients for this build:

  1. Page Design Element: content.html

    This is going to be - on purpose - a very basic build. I could get really creative with this XHTML (Content-Type: text/html) webpage, but that might distract from the overall example.

  2. Input/Textarea Element name Attribute match

    This one is simple yet very powerful. If you're NotesItem is named title, your XHTML Form Element's Input Element name for title needs to be title!

  3. NotesDocumentUNID passthru Logic

    Just like with the Smart Landing Page - which is a basic example of an advanced Domino Design Element-driven Domino CRUD Read - we'll be using a NotesDocumentUNID to drive the Update XHTML page Form population.

  4. ?CreateDocument Domino URL Command

    We'll use this to facilitate the Create Domino CRUD verb.

  5. ?SaveDocument Domino URL Command

    We'll use this to facilitate the Update Domino CRUD verb.

First, we'll create our simple content.html Page Design Element:

Domino CRUD API: content.html Page Design Element

Simple, and will get the job done. Two major things to point out here: the Form Element's processing agent and the value attribute for each Input Element.

The Form Element's processing agent - as shown - uses a Computed Text instance to populate it's action:

~UNID := @UrlQueryString("UNID");
@If(~UNID = ""; "content?CreateDocument"; "0/" + ~UNID + "?SaveDocument")

This simply checks the URL Query String for a parameter named UNID. If found, I know I'm going to Update a NotesDocument. Otherwise I'm going to Create a new NotesDocument.

The Computed Text set as the values of our Input and Textarea Elements does someting similar (for the Title Input Element):

~UNID := @UrlQueryString("UNID");
@If(~UNID = ""; ""; @GetDocField(~UNID; "title"))

When we click submit - via the simple Input Element typed "submit" - we're going to rely on our XHTML Form Element's processing agent to handle the rest.

For new NotesDocuments, we see that it's pointing to the Content Domino Form Design Element and will issue the ?CreateDocument Domino URL Command. This will result on a NotesDocument being creating in the target NotesDatabase and leverage the $$Return to redirect our Web Browser Client session post-submission to our Smart Landing Page.

For existing NotesDocuments, we'll use the following syntax:

/0/NotesDocumentUNID?SaveDocument

Same thing here - the ?SaveDocument does the real work here via the Domino CRUD engine and performs an Update with the submitted XHTML Form Element contents.

NOTE: Notice the /0/ placeholder for the View Design Element in the XHTML Form Element's processing agent. If you replaced this with /pages/, it would honor the pages View Design Element's Form Formula, thus first rendering/submitting the NotesDocument via the display Form Design Element and - since there is no $$Return - would simply return the Form Processed message to the Web Browser Client.

The last part of this is to direct people to an edit link for each NotesDocument in your Pages View Design Element:

~t := @If(title = ""; "Untitled Content"; title);
~pl := "<a href=\"pages/" + permalink + "\">Use Permalink</a>";
~unidl := "<a href=\"pages/" + @Text(@DocumentUniqueID) + "\">Use UNID</a>";
~htmledit := "<a href=\"content.html?open&UNID=" + @Text(@DocumentUniqueID) + "\">Edit</a>";

"<tr><td class=\"col0\">" + ~t + "</td><td class=\"col1\">" + ~pl + "</td><td class=\"col2\">" + ~unidl + "</td><td class=\"col3\">" + ~htmledit + "</td></tr>"

The ~htmledit gives us the UNID URL Query String Parameter required for our Update, and the rest is handled by the Domino CRUD engine!

Wanna play? I've enabled Anonymous access to the Understanding the Domino CRUD API Example NotesDatabase. You should have Editor access with the Delete role enabled.

In our next entry - Understanding the Domino CRUD API: non-Domino Form CRUD Basics - Part 2 - we'll discuss how you can handle Read and Delete CRUD verbs - completing the Basics subsection of the non-Domino approach. After that, we'll get into some pretty advanced stuff!

Hopefully you'll start to see - especially after this - exactly where we can go from here. My XHTML Form was created in Aptana and outside of it's using Computed Text to populate the XHTML Form Element really wouldn't need to reside in a NotesDatabase at all. See... getting a firm handle on this stuff is the ground work for extending your Domino Web Application Development to new heights: integrating with other technology investments and SaaS/cloud services!

YouTube: Lotus Notes/Domino Web Development - Permalinks vs. NotesDocument UNIDs

04/04/2009 07:43:01 PM by Chris Toohey

Just a quick video showing you the potential issues with NotesDocument UNID-based URLs and how you can easily create your own "permalink" functionality in your Lotus Notes/Domino Web Applications!

(Check out the HD version)

Feedback on the last video was awesome, so feel free to drop me a comment here or on the YouTube page with thoughts, suggestions, or requests!

Public Build: Event Calendar - Misc. Updates

02/25/2009 05:22:44 PM by Chris Toohey

Event Calendar It's been a while since I've updated the Event Calendar Public Build project... more due to me being extremely busy than not working on the build. Since my last video, I've put some considerable work into the application. It's still Notes Client-only at the moment... and for good reason: we're far from done! See, one of my goals with this particular project was to show you how to take a Notes-based application and ready it for the web... and I wanted to build a pretty feature-rich and configurable (which is key!) before I jump into the web-build of this particular project.

So what have I been doing?

Well, for starters I've added a facility that will allow you to assign Groups (from an Admin-defined list) as an additional level of categorization... and read-access restrictions - all configurable at the UI level to the Event Author via a Restrict to Group? flag.

Event Calendar Entry

You'll also notice the Reservations Embedded View - pretty self-explanatory there: user's will be able to click-and-subscribe to events!

I've also done some considerable work with the Preferences engine: specifically adding more keywords (which was simple enough, and a given really), and the Admin-defined Color-coding... with a twist. See, I'm allowing you to define the Color Profile Formula in a Formula field - using placeholders for the font and background colors - and I then apply the Runtime Formula (which is a Computed and evaluated version of the Admin-defined Formula).

Event Calendar Preferences

If that wasn't enough, I've also allowed you to define the default action of the New Event button via the Preferences document's Default Action. Selecting Event Form will wire the button to launch the simple single-entry Entry|entry Form Design Element, while selecting Event Wizard will wire the same button to instead envoke the New Events Wizard. This wizard, which is lifted from my Lotus Notes Client Wizard components example download, will allow the user to create multi-day event entries in the Event Calendar as well as drive the creation of the standard single-day event.

Event Calendar New Events Wizard

All of this resulting in a very simple, but very functional Lotus Notes Client application that can handle basic Event and Reservation management!

Event Calendar

The next step, prior to the web build, is the C&S (Calendaring and Scheduling) integration. The intended goal is simple: click on an event, and a new Meeting invitation is sent from a simple standard Mail Database Application, containing all of the Event information, and putting those individuals with reservations into the invite list - where we'll leverage the built-in C&S functionality in the standard Mail Application Template... which is something I certainly don't want to hack around in or attempt to re-write!

I'm on the fence as to whether to public this particular design release yet, which is admittedly incomplete. See, I don't want someone to take this application as a finished product and start using it... because the finished product will kick this one in the nards!

... but if I get enough "gimme-gimme-gimme!" feedback, I'll post what I have so far for download and dissection!

Quicktip: Environment Variables, Database Scripts, NotesDocument UniversalIDs, and non-View NotesDocument Indexing

09/15/2008 01:36:11 PM by Chris Toohey

The majority of the Lotus Notes Applications I've written lately - from customer applications to the freeware/tip jar-ware that I've been publishing to this site - all feature a Preferences NotesDocument, which contains... well, preferences for the given application. The Preferences Document is a simple NotesDocument containing Keywords and other data items that help the given Notes Application do whatever it's supposed to do.

Now, before we even hear from anyone asking "Why aren't you using Profile Documents?" - issues like HTTP Caching and their tendency to corrupt keep them off my radar. And, in the spirit of being truthful here: I just prefer to handle a NotesDocument as a NotesDocument, not some voodoo mystery back-end thing that's really just a special type of - you guessed it - NotesDocument.

There are, however, some issues with the Preferences NotesDocument approach. The biggest being it's dependancy on a Domino Views for NotesDocument lookups. For example, I've added a Domino View named (bykey)|bykey into pretty much all of the freeware/tip jar-ware applications, but it's there for the sole purpose of providing me with a lookup-point to get a handle on the Preferences Document. So... what's wrong with that?!

How many of you have a 2GB+ Domino Application lying around? Okay... do this for me. Create a new view containing any number of columns that you want, that shows all NotesDocuments in the database... and tell me how long that takes to open.

Now, run this simple script against your 2GB+ Domino Application:

Function getDocs() As NotesDocumentCollection
 
 Dim s As New NotesSession
 Dim db As NotesDatabase
 Dim col As NotesDocumentCollection
 
 Set db = s.GetDatabase("", "db.nsf")
 Set col = db.AllDocuments
 
 Msgbox "Got " & Cstr(col.Count) & " NotesDocuments!"
 
End Function

Obviously change your db declaration to get a handle on your 2GB+ Domino Application... but you get the idea here. What slows down your Domino Applications are NOT the number of or size of your NotesDocuments... it's their rendering in Domino Views. Sure - they cache... but ViewIndex caching makes the Domino Application even larger than it really needs to be, and what happens when something happens to the View or the ViewIndex itself? Yeah, prepare to stare at your Lotus Notes Client for a while...

I don't want to add to that for a Preferences Document. How can I justify that bloat to just allow someone to assign keywords and other Domino Application... stuff to make it work. Yeah, I can't do that in good conscience. And I have been doing just that...

So, from now on, my freeware/tip jar-ware Domino Applications are going to use the following approach, recently popularized by Andrew and Nathan. Specifically, I'm going to logically-define the "Preferences" NotesDocument UniversalID!

Doing this is pretty simple actually... I just need to define a schema and stick with it. So, for example, let's say that this will be for a global Preferences Document. We'll create our @Password HASH logic to create a UNID for our Preferences Document:

@ReplaceSubString(@Text(@Password("preferences")); "(":")";"")

So... my real problem with this approach is that I don't like having to bail out of whatever language I'm running at the given moment to get a handle on the Preferences Document UNID. I want to keep the Evaluates to a minimum here, so I'll look to the Lotus Notes Client cookie-like behavior of the Environment Variables to provide me with access-from-anything cache of the UNID for my Preferences Document.

To do this, I've simply added the following to the Initialize Event in my Applications Database Script:

Sub Initialize
 
 Dim s As New NotesSession
 Dim hash As String
 
 hash = s.GetEnvironmentString(|HASH_preferences|)
 If Len(hash) = 0 Then
  hash = Join(Evaluate(|@ReplaceSubString(@Text(@Password("preferences")); "(":")";"")|), "")
  Call s.SetEnvironmentVar(|HASH_preferences|, hash)
 End If
 
End Sub

Pretty basic stuff here, as this creates the following line in the Notes.ini:

$HASH_preferences=A68506D12B73EC4E4A77FB934144FD97

So, since we've taken the steps to set the UNID of our Preferences Document to be the evaluated @Password hash of "preferences", we can now use the Preference Document via View Index-free lookups in (for example) just one of the following ways:

  1. @GetDocField(@Environment("HASH_preferences"); "Categories");
  2. Set doc = db.GetDocumentByUNID(s.GetEnvironmentString("HASH_preferences"))

Now, while I will place this into the freeware/tip jar-ware Domino Applications as just Preference Document lookups... keep in mind that you can easily expand this to evaluate more user-specific lookups by adding such considerations into your Domino Applications. For example, you can have user-specific "Profile" Documents by setting the UNID to something like @Password("profile_" + @Name([CN]; @UserName)), and using either the Environment Variable approach or an inline HASH to get those NotesDocuments View/Index-free!