Imported Java agent

I saw a post on Lotus developerWorks asking for help on creating an imported Java agent. Since I have seen this question so many times I finally decided to create an example.

Please note: Lotus Notes/Domino will ignore the CLASSPATH variable set on the local machine. The equivalent of CLASSPATH in the Notes/Domino world is the JavaUserClasses notes.ini variable. Likewise Notes/Domino doesn’t use Manifest files in jar-files.

I case you didn’t know you can create Java agents in two ways in Domino Designer:

  • Write the agent in Domino Designer (this is the most common way to write a Java agent).
  • Import compiled code into Domino Designer.

This example will focus on the latter.

When creating an agent with imported code you must make sure that one of the classes extend the lotus.domino.AgentBase class. When the agent is run in Notes an instance of this class is created and the NotesMain() method is called. As you can see in the first screenshot I have written a simple agent in Eclipse. The class (dk.heisterberg.lekkim.blog.TestAgent) extend lotus.domino.AgentBase and have some simple Java code in he NotesMain() method. Apart from being a requirement, one of the advantages of extending AgentBase is that you do not have to worry about threads and how to get a Session object (you can simply call getSession() as shown in the example).

Once you have compiled the agent (automatically done if using Eclipse) you create a zip-/jar-file with the compiled classes. Make sure to include the entire package hierarchy if you are using packages. Then create an agent in Domino Designer, set the type to “Imported Java” and click the “Import Class Files…” as shown below.

In the dialog box you select the zip-/jar-file you created and add it to the right pane. Then, and this is the important point here, specify the class that extend the lotus.domino.AgentBase class in the “Base class” field. Remember to include the package name if you are using packages.

Click OK and verify the choices you made in the dialog box has been set correctly.

Give the agent a name, set the desired agent trigger and save the agent. That’s it!

The example database is available for download.

Sametime 7.5 – upgrading is going to be cool!

Technorati tag(s):

The buzz about the next release of Sametime started at Lotusphere 2006 and now IBM is starting to really tease us. The new information is looking VERY promising. While I guess the users will mainly focus on the updated UI the release brings a host to new features of which I’m really excited about a couple of them:

  • A supported, standards based, plugin architecture for 3rd party extension
  • Location based awareness
  • Possibility to save chat history
  • Administration of users and groups based on policies
  • Emoticons (I think it definately has its place in business IM’ing)

Further information:

Override standard Notes client error messages

While perrusing the fix list for Notes 6.5.5 I stumbled upon an entry describing how it is now possible to override the standard error messages if you know the hex error code. It’s SPR #ARUI6FRLJ5.

It means that you will be able to customize error messages like “The server is not responding” etc. I will need to look into this.

I guess the only thing we need to know now is the actual hex error codes… πŸ™‚

Update: Chris jumped in and told me where to find the error codes. As of Notes/Domino 7.0.1 there are 7308 error codes!! Wild.

Technorati tag(s):

If anyone has Rockys e-mail address…

…please let him know that his RSS feed is messed up and hence not working. Something about a mismatched tag:

XML Parsing Error: mismatched tag. Expected: </content:encoded>.
Location: http://www.lotusgeek.com/SapphireOak/LotusGeekBlog.nsf/stories.rss
Line Number 80, Column 802:

I discovered it by accident since I went to his site for the link to the super cool button maker and saw some posts I hadn’t seen in my RSS reader. I almost missed Bob Balaban guest blogging about UTF-8, UTF-16 and LMBCS (which are character sets if you were wondering)… πŸ™‚

Another quirk in Lotus Notes 7.x found

At the office we have found another funny quirk in Lotus Notes 7.0/7.0.1. Suppose you have a form with an embedded categorized view restricting the documents to a category. If you move the focus to the embedded view and press Shift – to collapse all sections the shown documents dissapear. My guess is that Notes collapse the view section we are restricting to.

The issue is only visible in Notes 7.x but not in Notes 6.5.1 or 6.5.4 (the only two 6.5 versions we’ve tested).

I guess I’m going to have to open a PMR with Lotus Support.

