Genii Weblog

Civility in critiquing the ideas of others is no vice. Rudeness in defending your own ideas is no virtue.

Wed 12 Jan 2005, 11:01 AM
I am working on my upcoming presentation for the Bundled Know-How conference EntwicklerCamp '05 on Pushing the Limits - Building Top Notch Lotus Software Extensions.

Aside: If you are in Germany or nearby, this is a conference you should seriously consider.  Besides this session, and my second one, Make Rich Text Your Business, there are sessions on Sharepoint and Office Integration, QuickPlace, SameTime, RSS, XML, Domino and .Net integration, etc. etc., and a lot of great speakers, including Gary Devendorf, Ed Brill, Rudi Knegt and Bernfried Geiger.  I hope to see you there.  But I digress...
Anyway, I was working on my presentation in between support calls and development and fixing the sessions db, and I got a relevant question in the mail:
If you have a minute to answer this question, I would really appreciate it.
I noticed that in your product you have your own @Formulas, is there somewhere I can go to learn how to do this?  Are there issues or concerns about doing this (creating my own @Formulas) that might make supporting/distributing an app difficult that relies on the @Formulas?
This seemed a priceless opportunity to take a break and answer the question here, in case there are others who wonder.  It also gives me a chance to think through a bit what I want to show in my presentation, where this is but one type of extension that I will show.

Extending the formula language
Long before LotusScript was even added to Lotus Notes, the formula language was the development language, and even then, Lotus offered a way to extend and add your own functionality.  This was the "external database driver", and was originally intended to be a way to query and effect databases other than Notes.  This was all long before ODBC support was added, much less database connectors.  Quickly, some enterprising API developers learned that you could use the @DbCommand syntax, which wasn't really used for anything else in those days, to create your own @formula commands.  The popular Formula One Toolkit, our own @YourCommand Toolkit and other more specific extensions took advantage of this in Notes R3.  For example, in R3, our @YourCommand customers could sort lists of text, numbers or dates using the syntax:

sorted_list := @DbCommand("YRCMD":"NoCache"; "Sort"; list);

The key to these extensions is that parameter.  The "YRCMD" told the Notes formula engine to look for a file called "ndbYRCMD.dll" and load the functions from that.  The same would be true for @DbColumn and @DbLookup, although most developers ignored those and stuck with the generic @DbCommand.  (Sure enough, even the standard @DbColumn and @DbLookup most developers are used to is implemented in the file "ndbNOTES.dll")  What is even better is, if the program were run on OS/2 2.x and above, the file it would look for would be "idbYRCMD.dll" or "idbNOTES.dll", or if it were to run on AIX, the file it would look for would be "libdbYRCMD.a" or "libdbNOTES.a", so the formula extension was cross-platform compatible.

Steps to take
First step: Install the Notes C API (full kit) for the Notes versions you want to support.  Key rule of thumb is that if you want to support R5 and ND6, install the lowest level R5 version which you plan to support.  API extensions built for R5 will run on ND6, but not the other way around.  The basic structure you need is found in the C API toolkit.  If you look in the \notesapi\samples\misc\dbdrive directory, where a full database driver extension is implemented.  There is also a lot of information in the Lotus C API User Guide in the topic "External database drivers".

Second step: Choose a name for your extension, and an abbreviated version that is no more than five alphanumeric characters with no spaces.  For example, for @YourCommand, I used YRCMD.  If your sample figures out odds for poker hands, you could call it ODDS, and the file generated would need to be ndbODDS.dll (for Windows).

Third step: Figure out the syntax you want to support.  This is highly flexible, since you control all the parameters, so you could have:

odds := @DbCommand("ODDS":"NoCache"; "FigureOdds"; "10Hearts":"7Diamonds":"6Clubs":"5Diamonds":"1Hearts"; "Discard":"10Hearts":"1Hearts"; "Straight");

and have your internal logic figure out the odds of getting a straight if you discarded the suggested two cards.

Fourth step: Figure out how to read in and process parameters, which are pretty easy and explained fairly well in the dbdrive sample, and also how to write results.

Fifth step: Implement your business (or non-business) logic.

Sixth step: Build your solution and test, test, test.  Test with incorrect data types, too many and too few numbers of elements or parameters, border conditions, etc.  This is especially critical because errors raised by the system may seem very out of place for your users if you haven't handled them yourself.  You can register your own strings for error codes, but you have to use them and not let the error fall through to the default.

Seventh step: Roll in the money you make.

Installing and Using @formula extensions
One of my favorite features of the database driver is that it requires no configuration or installation aside from copying it to the Notes or Domino executable directory (and yes, these do work on the server as well, so long as you implement the version for that OS).  There is no muddling with the NOTES.INI file the way you do with extension managers or menu add-ins or export filters.  The first time the formula language runs into a db driver name it doesn't recognize, it looks for the DLL to load.  If it doesn't find it, it returns a reasonable error that you can trap, so it is easy to handle exceptions when the product isn't installed, unlike an LSX where this is difficult.

Even better, the formula language is so prevalent that you can use your formula language extension from LotusScript or Java or even other C API programs, all by doing the Evaluate method or evaluation logic.  Integrating your extension into an app is as simple as writing the formula using @DbCommand, @DbColumn or @DbLookup with your db driver name.  You don't even have to have the product on your machine when you write the formula, as this is a run time load.  (In case you worry about performance, the load is only done once and is just recognized after that)

In case you can't tell, I am really enthusiastic about extending formula language.  Years after writing @YourCommand, I wrote the @Midas Formulas to extend rich text manipulation into formula language.  Coincidentally, Damien Katz chose just about that time to rewrite and reinvigorate the formula language engine, making the product even more desirable than it had been.  These extensions are easier to write than an LSX, easier to install than just about any other add-in, and usable from more languages and environments, including all OS versions if you choose to support them, than any other add-in.  If you want to see how easy and flexible they can be, see my @Midas for Domino Developers, Part 1Part 2 and Part 3, as well as a post about using @Midas Formulas with Java.  Also, don't miss my Totally Tabular with ideas you could use to build new formula language extensions.

Copyright 2005 Genii Software Ltd.