Java in Notes/Domino Explained: The story on recycle()


As with everything what you see is typically only the tip of the iceberg. This is also true for the Java objects for Notes/Domino since they are only thin wrappers around the underlying, more heavyweight, C++ objects. Since the Java garbage collector has no knowledge of this, all classes in the Notes/Domino API inherit a method called recycle() from the lotus.domino.Base class. The purpose of this method is to explictly tell the C++ object to free any memory it is using. A part from freeing its own memory, the object will also call recycle() on any object that it created. This means that calling recycle() on a database object will also recycle() a view object obtained opened through it.

If you do not realize that calling recycle() will cascade down through the object hierarchy like this you’re going to experience some “interesting” exceptions and unexpected behaviour at runtime.

It is important to note that the only reason for calling recycle() is to release memory while the agent (or other Java program) is running.

If your agent only does a small piece of work it’s probably not worth the effort of calling recycle() since people normally get into a lot more trouble calling recycle() than what they actually accomplish. My recommendation is to recycle document objects when you loop a document collection or view and otherwise not spend time thinking of recycle() unless you start experiencing java.lang.OutOfMemoryError errors.

To recycle() documents while looping a document collection or view you can use a loop-construct like the one below:

DocumentCollection dc = agentContext.getUnprocessedDocuments();
Document doc = dc.getFirstDocument();
Document docTemp = null;
while (null != doc) {
   // do stuff with the document

   // get next document into docTemp
   docTemp = dc.getNextDocument(doc);

   // recycle doc
   doc.recycle();

   // transfer reference to keep loop going
   doc = docTemp;
}

Update: As mentioned on this comment recycling is more important in servlets than in agents. When I post on servlets I’ll give some more pointers.

Java in Notes/Domino Explained: Stack, heap and references


Memory-wise a program running on a computer uses two discrete pieces of memory – the stack and the heap. The stack is a small(er) piece of memory specific to the method being executed. The heap is much larger and may be shared between programs. No need to worry about the implementation details more than this.

When you instantiate an object in Java you are actually allocating two pieces of memory – one on the stack and one on the heap. The memory of the stack is used to store a reference and the memory on the heap is used to store the actual object. The primitive datatypes (int, long, char etc.) are only stored on the stack.

Have you ever been debugging a Java agent using System.out.println and seen something like “java.lang.Object@bbcab38” show up in the Java debug console? What you are seeing is actually the memory address of the object and not the object itself. This happens because there is no toString() method in the object so the JVM prints out the memory address since that’s the last resort to show something unique about the object.

The below figure shows that’s on the stack and the what’s on the heap from the perspective of the simple agent shown below running in Notes/Domino. Notice how the declared int only exists on the stack.

import lotus.domino.*;

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

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

Of cause the above picture isn’t totally accurate since it doesn’t show all the objects created and references held by the objects on the heap but you get the picture. The lotus.domino.Database pointed to by the lotus.domino.AgentContext object is the current database, that is agentContext.getCurrentDatabase().

By reference vs. by value

In Java you only have direct access to what’s on the stack which means that what you manipulate in your agents are the references (i.e. on the stack) and not the objects themselves. This means that you in Java always program by reference and not by value. In fact there is no equivalent of the ByVal keyword in LotusScript. If you need to work on a copy of an object (i.e. ByVal) you’ll need to copy the object yourself – in Java-speak this is called cloning the object.

Java in Notes/Domino Explained: Tricks in the Java Debug Console


The Java Debug Console is found under FileToolsShow Java Debug Console in the menu and this is where the output of System.out and System.err goes. There are a number of secret keyboard commands you can use to show various information. Below is a listing of these commands.

Note: The cursor has to be in the output field (the big one on the top) for the commands to work.