Technorati tag(s):

Show ‘n Tell Thursday: Export directly from a web agent to an Excel spreadsheet in landscape format (23 Feb 2006)

A lot of web applications has a requirement to export some data to Excel spreadsheets. Whether you write the code (normally an agent) to export the data in LotusScript or Java you normally have two options:

  • Use a HTML page
  • Use a XML document

I’m going to concentrate here on using the HTML option since it is by far the easiest and the one that produces the shortest agent. However using the XML option affords you a number of other advanced options such as creating named cells and creating multiple worksheets in a workbook. I really suggest looking into this option if you need more specialized formatting.

To do this the easiest approach is creating the spreadsheet in Excel, saving is as XML and then using the generated XML document as a “template”.

Anyways – on with the export. To export from the web to Excel using a HTML document is mind numbingly easy. Simply create a HTML document with a HTML table and set the Content-type to application/vnd.ms-excel. Exporting a static spreadsheet with two columns and two rows is as simple as the following:

Sub Initialize
   Dim session As New NotesSession
   Dim docContext As NotesDocument
   Set docContext = session.DocumentContext

   'set content-type
   Print "Content-type: application/vnd.ms-excel"

   'start table
   Print |<HTML>|
   Print |<body><table border="1">|

   'output table
   Print |<tr><td>|
   Print |1-1|
   Print |</td><td>|
   Print |1-2|
   Print |</td></tr>|
   Print |<tr><td>|
   Print |2-1|
   Print |</td><td>|
   Print |2-2|
   Print |</td></tr>|

   'stop table and document
   Print |</table></body></html>|

End Sub

The trick is however to set the page title and page orientation for print. To do this you use can use some Microsoft proprietary CSS extensions. The changes from the above code is highlighted in bold.

Sub Initialize
   Dim session As New NotesSession
   Dim docContext As NotesDocument
   Set docContext = session.DocumentContext

   'set content-type
   Print "Content-type: application/vnd.ms-excel"

   'start table
   Print |<html xmlns:x="urn:schemas-microsoft-com:office:excel">|
   Print |<head>|
   Print |
<style>
  <!--table
  @page
   {mso-header-data:"&CMultiplication Table00ADate: &D00APage &P";
   mso-page-orientation:landscape;}
   br
     {mso-data-placement:same-cell;}

  -->
</style>
  <!--[if gte mso 9]><xml>
   <x:ExcelWorkbook>
    <x:ExcelWorksheets>
     <x:ExcelWorksheet>
      <x:Name>Sample Workbook</x:Name>
      <x:WorksheetOptions>
       <x:Print>
        <x:ValidPrinterInfo/>
       </x:Print>
      </x:WorksheetOptions>
     </x:ExcelWorksheet>
    </x:ExcelWorksheets>
   </x:ExcelWorkbook>
  </xml><![endif]-->|

   'start body and table
   Print |</head><body><table border="1">|

   'output table
   Print |<tr><td>|
   Print |1-1|
   Print |</td><td>|
   Print |1-2|
   Print |</td></tr>|
   Print |<tr><td>|
   Print |2-1|
   Print |</td><td>|
   Print |2-2|
   Print |</td></tr>|

   'stop table and document
   Print |</table></body></html>|

End Sub

It is as simple as that. The trick is of cause in the CSS extensions to control the page setup. The ones used here should be pretty self-explainatory. There are numerous other CSS extensions you can use – see the link at the bottom for more information.

Hope it helps someone. Happy Thursday.

Further reading:

Technorati tags: ,

Awareness with Notes 6.5.1 against Sametime 7.0 server – broken?

I upgraded the combined Domino/Sametime server at a remote site from Domino 6.5.4/Sametime 6.5.1 to Domino 7.0/Sametime 7.0 the other day. The only issue during the upgrade were some problems with some files being written to the wrong place. Afterwards the install tested out okay. The problem was however that I tested using my Notes 7.x client… πŸ™

