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!

Aritcle Preview: Advanced NotesDocument Workflow Processing Engine

08/04/2009 12:32:53 PM by Chris Toohey

I believe that the major hurdle for any Lotus Notes Domino developer adopting an MVC-like software architecture is the perception that more advanced application workflows and seemingly ever-changing applied business logic would require dependences on UI elements and objects. This is where you see things like processing a NotesDocumentCollection with doc.ComputeWithForm or using cascaded Computed Fields to maintain the business logic in the NotesDocument.

Now, I fully understand that for an existing NotesDatabase application, you may need to use this approach to update and maintain NotesDocument workflow. I submit however that if you're still using this approach for new projects, then you are greatly limiting the life of your applications. Not to mention that dependences on UI Design Elements for applied business logic for NotesDocuments often limit the UI functionality on the Lotus Notes Client as well as can require re-writes for multi-Client access.

But why do we still rely on "older" NotesDatabase designs and development methodologies? Pretty simple actually: we're relying on reusing existing design components to deliver our applications, we have to adhere to internal development standards defined by a "corporate communications" team, and we simply don't have time to re-invent the wheel.

So, instead of simply preaching to you about how you need to change your wicked ways, I thought that I would instead design an Advanced NotesDocument Workflow Processing Engine and include that in a NotesTemplate framework.

So that's the idea. I'll be putting together the workflow engine that I use for most of my multi-client NotesDatabase applications as well as a few other slick and functional components (such as my Excel Export and simple integration with Zephyr).

My question: is there anything else that you would like to see in this framework?

Quick Hack: Controlling the Render Form of a NotesDocument in the Lotus Notes Client

07/29/2009 12:03:36 PM by Chris Toohey

As I am ever discussing the need to separate the NotesDocument from Form Design Element binding - in other words, separating UI from the DataStore - I thought that I'd pass you a quick tip.

First, the scenario:

I have a Lotus Notes Client-based application that contains a simple document approval engine. Each approval document is a response NotesDocument to the parent NotesDocument which contains the overall status and miscellaneous document data. There is a business logic to which NotesDocument and Form Design Element is displayed based on who you are in the system or the current state of the NotesDocument.

For example, while the NotesView shows me the given document, I might be launching my individual review response NotesDocument, or a reader response NotesDocument, or the actual document.

Use Form Formula? Well, I do... but not how you might suspect. See, remember that I might need to launch the document or one of it's specific responses (my review NotesDocument).

Simply put, I need to be able to control what's opened regardless of how it's opened.

The tip:

document is not a UI component per se, but rather a "stub" Design Element that relies on the application logic to render a given NotesDocument via it's PostOpen event.

Example A Sub Postopen(Source As Notesuidocument)

  Dim s As New NotesSession
  Dim w As New NotesUIWorkspace
  Dim rcol As NotesDocumentCollection
  Dim rdoc As NotesDocument

  Set db = s.CurrentDatabase

  Set rdoc = Nothing
  Set rcol = source.Document.Responses
  If (rcol.Count > 0) Then
   Call rcol.FTSearch(|[reviewer] = "| & s.CommonUserName & |"|, 0)
   Set rdoc = rcol.GetFirstDocument
   Call w.EditDocument(True, rdoc)
  End If

 Call source.Close(True)

End Sub

Pretty basic right? Well, here's the trick that will allow you to open that - in the above case - review NotesDocument with any Form you wish.

Example: Sub Postopen(Source As Notesuidocument)

  Dim s As New NotesSession
  Dim w As New NotesUIWorkspace
  Dim rcol As NotesDocumentCollection
  Dim rdoc As NotesDocument

  Set db = s.CurrentDatabase

  Set rdoc = Nothing
  Set rcol = source.Document.Responses
  If (rcol.Count > 0) Then
   Call rcol.FTSearch(|[reviewer] = "| & s.CommonUserName & |"|, 0)
   Set rdoc = rcol.GetFirstDocument
   Call rdoc.replaceItemValue("form", "reader")
   Call w.EditDocument(True, rdoc)
  End If

 Call source.Close(True)

End Sub

Pretty simple right?

This allows me to open rdoc with the reader Form Design Element.

