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!

HTTP Request Consumer Domino Agents - Build, Demo, and Download

09/21/2009 12:01:19 AM by Chris Toohey

I was recently asked by two people how they could get a Domino Agent Design Element to consume an HTTP request. Well, I wasn't asked this exactly...

One Lotus Notes/Domino developer asked me how they could modify a NotesDocument via a web browser client when said NotesDocument is not in edit mode in the UI. He is updating several fields in the NotesDocument - via an Approve button - and ultimately has to redirect the user to a different URL post approval.

The other request was asking for a simple search form in a Domino Web Application... more or less. The original request was to submit the NotesUIDocument (if you will...) via @FileSave;@FileCloseWindow, capture the submitted request, not save a new NotesDocument to the NotesDatabase, run an Agent Design Element via the WebQuerySave Event on the Form Design Element, and do the voodoo that he-do from the Agent Design Element.

Over the past several years, I've come up with a different approach: Submitting an HTTP request to a Domino Agent Design Element... and doing whatever I need to do from there.

Now - before I get into this - some of you may have noticed that I keep referring to each Design Element in it's full name, ie., Agent Design Element. I'm doing this - and will continue to do so - to alleviate confusion. See... I'll be talking about an HTML Form Element interacting with a Domino Form Design Element via the HTML Form Element's Processing Agent, which is targeted at a Domino Agent Design Element. In other words, the Form will interact with a Form via it's Processing Agent, which points us to our Agent. So yeah, it's not like I'm doing this for the word count!

Build Synopsis

For our build example, I'm going to create a simple search facility via an HTML Form Element and a Domino Agent Design Element. To complicate my life make sure we effectively cover all HTTP POST and HTTP GET Method requests, the example NotesDatabase build will feature a unique HTML Form Element each running an HTTP POST, and HTTP GET, and even an AJAX-based interaction with our Domino Agent Design Element.

I'll break this build down into three stages. In the first stage, we'll create a simple HTML Form Element using a Domino Page Design Element that will submit our request to a Domino Agent Design Element. We'll build this Domino Agent Design Element in phase two, and complete our build... well, putting in some Domino-specific hacks to get everything to work via GET. That last part will make sense when this article's finished in that you'll know what I'm talking about - not that you won't see how frustrating it can be!

Phase One: HTML Search Forms

We'll start off by creating a Page Design Element named index.html, setting the Content Type to text/html, setting the NotesDatabase properties to use our index.html as the Default Launch Object (not really needed per se, but it makes everyone's life easier...), and after we've set the HTML Head attributes and the beginning of the Body Element, we can add the following markup:

<h4>HTTP POST via simple HTML Form</h4>
<form id="example_httppost" name="example_httppost" action="search.agent" method="POST">
<label for="example_httppost_query">Query</label><input type="text" id="example_httppost_query" name="query" value="" /><input type="submit" value="Submit Trigger" />
</form>

We'll add 2 additional forms to the index.html Page Design Element - one for HTTP GET via simple HTML Form and another for HTTP GET via AJAX - but as each require a minor tweak that we'll cover in stage three of the build. We'll stick with this one as it gets the overall concept across: we're building a simple HTML Form Element that will submit a request (via POST) against our search.agent Agent Design Element.

Take note of the query HTML Input Element (or Field). This field will contain our search criteria, and will be the sole piece of data consumed when the HTTP POST request is submitted to the search.agent Agent Design Element.

Phase Two: Creating the search.agent Agent Design Element

In this phase, I'll create a simple Domino Agent Design Element - written in LotusScript - that will consume the submitted HTTP requests. I've simplified this Agent Design Element, which consists three (3) Functions and the Initialize:

getvalue

unescape

ReplaceSubstring

Initialize

Pretty basic stuff. Each function really just supports the simple act of taking the Domino Agent's Session - evaluated to a NotesDocument via DocumentContext - decides whether it's a POST or GET Method-submitted HTTP Request, and returns a value accordingly. In this case, it's grabbing the query parameter and using it's correlating submitted value for an FTSearch against a NotesDatabase. For our example build, I'm pointing it to the Domino Server Directory (names.nsf), thus using this more as a NotesData proxy vs. having the FTSearch run against the HTTP Request target NotesDatabase.