As mentioned I thought everything was fine – the problems started this morning however. The users (running awareness from Notes 6.5.1 clients) started complaining about Sametime connectivity issues. It appears that Sametime 7.0 isn’t allowing connections from Notes 6.5.1 clients (Sametime error: 0x8000003). The solution so far appears to be upgrading the clients to 6.5.4 (or downgrading the server).

I don’t want to downgrade the server so I have to decide whether to go with Notes 6.5.5 or Notes 7.0 (I’m still having issues with my Notes 7.0.1 install).

Technorati tag(s): ,

Opening a database by replica id with failover – possible at all?

While opening a database using LotusScript using failover is simple, opening the same database using the replica id (also with failover) doesn’t seem so… The goals and premises of the below snippets are:

  • I would like to open a database, with failover, using the replica id
  • I know the database is normally available on server1/Example
  • I do not know which other servers are in cluster with server1/Example

Normally opening a database is as simple as:

Dim db As New NotesDatabase("server1/Example", "maildadminis.nsf")
If db.IsOpen Then
   Msgbox "Database at " + db.Server + "!!" + db.FilePath + " is open..."
Else
   Msgbox "Couldn't open database..."
End If

After replacing one line of code the snippet becomes cluster aware and fails over beautifully to server2/Example if server1/Example is down.

Dim db As New NotesDatabase("", "")
Call db.OpenWithFailover("server1/Example", "maildadminis.nsf")
If db.IsOpen Then
   Msgbox "Database at " + db.Server + "!!" + db.FilePath + " is open..."
Else
   Msgbox "Couldn't open database..."
End If

Moving along I would like this code to work with a replica id instead of a filename. The obvious choice was to try and open the database using the replica id on server1/Example (which would be down), grab the filename and then open the found filename on server1/Example – now using failover.

Dim exists_in_cluster As Boolean
Dim db As New NotesDatabase("", "")
Call db.OpenByReplicaID("server1/Example", "C125711B0076CBF4")
If Not db.IsOpen Then
   'try opening with failover
   exists_in_cluster = db.OpenWithFailover(db.Server, db.Filepath)
End If

If exists_in_cluster Then
   Msgbox "Database at " + db.Server + "!!" + db.FilePath + " is open..."
Else
   Msgbox "Couldn't open database..."
End If

As you might expect this doesn’t work. The database filename isn’t available (after line 3) since the code has no way of translating the replica id to a filename (server1/Example is down – remember).

Another option would be to try and use the NotesDbDirectory class.

Dim dbdir As New NotesDbDirectory("server1/Example")
Dim db As NotesDatabase
Dim path As String
Dim next_db As Boolean

next_db = True

Set db = dbdir.GetFirstDatabase(DATABASE)
While Not (db Is Nothing) And next_db
   If db.ReplicaID = "C125711B0076CBF4" Then
      path = db.FilePath
      next_db = False
   Else
      Set db = dbdir.GetNextDatabase()
   End If
Wend

'try and open the database on server1
Call db.Open("", "")
If Not db.IsOpen Then
   'try and open with failover in cluster
   Set db = New NotesDatabase("", "")
   Call db.OpenWithFailOver("server1/Example", path)
End If

If db.IsOpen Then
   Msgbox "Database at " + db.Server + "!!" + db.FilePath + " is open..."
Else
   Msgbox "Couldn't open database..."
End If

This doesn’t work either because server1/Example is down hence I’m unable to get a directory listing from the server.

So… What is a LotusScript programmer to do? I could give in and use the Domino Cluster Directory to find the filename for a replica id and then go directly to opening the database using failover. I would however really like to avoid using the Cluster Directory which in my book is a system database which is best left alone. Another option is to use the catalog.nsf to do the same thing.

What really bothers me is that the Domino server and/or the Notes client must already have the functionality since it is used when failing the client over. Why not expose it?

Technorati tag(s): ,

Trying to explain inheritance and polymorphism

Disclaimer: Sorry for the boilerplate but I have to state here, that the text is my (Mikkel Heisterberg) property and may not be reproduced without written concent from the author.