Key Description
p Print a list of the system properties (an enumeration of System.getProperties()
d Toggle debug info.
m Show memory information
g Run garbage collection
h Show help (list commands)
f Finalize objects in queue
v Show Java version information
0-9 Set applet error level

Re: Loving policies – especially mail settings


As described in an easier post (Loving policies – especially mail settings) we have been using the mail settings document introduced in Domino 7 to apply calendar settings to users mail databases. More specifically we have been enabling the “Allow Notes to update To Do status and dates for incomplete entries” setting on the calendar profiles so that To-Do’s that hasn’t been completed flow along to the next day.

This functionality is implemented by scheduling an agent in the users mail database. The agent is called “Update Tasks” and by default it is enabled to run at 1AM when the above setting is enabled by the user.

However there is a problem by enabling this setting using mail settings. The setting is correctly applied to the calendar profile documents but the “Update Tasks” agent isn’t being enabled. The effect is that you think the setting is enabled but in fact it isn’t.

Two things to do now:

  • Write an agent to enable the agent across mail databases
  • Call Lotus Support

Bummer… ๐Ÿ™

(The particular server is on Domino 7.0.)

Update: Here’s an agent to enable the agent. Create an agent in the Domino Directory and run it on selected users. Since it is Java-week here at lekkimworld the agent is in Java… ๐Ÿ™‚

import lotus.domino.*;

public class JavaAgent extends AgentBase {

   public void NotesMain() {

      try {
         Session session = getSession();
         AgentContext ac = session.getAgentContext();

         DocumentCollection dc = ac.getUnprocessedDocuments();
         Document doc = dc.getFirstDocument();
         Document docTemp = null;
         while (null != doc) {
            Name nn = session.createName((String)doc.getItemValue("FullName").elementAt(0));

            // get mail database
            Database db = session.getDatabase(
               doc.getItemValueString("MailServer"),
               doc.getItemValueString("MailFile"));

            try {
               // get calendar profile and see if setting is enabled
               Document docProfile = db.getProfileDocument("CalendarProfile", null);
               if (docProfile.getItemValueString("TaskFollow").equals("1")) {
                  // setting enabled - get agent
                  Agent a = db.getAgent("Update Tasks");
                  if (!a.isEnabled()) {
                     // set run-on server to mail server to be safe
                     a.setServerName(doc.getItemValueString("MailServer"));

                     // enable agent
                     a.setEnabled(true);

                     // save agent
                     a.save();

                     // log
                     System.out.println("[OK] Enabled 'Update Tasks' for " + nn.getAbbreviated());
                  } else {
                     // log
                     System.out.println("[OK] 'Update Tasks' already enabled for " + nn.getAbbreviated());
                  }
               } else {
                  System.out.println("[NO] " + nn.getAbbreviated() + " doesn't have setting enabled...");
               }
            } catch (NotesException e) {
               System.out.println("[ERROR] Unable to process user (" +
                  nn.getAbbreviated() + "): " + e.text + " (id: " + e.id + ")");
            }

            docTemp = dc.getNextDocument(doc);
            doc.recycle();
            doc = docTemp;
         }

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

A challenging DB2 project coming


At the office we have been contacted by a customer who wants help designing and implementing a (relational) database but it’s not just any database. We are talking a database that will grow anywhere from 60 to 240GB per month!! How’s that for requiring scalability? Being in bed with IBM we have of cause already been in contact with the DB2 guys at IBM here in Denmark to get some help. I think we need to think this project through before starting of… ๐Ÿ™‚

Does anyone know of any storage related restrictions on the DB2 products?

Java in Notes/Domino Explained: Creating your own packages


The purpose of a package is to create a namespace for the classes to make similarly named classes from different packages distinguishable to the compiler and the JVM. Using packages you can have a class called MyClass in two packages but have the compiler know the difference between them. This really comes in handy when starting to work with third-party libraries since all libraries tend to have a Context or Document class.

Looking at the core Java API you’ll find two classes called Document. The Notes/Domino Java API also has a class called Document. The compiler and JVM are however able to distinguish between these three classes since they are in different packages:

  • javax.swing.text.Document
  • org.w3c.dom.Document
  • lotus.domino.Document

Creating packages

You create a package by using the package directive at the top of your class. The below class is in the mypackage package:

package mypackage;

public class Echo {
  public String echo(String s) {
    return "Echo: " + s;
  }
}

To use this class you have to import the package using the import directive (first example below) or specify the fully qualified name of the class (second example below).

import mypackage;

public class SomeClass {
  public void run() {
    Echo e = new Echo();
    System.out.println(e.echo("HelloWorld"));
  }
}
public class SomeOtherClass {
  public void run() {
    mypackage.Echo e = new mypackage.Echo();
    System.out.println(e.echo("HelloWorld"));
  }
}

Classes automatically have access to the classes in the same package so there’s no need to import the package into itself.

Package naming


Packages are normally named using a hierarchical naming scheme sort of like domain names. Domain names are in fact very often used to make sure that packages from a certain company are uniquely named. At my company we always start our package names with dk.it-inspiration for example.

When discussing package naming two points of confusion are common:

  1. Package name doesn’t have to unique in the World but simply within the scope of the code you write. You are free to think up any package name you like. You can even choose to start your packages with “com.ibm” if you are so inclined.
  2. Although package names are hierarchical they will not be imported in a hierarchical manner.

Point number 2 is often confusing to programmers new to Java so let me explain it in a little more detail. If you look inside the notes.jar file you’ll see that it contains a lot of packages as shown on the left. However even though you import lotus.domino.* in your code the classes from lotus.domino.cso, lotus.domino.local and lotus.domino.util will not be imported. You have to import these packages explicitly (although there is no need to do so).

If you come to Java from LotusScript I guess packages will be a welcome addition. Since LotusScript has no concept of namespaces for functions, you often run into issues with function and sub naming. For example you cannot write a function called Split since LotusScript already has a function of that name. In fact this was a major pain upon upgrading to Notes/Domino 6 where the function was introduced since I had already written a Split function in our Notes/Domino 5 applications. As part of the upgrade all our LotusScript code using this custom Split function had to be rewritten.

This wouldn’t have happened if LotusScript had had the concept of namespaces.

Show ‘n Tell Thursday: Allow deletion of reservations in the RnR database (6 April 2006)


Some users prefer to create reservations directly in the RnR database instead of from their calendar. If this is the case they also sometimes need to delete a reservation. This is however not easily possible since the Querydocumentdelete event in the database script prevents this. Pressing delete will only result in the user being shown following message: “You must use the Delete Reservation action provided in the view to delete selected reservation(s).”

The Delete Reservation action is however not visible to normal users having been given the standard access of Author as recommended in the About document. The action is only shown to Editors and above.

The solution is to give the users Editor access or customize the RnR template to control the visibility of the action based on a role instead.

Technote: Changing the IP address of a server

While changing the IP address of a server may not be a common thing to do it still happens. If one of those junior administrators did use the IP address instead of the hostname to create connection documents it might be nice to know how to “unlearn” those IP addresses from the Domino server. This technote shows you how (it also works for connection documents in the local NAB).

Technote 1231458: Changing the IP address of a server

Java in Notes/Domino Explained: Dynamic class loading


When coding in Java you do not need to know the class you want to instantiate at compile time. You can have the program decide which class to instantiate, ask the user or let it be a configurable parameter. The only caveat with dynamic class loading is that the class you instantiate has to have a no-argument, public constructor.

To use the functionality you need two core Java language features:

  • Classloading
  • The ability to cast an object reference

Dynamic class loading is a much used feature when creating frameworks in Java since it allows you to specify the class to use in a property file outside the code. In the Notes/Domino world it is even easier since you can let the user choose the class to use in a database profile. To use dynamic class loading you use the forName() method of the java.lang.Class class (highlighted in bold):

Class clazz = Class.forName("java.util.Date");
Date date = (Date)clazz.newInstance();
System.out.println(date);

The above example is a little stupid since it simply creates a Date object and prints the date to the console but it shows how to use dynamic class loading.

In the Notes/Domino world you can use dynamic class loading to let the user select the behaviour he/she wants from a profile document. To to this you would write the different behaviours as a couple of different classes all implementing a common interface and then having the user choose which class to use in a profile document. Your agent could then read the classname from the profile document and instantiate the class specified there:

import lotus.domino.*;

public class JavaAgent extends AgentBase {

   public void NotesMain() {

      try {
         Session session = getSession();
         AgentContext ac = session.getAgentContext();

         // get database and profile document
         Database db = ac.getCurrentDatabase();
         Document doc_profile = db.getProfileDocument("JavaClassLoading", null);

         // get classname as a string
         String classname = doc_profile.getItemValueString("DBProfileClassname");

         // have Java load the class
         Class clazz = Class.forName(classname);

         // instantiate the class (we assume the class implements
         // the NameLoader interface specified in the agent)
         NameLoader nl = (NameLoader)clazz.newInstance();
         nl.loadNames();

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

public interface NameLoader {
   public void loadNames();
}

I have used this approach many times by designing an interface and having multiple classes implement the interface. Then the actual class to use is selectable on a profile document making the application very configurable.

Another example of where you use dynamic class loading “in the wild” is for JDBC (database access from Java). Here you use the dynamic classloading and dynamic object instantiation of Java to tell the DriverManager (the class creating the actual connection to the database) which class to use for the JDBC connection. The below example creates a connection the SAMPLE database that comes with DB2 using the JDBC Application driver.

// load DB2 JDBC driver
Class.forName("COM.ibm.db2.jdbc.app.DB2Driver");

// create connection to sample database
Connection con = DriverManager.getConnection("jdbc:db2:sample");

// create statement
Statement stmt = con.createStatement();

// execute query
ResultSet rs = stmt.executeQuery("select * from employee");
...
...

That’s one wierd programming contest

The Underhanded C Contest started yesterday. The objective of this wierd programming contest is as follows (my highlighting):

“We hereby announce our second annual contest to write innocent-looking C code implementing malicious behavior. In many ways this is the exact opposite of the Obfuscated C Code Contest: in this contest you must write code that is as readable, clear, innocent and straightforward as possible, and yet it must fail to perform at its apparent function. To be more specific, it should do something subtly evil.

I guess we now know who writes all those backdoors into the operating systems… ๐Ÿ˜‰