Mon 7 Sep 2009
Some of my old blog posts are less practical tip than they are just thinking out loud. While most of these centered around Lotus Notes, as it was at one time my bread and butter, there are still concepts that I think are useful in other contexts, so a few of those articles will appear here, as this one does.
A number of years ago I wrote an article for e-Pro Magazine treating the topic of emulating a messaging queue with standard Domino technology. That first article was aimed at handling simultaneous data access from multiple users against individual documents. Recently I again used the concept of a messaging queue to handle a tricky problem, this time on the Notes Client UI.
Let's just cover what a messaging queue is and is supposed to do, briefly. A messaging queue is just a place where individual instructions are dropped by one or more processes to be picked up, in order received, and executed by another. When you consider the steps involved in queue management, you may have as many processes as you like adding messages to the queue (analogous to an array.push) but must have only one process removing messages (array.pop). This is also known as a mutex.
Despite the appearance of multi-threading running more than one program at once, it is usually just thread management through a mutex to process one instruction set at a time, albeit rather quickly. This last bit is somewhat central to the concept of a messaging queue, but not critical to the implementation I discuss below - not entirely. You see, for a messaging queue to work properly, a message has to be cleared once it is processed. If you leave the message on the queue, it can be reprocessed ad-infinitum causing all manner of mayhem. I mention this mostly because I have encountered some attempts at using this architecture that used a latent or come-along process to clear messages and that is an approach fraught with problems.
Happily, our example today is simplistic by comparison. To make things simple, I'm using a single instruction queue. Only one message can be in the queue at a time. If another message comes in before the instruction in the queue is processed, the last instruction in is processed and the previous instruction is discarded as it is overwritten with the new. This is useful for a UI, as you will see.
I have an application with a series of framesets. In one frame is an embedded IE Browser object occupying the entire frame. This means controls to interact with it can not be on the same form and in fact live in a separate form in a separate frame positioned much like a browser control bar above the embedded browser's frame. If I want the user to be able to "click" back or forward or reload, I have to have a way to tell the OLE object to execute these internal commands. However, scripting frame to frame via LS is not supported in a straight forward way.
To achieve this frame to frame interaction, I took my single instruction queue and manifested it as a variable in the notes.ini file. This is a safe, quick, local and global access point for a short string. In my browser form, I have a timer running once a second to examine the "queue" for a new message. If the variable has a command I deemed to mean "do nothing", the timer's processing function exits. If it finds a command though, placed there by clicking on the control bar, it interprets the instruction and calls the desired function on the locally scoped OLE Browser.
The browser executes this in a serial fashion, then returns control to the calling function, which as a final step, returns the queue to the "do nothing" state.
Pros and Cons
I like this approach from the perspective that it allows the user to click "back" and then quickly decide they meant "reload" and the browser will reload instead of go back because it only takes the last command. It also gets around less elegant approaches like using "set focus" and "send key" command, or even windows messaging queue manipulation (which I considered and consequentially drew inspiration from).
I don't like this approach because the LS timer can't get any quicker that 1 second - which means the user has a maximum command lag of 1 second depending on when they click the button and when the timer next calls it's function. But, it has made for a much more reliable connection than other methods explored.
Dispatching messages directly to the windows messaging queue was another attractive option as you get thread priority response time (what ever priority the browser is given) but there is a lot of work to do to get the proper window handle to dispatch a message to. I looked at this very closely and gave up trying to tunnel down through the Client hierarchy to get an ambiguously referenced embedded object windows handle. Just too iffy. Again though, I'd love to see where someone had nailed this process down as it would mean much more control over the object (just not Refresh as that's not among the standard windows messages and is more of a context / menu verb that needs to be invoked).
And, happy Labor Day.