As a LotusScript programmer you use objected-oriented programming (OOP) every day whether you realize it or not. The built-in LotusScript classes (NotesSession, NotesDatabase etc.) are classes based on OOP, written by IBM Lotus Software to make it easier for you to program Lotus Notes using abstractions you understand (such as databases, views, documents etc.) instead of dealing with a lot of low-level details.

In OOP parlance a class is a prototype object (it is a template) instructing the computer how to construct an object of a given type. The NotesDocument class creates NotesDocument objects.

OOP is built upon two core concepts:

  • Inheritance
  • Polymorphism

Inheritance means that one class can inherit its functionality (e.g. subs, functions and properties) from a parent class. If you recall the class hierarchy of the built-in LotusScript classes, NotesRichTextItem inherits from the NotesItem class making a NotesRichTextItem have all the same functionality of a NotesItem. Apart from the NotesItem functionality the NotesRichTextItem class also knows how to handle rich text formatting, doc-links etc.

Making NotesRichTextItem inherit from NotesItem means that the developer does not have to repeat all the code of the NotesItem class in the NotesRichTextItem class (it’s inherited).

Additionally inheritance also affords polymorphism. This means, in our NotesItem/NotesRichTextItem discussion, that every place I use a NotesItem In my code I can use a NotesRichTextItem instead since it is guaranteed to have all the same functionality since it is inherited. This means I can write code as follows:

Dim item As NotesItem
Set item = doc.GetFirstItem("MyNormalItem")
Msgbox item.Name
Set item = doc.GetFirstItem("MyRichTextItem")
Msgbox item.Name

This is a very powerful concept though it can take some time to really understand the benefits and be able to fully exploit it. To help clarify let me use an analogy.

Suppose you are out walking in the woods with your friend and his 5 year old son. You are a passionate about birds and know all about the different species, how and where they feed, breed etc. Your friend isn’t knowledgeable about birds Β– his son even less so. When spotting a specific species of bird, say a Red-tailed hawk, you can tell your friend to look at the hawk. Not being into birds himself your friend doesn’t know all the details about that specific species Β– he only knows that it is a predatory bird. It still means, however, that even without knowing any specifics about hawks your friend can talk intelligently about it since he knows it’s a predatory bird and it hence inherits many of its traits from predatory birds in general. In a sense he’s thinking “predatory bird” when you say “Red-tailed hawk”. Your friends’ son doesn’t need to distinguish between the different species and hence only sees a “bird”. He does know some general traits about birds though (they lay eggs, they can fly etc.).

Both are using polymorphism since they’re using a more general term (predatory bird / bird) instead of your specific term (Red-tailed hawk). They may now know specifics but they know enough to talk about the bird in decreasing detail.

Returning to our LotusScript example suppose you are writing a function returning a NotesItem (“bird”). You colleague doesn’t need to know that you sometimes return a rich text item (“hawk”) and sometimes a normal item (“bird”) since they can be used interchangeably as long as you only need access to common functionality (“it can fly”, “it lay eggs” etc.)

Thus you are leveraging polymorphism to help shield your colleague from the details he maybe does not need to know.

Show ‘n Tell Thursday: Fixing the sorting in the “Recent Messages” (16 Feb 2006)

If you are like me (and most of the organizations I do consulting for) you like the newest e-mails to be on top in the inbox which is the opposite of the default sorting in the inbox. Previously, Notes 5 and earlier, you had to customize the $Inbox-folder in the mail template to achieve this. Since Notes 6 and the addition of persistant sorting of view/folder columns you don’t need to do this anymore since the users can do it themselves.

This is all well and good but if you use the “My Work” bookmarks page you will see that the newest e-mails are at the bottom of the “Recent Messages” list on the Today-page no matter how to sort your e-mails. This annoyed me for a while until I decided to track down why the sorting of the $Inbox-folder wasn’t honored.

As you can see below I found the offending option and fixed it.

To fix the sorting you need to open the bookmark.nsf database in the Designer and go to the list of forms. Find the form called “ng-today_mail” and open it for editing.

Now select the embedded view in the content pane and bring up the preference box. Go to the second tab and deselect the “Show recent first” option. Save and close the design element.

That should do it.

Technorati tags: