The February 2004 Blog
send me a comment

Notes OpenLog Progress (Sunday, Feb 29)
[ permalink ] [ GoogleTrack ] [ e-mail me ] [ >> ]

When last we spoke of the Notes OpenLog Project in this blog, I had just released version 0.91. If you haven't been over to the OpenNTF site since then, you've missed a few incremental updates to the database. I'm now up to version 0.94.

In case you've been falling behind on the aggresive release schedule, here are some of the changes I made between version 0.91 and verison 0.94:

So far, so good, as far as I can tell. I feel like I was kind of spamming the OpenNTF site with new releases for about a week there, because I kept making updates to the database, but I thought it might be useful for everyone to see the genesis of the code across the various versions, especially if I started introducing errors into the codestream or anyone disagreed with the design decisions I was making.

I was also trying hard to introduce more functionality without making things muddy (as Justin would say). For example, my original use for the code was for backend agents, but Rob and Bruce pointed out a few restrictions caused by such thinking, so I added some additional logging options.

After all this, though, I'm still a tiny bit reluctant to release an official "1.0" version of the database. Here's what I'd like to do before that happens:

  1. Make the interface a little more "web friendly"
  2. Provide more sample code, to make sure people understand the options (and how easy it is to use) without having to look at the script libraries
  3. Get some feedback on whether or not anyone has had any problems (either because of bugs in the OpenLog code or unclear instructions on how to use it)

While I'd appreciate some help on all of those items, I'd especially like to hear about the last one. Is anyone else using this thing yet? Is it useful, confusing, or just kind of esoteric? Do you have it on a production server?

I'm not trying to fish for compliments here. Just want to get some feedback. Thanks.

Muscle Cramps (Saturday, Feb 28)
[ permalink ] [ GoogleTrack ] [ e-mail me ] [ >> ]

I woke up this morning around 6:00 AM with this strange muscle cramp in my back (unless you don't think that muscle cramps are strange, in which case it was a normal muscle cramp). It wasn't any kind of debilitating pain, but about every 30 to 60 seconds this muscle in the middle of my back would bunch up.

I figured it would work itself out, so I got up after a while and made pancakes for everyone, like I try to do every Saturday. By the time breakfast was over, the cramps were still coming in spurts, so my wife asked if I wanted a heating pad. I initially refused, thinking that real men don't need such things. About 20 minutes later, though, I realized that I wasn't a real man and asked for the heating pad. My wife smiled and brought out one of those adhesive ThermaCare heating pads that you remove from the packaging and stick to your body, and through the magic of modern chemistry it starts getting warmer and warmer.

Funny thing is, this particular brand of heating pad was packaged specifically for the relief of menstrual cramps. All the instructions and pictures on the box dealt with things like placing the adhesive side of the pad to your panties and applying the heat to...well, not your back. Not knowing how this related exactly to my particular situation, we just got some masking tape and stuck it to my lower back.

Half an hour later, I'm not sure if my back feels better or not, but I certainly don't have any menstrual pain.

The Most Manly of Creatures (Thursday, Feb 26)
[ permalink ] [ GoogleTrack ] [ e-mail me ] [ >> ]

I know it's still Thursday as I'm writing this, but it's late where I'm at, and most of you won't be reading this until Friday, so... here's a little Friday humor for you, courtesy of the weekly News of the Weird column:

Geologist David J. Siveter of Leicester University (England) wrote in the journal Science in December that he and his team had found a fossil 425 million years old that is probably the oldest record of an unambiguously male animal. They named the half-inch-long shellfish Colymbosathon ecplecticos, which they said means "swimmer with a large penis," referring to its organ that is one-fifth of its body length. [New York Times, 12-4-03]

Oh my...

domBulletin Rocks (Tuesday, Feb 24)
[ permalink ] [ GoogleTrack ] [ e-mail me ] [ >> ]

I just set up a domBulletin discussion board at work today. It took about 20 minutes to get it up and running, including printing and reading the documentation, adjusting the ACL, and setting all the preferences. If I had to do it again, I could easily have it ready in less than half that time.

Looks great, my co-workers like it, it's full-featured, and I don't get any of those "Notes web apps are so ugly out of the box" comments. domBulletin rocks.

The Economy of Printers (Sunday, Feb 22)
[ permalink ] [ GoogleTrack ] [ e-mail me ] [ >> ]

I was out shoppping today, and I decided to see how much the latest inkjet printers cost. Not that there's anything wrong with the printer that I have, but it's a few years old, and it doesn't have quite the resolution of most of the inkjets on the market today.

At the low end, I saw that I could buy a 2400 x 1200 dpi Lexmark for $35. It came with both black and color "starter" ink cartridges, and pretty much had everything but the USB cable (not a problem for me -- I've got plenty of those). Just out of curiousity, I looked to see how much the normal ink cartridges were for this machine (since I wasn't sure how much ink would be in something called a "starter" cartridge).

Turns out that a black cartridge is $30 and a color cartridge is $33 for this particular machine. Amused by the price disparity between the printer and the ink, here's my new printer strategy:

That way I'll get the tax credit for a donation, my local school system will get new computer equipment, and I'll be saving money on printer ink.

More Thoughts About recycle() (Friday, Feb 20)
[ permalink ] [ GoogleTrack ] [ e-mail me ] [ >> ]

When last we left our superhero, he was pondering the question of why AgentContext in a Notes agent would be a global reference, even when it was created from two distinct Sessions (when I say distinct, I mean that they were instantiated separately and recycling one had no effect on the other).

I think some of my confusion about the Session object and the AgentContext object in the Domino Objects for Java was that I was thinking that AgentContext was contained by Session -- just like how in the backend LotusScript classes or the C++ API everything you use is essentially contained by a Session object.

However, in Java I don't think that the containment works quite like that (not with regards to AgentContext anyway). Even though the documentation explicitly states that AgentContext is contained by Session, I have a feeling that it's really a static object (either in the true Java sense or in the sense that it's a single handle in memory). This would make sense, because within the confines of an agent there really is only ever one AgentContext, and sharing it among any Session object that may ever request it would be efficient.

As a result, calling Session.getAgentContext() won't access an AgentContext that was created as a private member of the Session; rather, it will get a handle to the static AgentContext that was created in memory when the agent fired up. If this is the case, then no matter how many different and unique Session objects you create, they're all using the same AgentContext handle. As a result, if you recycle() any of the AgentContexts, you recycle() them all (as I found).

It would also appear from my testing that recycling a Session does not recycle the AgentContext -- and why would it? If AgentContext is truly static as I described above, then Session.recycle() had better not recycle it, because some other Session somewhere might need it.

Which all goes back to the two golden rules of recycling Notes Objects in Java:

In the case of recycling AgentContext, I shouldn't have been doing it for both those reasons: [1] I didn't actually create the object (as indicated by the "get" in "getAgentContext"), and [2] if it's a static reference, it might be in use somewhere else.

In general, this second rule is really hard to keep straight, especially across many classes or threads. This is because with the Domino Objects, two objects that are referencing the same database, view, document, etc are the same object. The Notes help gives this example:

View v1 = db.getView("All");
View v2 = db.getView("All");
v1.recycle(); // also recycles v2

Or, if that didn't quite click with you, try compiling and running this example:

import lotus.domino.*;

public class JavaAgent extends AgentBase {
    public void NotesMain() {
        try {
            Session session = getSession();
            AgentContext agentContext = session.getAgentContext();
            Database db = session.getDatabase("", "names.nsf");
            GetNamesDb gnd = new GetNamesDb();
            
            // this will work fine...
            System.out.println("User: " + session.getUserName());
            // ...but this will cause an error
            System.out.println("Main agent: " + db.getFileName());
        } catch(Exception e) {
            System.out.println("Main agent error: " + e);
            e.printStackTrace();
        }
    }
}

///////////////////////////////////

import lotus.domino.*;

public class GetNamesDb {
    public GetNamesDb () {
        try {
            Session s = NotesFactory.createSession();
            Database gdb = s.getDatabase("", "names.nsf");
            System.out.println("GetNamesDb: " + gdb.getFileName());
            gdb.recycle();
            s.recycle();
            // sleep for a few seconds to make sure everything
            // gets nice and recycled
            Thread.sleep(3000);
        } catch (Exception e) {
            System.out.println("GetNamesDb error: " + e);
            e.printStackTrace();
        }
    }
}

You'll get an error when you try to call db.getFileName() in the main part of the agent, because that object has already been recycled, even though it was created and recycled as a local object in another class using a different Session. (What makes me think it's a different Session? Because I can recycle it without affecting the other Session object.)

This means that you have to be really, really careful when you decide to recycle a Notes object anywhere in any class or thread, even if you created and used it as a local variable. If anything else anywhere has a reference to the same thing (like in my example), then that reference will also be recycled.

Now, if you just read all that and think that I told you something that was painfully obvious, then either I didn't do a good job of explaining myself or I'm just stupid about these things. Take your pick. And you know, maybe I'm wrong about this whole thing too. I guess I'm just used to thinking that local objects and variables are actually local, and in this case they're not. Then again, I'm certainly not used to thinking about recycling my objects when I'm done with them, because that's normally what a garbage collector is for...

What You Don't Know About AgentContext Can Hurt You (Tuesday, Feb 17)
[ permalink ] [ GoogleTrack ] [ e-mail me ] [ >> ]

First of all, I just want to say that I'm going to try very hard not to turn this into the "OpenLog blog" over the next few days and weeks as that particular application works its way through development and testing. However, because that's my pet programming project right now, it's bound to take up a lot of my brain cycles that may normally focus on other (possibly more interesting) topics.

That being said, I just released my first bug fix in the form of OpenLog version 0.91a (I may be changing the name soon too, but that's a whole different subject). It was a small but important bit of the Java library that could have caused some really unexpected problems. Here's the scenario:

I've known for a while that you should try to be good about calling the recycle() method on your Java Domino objects. I linked to an IBM technote on the subject over a year ago, and I've also got a bookmark to Julie Kadashevich's comments about it from way back when. So, armed with this knowledge, I tried to recycle everything I could in my OpenLog Java code.

Well I learned something new about AgentContext as a result. In a Notes Java agent, AgentContext is not only your handle to the currently running agent, but also things like CurrentDatabase, DocumentContext, and UnprocessedDocuments -- all good things to have. In other words, it gives you a handle to the current state of your environment, much like NotesSession does in LotusScript.

Apparently that connection between AgentContext and NotesSession goes a little further. You may or may not know this, but in a LotusScript agent there is only ever one NotesSession object. No matter how many times you type the line:

Dim session As New NotesSession

in your code, you're always accessing the same NotesSession object. You could have that code a hundred different times in a hundred different classes and functions and subs, and they'll all be pointing to the same place. The good thing about this is that you have no performance penalty for making that declaration, because you're just grabbing a handle, not actually creating an object, so you can "create" sessions as often as you'd like and not have to worry about wasting memory (same with session.CurrentDatabase by the way, if this is news to you).

Well I just found out that AgentContext seems to act the same way. I haven't seen this written definitively anywhere, but I'm pretty sure that there's only ever one AgentContext, and it's shared by all of the Java classes in an agent that might want it. For example, this agent:

import lotus.domino.*;

public class JavaAgent extends AgentBase {
    public void NotesMain() {
        try {
            Session session = getSession();
            AgentContext agentContext = session.getAgentContext();

            // (Your code goes here) 
            SessionKiller sk = new SessionKiller();
            try { Thread.sleep(10000); } catch (Exception e2) {}
            System.out.println("User: " + session.getUserName());
            System.out.println("Agent: " + 
                agentContext.getCurrentAgent().getName());

        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

/////////////////////////////////////////////////////

import lotus.domino.*;

public class SessionKiller {
    public SessionKiller () {
        try {
            Session s = NotesFactory.createSession();
            AgentContext agentContext = s.getAgentContext();
            System.out.println("SK User: " + s.getUserName());
            System.out.println("SK Agent: " + 
                agentContext.getCurrentAgent().getName());
            agentContext.recycle();
            s.recycle();
        } catch(Exception e) {
            System.out.println("SessionKiller error: " + e);
            e.printStackTrace();
        }
    }
}

will produce the following output on the Java Debug Console:

SK User: CN=Julian Robichaux/O=nsftools
SK Agent: sessiontest
User: CN=Julian Robichaux/O=nsftools
NotesException: Object has been removed or recycled
    at lotus.domino.local.NotesBase.CheckObject(NotesBase.java:1249)
    at lotus.domino.local.AgentContext.getCurrentAgent(Unknown Source)
    at JavaAgent.NotesMain(JavaAgent.java:15)
    at lotus.domino.AgentBase.runNotes(Unknown Source)
    at lotus.domino.NotesThread.run(NotesThread.java:208)

Oops! It looks like calling recycle() on the AgentContext that I created in the SessionKiller class had the unfortunate effect of recycling the AgentContext in the main agent, despite the fact that I instantiated a completely different Session object to get it from. Interestingly, recycling the Session object didn't seem to affect or have any connection to the Session object in the main agent class (likely because I used a NotesFactory to create it), but the AgentContext ended up being the same in both cases.

Now, whether or not this makes sense is probably a philisophical debate, and in the end it doesn't matter. In my limited testing, it seems that recycling one AgentContext object will recycle all AgentContext objects. So the moral of this story is:

Don't ever call AgentContext.recycle() until you and all of your threads are completely finished...and maybe not even then

I was doing that in the constructor of my OpenLogClass, thinking I was just getting rid of a local object reference, and I found out that I thought wrong. Hope that helps someone else out there who might make the same mistake.

OpenLog 0.91 - Now With Better LotusScript Stack Tracing (Monday, Feb 16)
[ permalink ] [ GoogleTrack ] [ e-mail me ] [ >> ]

I just posted a new version of the OpenLog database to the OpenNTF project page.

No bug fixes (because no one's told me about any bugs yet), but I added the capability to construct LotusScript stack traces as you're passing errors up the stack, sort of similar to how Johan's Log4LS libraries work. This shouldn't affect any of the original functionality of the database (famous last words, I know), but it does provide some additional functionality that a few people have already requested. Please download the latest version of the OpenLog database and read the "Using This Database" document for more details.

Lotusphere Article Consolidation (Sunday, Feb 15)
[ permalink ] [ GoogleTrack ] [ e-mail me ] [ >> ]

In order to relieve concerns that I've had the World's Largest RSS Feed for the past few weeks, I've moved all my Lotusphere content to its own page (of course, if you're using an RSS reader that understands conditional GETs it probably hasn't been a big issue for you).

You can now read it all (in proper chronological order) on the Lotusphere 2004 Page. I've even added some permalinks to the "subentries" I had on many of the days I was in Orlando, so if you want to link to my coffee service story (for example), it's now easier to do so.

OpenLog Version 0.9 is Released (Saturday, Feb 14)
[ permalink ] [ GoogleTrack ] [ e-mail me ] [ >> ]

There is now an OpenLog project page on the OpenNTF site, and database version 0.9 is available there for download. Please check it out and see what you think.

Happy Valentine's Day.

OpenLog Database Project (Thursday, Feb 12)
[ permalink ] [ GoogleTrack ] [ e-mail me ] [ >> ]

I know, I know, I've been a real slacker about not blogging for the past week. I promise I've been thinking of all of you this whole time, and I've been racked with guilt.

But...

I've been working on a programming project. One that may interest you. Here's the problem I've been looking at:

If you're a Notes developer, I'm sure that you've written at least one error and event logging database in the past. It's just something we all do. Several weeks ago, I was getting ready to write yet another one myself, when I thought, "You know, I should really spend some time planning this out and making it really generic and really easy to use. No weird customizations or functions with all sorts of hardcoded values in them -- something anyone could use for anything...and everything."

So I let that idea brew for a while. And once it really started to work itself out in my head, I began coding late at night after the kids went to bed. As badly as I wanted to keep up with my blogging, I knew I had to focus on this and just get it done, or it would be hanging over me for a really long time.

Now, a week later, I think I'm pretty much done (except for fleshing out two of the help documents) and ready to go beta. I just proposed it as an OpenNTF project, so you can check over there for updates. I thought that OpenNTF would be a better venue for this type of thing, because it will be more of a "living" database over there, whereas things get a bit static on my site. And since I know that you've all written these sorts of databases before, I expect a lot of comments and feature enhancements from the studio audience.

Here's what I ended up with: a database with two script libraries (one LotusScript, one Java) that you can copy and paste into any or all of your existing databases. If you include these libraries with your agents and scripts, you can create error and event documents in the log database with a single call to the functions/methods.

So far that's pretty unexciting, right? Let's look at an example. Here's a short LotusScript function:

Sub ErrorSub1 ()
	On Error Goto logErr
	Print Cint("nope")
	Exit Sub
logErr:
	Call LogError
	Exit Sub
End Sub

Pretty simple, and the only thing that looks non-standard is the "Call LogError" line in the error block. Take a look at the log document that is produced. No other code was required; all you had to do was include the script library in the agent and call the LogError function. You didn't even need to pass any parameters. And if you're running ND6 (I'm doing testing on R5 to keep it slightly backwards compatible), you even get a LotusScript stack trace!

Similarly with Java, this code:

// global variable
private OpenLogItem oli = new OpenLogItem();

public void errorMethod1 (Session session) {
    try {
        DbDirectory dbdir = session.getDbDirectory("noserverwiththisname");
        Database db = dbdir.getFirstDatabase(DbDirectory.DATABASE);
    } catch(Exception e) {
        e.printStackTrace();
        oli.logError(e);
    }
}

will produce a very similar log document. Beats the heck out of those crappy little NotesLog documents that make you pass all sorts of information when you create them. The database itself looks a little better than the standard Agent Log database too (here's a screenshot of the current version in R5).

So you can log all of your LotusScript and Java errors in a common format to a common log database by just adding one line of code to the routines in your existing agents and script libraries -- with no messy parameters other than the Exception object in Java. And if you do this to all of your databases, then every morning when you come to work to check your logs, all you have to do is check one single database to get everything all together in the same view.

But wait, there's more. There's also the capability to define Notification profiles in the log database, so that certain people or groups of people are sent e-mail notifications whenever specific events or errors occur. The profiles allow you to specify a number of different "watch" parameters, and you can even use wildcard characters and lists of terms to broaden your specifications. So not only can you set up a notification to (for example) tell you whenever an error is logged from a particular database, you could also get notified whenever any error that contains the word "LS:DO" or "network" occurs.

What that means is: no more writing custom error notification routines in all of your databases. You can handle it all with profiles in the central logging database.

This also means that any of your databases that don't have proper error logging or notifications can be brought up to speed very quickly. You and your development team will no longer have any excuse not to log all of your errors.

Oh yeah, and I think that the Java library will work just as well with servlets too (still testing, but I don't see why not). Would that be helpful?

The ComputerWorld Slant (Wednesday, Feb 4)
[ permalink ] [ GoogleTrack ] [ e-mail me ] [ >> ]

During Lotusphere, ComputerWorld printed an online article entitled "Lotusphere: Customers eye Workplace with interest, but are wary". The article is now in the latest print issue of ComputerWorld, with the new title "Lotus Users Wary About IBM's Workplace Strategy".

In addition to the subtle change of title, they also made some minor edits to the story, and removed the last three paragraphs, which read:

The Workplace direction also has its fans among current customers. Columbia, Md.-based MedStar Health's messaging and support services manager, Frank Hasting, said he's very happy with his existing Domino-based messaging system and even happier at the savings he foresees from Workplace products such as Lotus Workplace Messaging. That simplified, Web-based system is intended to bring e-mail access to users who don't need a full suite of messaging features.

MedStar now supports e-mail for 23,000 users in the hospitals it runs. Hasting would like to use Lotus Workplace Messaging to add accounts for another 14,000 workers such as doctors and nurses, who are likely to access the system through kiosks and need a basic messaging system.

"In terms of the cost per client, the savings are dramatic -- $15 per user vs. $60," he said. "It's huge savings, an order of magnitude. It's going to be great."

I understand that you sometimes have to edit a story for readability and length, but in doing so they effectively removed all positive references to Workplace when the story went to print. That seems a little...slanted.

Lotusphere in Review - Part Three (Tuesday, Feb 3)
[ permalink ] [ GoogleTrack ] [ e-mail me ] [ >> ]

This entry has been moved to the Lotusphere 2004 page on this site.

Lotusphere in Review - Part Two (Sunday, Feb 1)
[ permalink ] [ GoogleTrack ] [ e-mail me ] [ >> ]

This entry has been moved to the Lotusphere 2004 page on this site.