The only caveat to this approach would be if I needed to actually save content back to rdoc but wanted to ensure that the form NotesItem wasn't overwritten with my reader value.

... which is something I'll save for tomorrow's post.

Personal Address Book + 1 Domino Agent = Read-Only WAP UI for Mobile Devices

07/29/2009 12:42:41 AM by Chris Toohey

I was contacted by Keith the other day asking me for a downloadable example from my WML-enabling a Personal Address Book - It's in the cards.... article.

Instead of going the multi-Design Element route (as the original article called for a View Design Element and a Form Design Element), I thought that I would take a second to simplify the approach and instead deliver the same functionality with a single Agent Design Element.

The Agent - named mobile - can be added to any Lotus Notes Personal Address Book Template-based NotesDatabase, have that NotesDatabase setup with an appropriately configured Access Control List, put in on a Domino HTTP-enabled Server, and simply point your mobile devices to NotesDatabase/mobile.

The Agent itself is very simple - by design - and can allow for customization via tweaking to meet the needs of the particular customer:

Sub Initialize

 Dim s As New NotesSession
 Dim db As NotesDatabase
 Dim col As NotesDocumentCollection
 Dim doc As NotesDocument
 Dim markup_options As String
 Dim markup_cards As String
 
 Set db = s.CurrentDatabase
 Set col = db.AllDocuments
 Call col.FTSearch(|[form] = "Person"|, 0)
 
 Print |Content-type: text/vnd.wap.wml|
 
 If (col.Count > 0) Then
  
  Set doc = col.GetFirstDocument
  
  Do Until (doc Is Nothing)
   markup_options = markup_options + |<option value="| + Join(doc.GetItemValue("fullname"), "") + |"><onevent type="onpick"><go href="#card_| + Cstr(doc.UniversalID) + |" /></onevent>| + Join(doc.GetItemValue("fullname"), "") + |</option>|
   markup_cards = markup_cards + |<card id="card_| + Cstr(doc.UniversalID) + |" title="Contact Info"><p><b>| + Join(doc.GetItemValue("fullname"), "") + |</b><br />| + Join(doc.GetItemValue("mailaddress"), "") + |<br />| + Join(doc.GetItemValue("officephonenumber"), "") + |</p></card>|
     Set doc = col.GetNextDocument(doc)
  Loop
  
  Print |<?xml version="1.0"?><!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">|
  Print |<wml><card id="card1" title="| + Cstr(db.Title) + |"><p><select name="name">| + markup_options + |</select></p></card>| + markup_cards + |</wml>|
  
 Else
  
  Print |<?xml version="1.0"?><!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">|
  Print |<wml><card id="card1" title="| + Cstr(db.Title) + |"><p><b>Unable to load Contacts</b></p><p>There appears to be an issue with this address book. Please contact support.</p></card></wml>|
  
 End If
 
End Sub

Pretty simple stuff here, which renders the following WML markup:

<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>

<card id="card1" title="Example WAP NAB">
<p>
<option value="Chris Toohey">
<onevent type="onpick">
<go href="#card_3CEDB7D07E5327D98525760200117ECA" />
</onevent>Chris Toohey</option>
</select>
</p>
</card>

<card id="card_3CEDB7D07E5327D98525760200117ECA" title="Contact Info">
<p>
<b>Chris Toohey</b><br />
ctoohey@dominoguru.com<br />
610.417.1700</p>
</card>

</wml>

So feel free to take the above LotusScript-based Agent Design Element code and use it to add a mobile device WAP UI to any Group Address Books and such that you might have lying around. Also, feel free to point your mobile device WAP-friendly browser to check-out the online demo that I've setup.

(Note: I wrote this in an Agent and leveraged things like FTSearch from within the mobile Agent. I do this so you can easily pinpoint what's going on and apply any required modifications.)

Now, for a killer solution: combine this with Showtime and deliver via Channel Push - for example - as many icon-laden WAP-enabled Personal Address Books that your customer teams require.

So, to review:

To implement this solution, you can simply create a new Agent Design Element named mobile, past in my code, and point any WAP-friendly mobile device to /mobile.

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!