I mention that so you can immediately see the extended potential of this approach: your target NotesDatabase doesn't need to be HTTP-accessible in order to return NotesData to a Web Browser or Mobile Device Browser client!

The query thus returns a NotesDocumentCollection, which I then iterate through to build my markup String - which I will Print directly back to the Browser Client.

... and that's pretty much it. There is one additional check... but that's for AJAX vs. POST/GET Method HTTP Requests. Since the UX requires a different Content Type and, well, a different construct of the markup Printed.

Phase Three: AJAX considerations, Domino URL Command hacks, and final tweaks

For the AJAX-based HTTP Request, I add a simple QueryString Parameter and value (AJAX=1). It's usage is fairly evident in the search.agent Initialize LotusScript above - if set, return a Plain Text series of HTML SPAN Elements. Otherwise, it's full HTML Print.

Another gotcha: Domino URL Commands. This was an interesting one. When submitting an HTTP Request via the POST Method, it's simple: QueryString parameters are ignored, and you can point directly to the Domino Agent Design Element name without the need for additional parameters (ie., search.agent). With the GET Method, that's not the case. The entire contents of the submitted HTTP Request are added to the QueryString - both parameter and value. This wouldn't be a bad thing if Domino didn't require a valid Domino URL Command to preceed any of these parameter/value pairs.

For example, if I submit via GET Method to the search.agent Agent Design Element, I'll get this: search.agent?query=blah. And this will fail with a Domino-generated error message telling you - in all it's H2 glory - that there's no such Domino URL Command as query. open is a valid cross-Design Element Domino URL Command, so I decided to go with that... but in order to front-load the parameter, I needed to add it to the HTML Form Element.

<input type="hidden" name="open" value="" />

Silly, but it gets the job done! The result is an ugly but fully functional Domino URL: search.agent?open=&query=blah.

This same consideration applies to the AJAX requests as they use the GET Method to communicate with the search.agent Agent Design Element, but for that we can simply prepend the AJAX=1 to the URL from within the AJAX function.

As for tweaks - this is LotusScript: make it do what you want it to do! Pretty basic functionality that just can't be achieved via the Formula that's supported over the Browser Clients. If you need this to update a given NotesDocument, you can either pass a UNID vs. the query, run a target-NotesDatabase.getDocumentByUNID(UNID)-lookup, and do to that NotesDocument what you will!

Online Demo, Example Download, and Closing Remarks

For those of you who prefer online demos: http://domino1.clearframe.net/httpconsumer.nsf/index.html. Note: I've changed the target NotesDatabase from the Server Domino Directory to the NotesDocument Auto-Save Example Domino Web Application. You have the ability to create/edit NotesDocuments in that online demo as well, so feel free to have at it!

You can also download the demo NotesDatabase by clicking thru to the online demo (see, making you chase it!).

Lastly, I created this article and demo to help Lotus Domino Web Application Developers extend their application capabilites and functionality. In corresponding with one of the developers who mentioned a need for this functionality, he stated that he would compensate me for any help I could provide. I'll tell you what I told him: I'm very thankful for the offer, but the best way to compensate me for something that you find useful on this site is via contribution/donation to the site. All monies donated to this site go directly back into the site. Now, while I'm lucky in that I don't have hosting fees to worry about, I do purchase software - such as the warez I use for podcasting/screencasting, editing, etc. And I'm also picking up additional gear as needed/desired, such as new headsets for said podcasts/screencasts, etc. Now, while I don't think I'll hit the numbers in the coffers to pick up some higher-end hardware (such as the Apple Touch and the entry-level development Mac rig that I've been flirting with picking up)... every little bit extra helps the P.O. go through my wife that much easier.

If you can't donate to the site, I'll take your feedback - which is even more valuable. Like what you're seeing here? Want to see something else? Let me know and I'll see what I can do!

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: NotesDocument Deletion Basics

04/19/2009 01:57:41 PM by Chris Toohey

Deleting NotesDocuments in a NotesDatabase via the ?DeleteDocument Domino URL Command is simple enough, but there are many things to consider - some of which I'll go over in this entry.

1. Click-Confirm-Delete

You're going to want to create a simple to use, simple to recognize NotesDocument deletion mechanism for your Web Browser Client UI. In the Understanding the Domino CRUD API Example NotesDatabase, I've setup a simple click-confirm-delete engine for submitting a Delete request to the Domino CRUD API (example pictured below).

Understanding the Domino CRUD API Example NotesDatabase - 'click-confirm-delete' Example UI

This UI-driven Click-Confirm-Delete facility will - when the delete icon is clicked - use a JavaScript confirm prompt to drive the cancellation or confirmation of the ?DeleteDocument GET-method call.

As Stephan Wissel commented, a direct ?DeleteDocument URL link from your UI could prove problematic and is really not recommended. As a slight work-around, I'm building the call to the Domino URL command via JavaScript.

First, an additional column to my pages rendered View Design Element:

<td class=\"col4\"><img title=\"Delete this NotesDocument\" onclick=\"notesdocument_delete('" + @Text(@DocumentUniqueID) + "');\" src=\"pk_icon_delete.gif\" alt=\"Delete this NotesDocument\" /></td>

Combining this with a very simple JavaScript function:

function notesdocument_delete(UNID) {
var q = confirm("Do you want to delete this NotesDocument?");
if (q) {
  window.location = "pages/" + UNID + "?DeleteDocument";
}
}

And we have the first part of our NotesDocument deletion facility.

2. Post-deletion behaviour -- what now?!

You'll note, in the above notesdocument_delete JavaScript function, I declare a valid View Design Element for the window.location to issue the ?DeleteDocument Domino URL Command.

The defining of a valid, existing, and Web Browser Client-accessible View Design Element is required for the ?DeleteDocument. Failure to define a View Design Element will result in the following error:

Invalid View Design Element for issued ?DeleteDocument Domino URL Command Error Message

A successful submission will look like this:

Standard confirmation of a NotesDocument deletion via the ?DeleteDocument Domino URL Command Message

Since we wanted to make this NotesDatabase a Domino Web Application, we know that this type of behaviour just won't do! We'll want to create a custom deletion confirmation message and - in this case - redirect them back to the NotesDatabase default launch element.

To do that, I've created a copy of the confirmation.html Page Design Element, stripped all of the NotesDocumentUNID lookups, and renamed it $$ReturnDocumentDeleted.

The $$ReturnDocumentDeleted, not unlike the $$Return, is a special-named element that provides functionality in the Domino RAD engine. Simply put, the $$ReturnDocumentDeleted-named Design Element is returned post-successful NotesDocument deletion.

For the Understanding the Domino CRUD API Example Application, I'm using a Page Design Element. Technically, you could name any Design Element $$ReturnDocumentDeleted and that Design Element would be returned post-successful NotesDocument deletion.

NOTE: I could have just as easily re-written the confirmation.html Page Design Element to accomodate this functionality (and added an alias of $$ReturnDocumentDeleted) instead... but that might throw off future users of the examples.

That's pretty much it for the basics of the ?DeleteDocument Domino URL Command. The next part of the ongoing Domino CRUD API series will discuss Read and the various ways that we can pull NotesDocument data from a Domino Web Browser-accessible NotesDatabase.

Stay tuned!

Domino + HTTP Request Headers

04/15/2009 11:53:01 AM by Chris Toohey

I've put together a simple Page Design Element - based on comments/feedback - that displays all values returned via an @GetHTTPHeader call for each HTTP Request Header Field listed by the W3C.

To do this, I created a simple grid (took about 5 minutes) to show the HTTP Request Header Field name and it's returned value.

Domino + HTTP Request Headers Example

Blanks should not be considered "unsupported", but rather not populated at this time. We, as Domino Web Application Developers, can set these HTTP Headers (either through @SetHTTPHeader Formula calls or via hand-generated markup). This gives us an amazing opportunity for some really slick and functional application development should we start leveraging things like MD5 hashes and ETags to help optimize rich Web Browser Client experiences.

The Domino + HTTP Request Headers Example Page Design Element sits in Anonymous-accessible NotesDatabase on my Domino server - in fact the same one that I've been using to create the "Understanding the Domino CRUD API" examples and videos - so you should be able to play around with that.

See how feedback rocks?! ;-)

Understanding the Domino CRUD API - $$Return Basics

04/14/2009 01:38:25 PM by Chris Toohey

Learn how you can return custom NotesDocument submission messages and redirect to specific URLs with the Domino Rapid Application Development (RAD)-friendly $$Return.

This screencast, running 3:55, just touches the surface on what you can do with a $$Return in the world of the Domino CRUD API.