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… πŸ˜‰

Java in Notes/Domino Explained: More in depth on classloaders


When you run an agent in Notes/Domino the agent class is loaded into memory by a classloader (for more information about what a classloader actually is please refer to this previous post). In the case of Notes and Domino this classloader is the AgentLoader class from the lotus.domino package (that is lotus.domino.AgentLoader).
This is also the classloader which is responsible for loading all the other classes your agent and auxillary classes may use during their execution.

You can query any class in Java about which classloader actually loaded the class into memory. You do this using the getClassLoader()-method of the class instance as shown below:

import lotus.domino.*;

public class JavaAgent extends AgentBase {

   public void NotesMain() {

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

         // get class for the current object
         Class clazz = this.getClass();

         // get classloader that loaded this agent class
         ClassLoader cl = clazz.getClassLoader();
         System.out.println("Default ClassLoader: " + cl.getClass().getName());

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

The output of this agent in the Java Debug Console will be:

Default ClassLoader: lotus.domino.AgentLoader

In Java every classloader may be part of a hierarchy and hence a classloader may have a parent classloader. The only classloader that never has a parent is the top classloader called the bootstrap classloader which is installed by the JVM when initialized. The bootstrap classloader cannot be substituted in the case of Notes/Domino.

If a classloader is asked to load a class and it cannot find it, the request is delegated to the parent classloader if one is present. To demonstrate this we first need an extra classloader – let’s write our own classloader that loads classes from outside the Notes/Domino system classpath. Writing ones own classloader is actually VERY simple. You simply have to extend the java.lang.ClassLoader class and override one method. The code below shows how to write a classloader that loads classes from the root of the C-drive:

import java.io.*;

public class MyClassLoader extends ClassLoader {
   public MyClassLoader() {
      super();
   }
   public MyClassLoader(ClassLoader cl) {
      super(cl);
   }

   public Class findClass(String name) throws ClassNotFoundException {
      try {
         // use utility method to load class bytes from
         // the root of the C-drive
         byte[] b = this.loadClassData(name);
         return this.defineClass(name, b, 0, b.length);
      } catch (Exception e) {
         throw new ClassNotFoundException();
      }
   }

   private byte[] loadClassData(String name) throws Exception {
      // open a the requested file and read the bytes into an array
      InputStream in = new BufferedInputStream(
                       new FileInputStream("c:\" + name + ".class"));
      byte[] raw_classdata = new byte[1024];
      int length = in.read(raw_classdata);

      // since the byte array must be exactly the
      // correct length we copy the bytes into a
      // new array
      byte[] classdata = new byte[length];
      for (int i=0; i<length; i++) {
         classdata[i] = raw_classdata[i];
      }

      // return the byte array
      return classdata;
   }
}

As you can see it is quite easy and only the imagination sets limits as to where you could load classes from in your agents. You could actually write a classloader to load classes from a central class repository using some network protocol of your choosing.

Since we need some classes to load using our new classloader I have written two very simple classes called OutsideClasspath and OutsideClasspath2 as shown below. The classes should be compiled using the javac-tool or using Eclipse and placed in the root of your C-drive. If you do not want to compile the classes yourself you can download them using the links below.

public class OutsideClasspath {
   public OutsideClasspath() {
      ClassLoader cl = this.getClass().getClassLoader();
      System.out.println("Constructor of OutsideClasspath class " +
         "(loaded by: " + cl.getClass().getName() + ")...");

      // load another class
      OutsideClasspath2 oc2 = new OutsideClasspath2();
      System.out.println(oc2.echo("Hello from OutsideClasspath"));
   }
}

public class OutsideClasspath2 {
   public OutsideClasspath2() {
      ClassLoader cl = this.getClass().getClassLoader();
      System.out.println("Constructor of OutsideClasspath2 class " +
         "(loaded by: " + cl.getClass().getName() + ")...");
   }

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

Using our new classloader is also simple. We simply instantiate it and pass the bootstrap classloader as the parent classloader in the constructor.

import lotus.domino.*;
import java.util.*;

public class JavaAgent extends AgentBase {

   public void NotesMain() {

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

         // get bootstrap classloader
         ClassLoader cl = this.getClass().getClassLoader();
         System.out.println("Default ClassLoader: " + cl.getClass().getName());

         // get classloader of the agent and show class name
         System.out.println("Agent class loaded by: " +
                this.getClass().getClassLoader().getClass().getName());

         // create our own classloader passing the
         // bootstrap classloader in the constructor
         cl = new MyClassLoader(cl);
         Class c = cl.loadClass("OutsideClasspath");
         Object o = c.newInstance();

         // create a java.util.Date object using our own classloader
         // to demonstrate the hierarchical nature and delegation
         // model of classloaders
         Class clazz_date = cl.loadClass("java.util.Date");
         Date d = (Date)clazz_date.newInstance();
         System.out.println(d);

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

The output of the agent is as follows:

Default ClassLoader: lotus.domino.AgentLoader
Agent class loaded by: lotus.domino.AgentLoader
Constructor of OutsideClasspath class (loaded by: MyClassLoader)...
Constructor of OutsideClasspath2 class (loaded by: MyClassLoader)...
Echo: Hello from OutsideClasspath
Sat Apr 01 22:13:49 CEST 2006

The output demonstrates a couple of things:

  • The agent class is loaded by the bootstrap classloader.
  • That we are able to load classes using our own classloader what is we can load and instantiate an instance of the OutsideClasspath class.
  • That classes use the classloader that loaded them to load any classes they need. This is demonstrated by the fact that the OutsideClasspath2 class is automatically loaded by MyClassLoader when the OutsideClasspath class creates and instance of it.
  • That classloaders delegate the loading of classes to their parent if they cannot find the class. This is demonstrated by the fact that the request to load java.util.Date is delegated to the bootstrap classloader.

I hope this post has demonstrated the power of classloaders and how you can easily write one that suits your purpose.

Please note:

  • Even if we had not supplied the bootstrap classloader in the constructor of the MyClassLoader class a ClassNotFoundException exception would not have been thrown at runtime when asked to load the java.util.Date class. This is because the bootstrap classloader is always asked as a last resort. Setting the parent classloader is only important if you build your own hierarchy of classloaders as is the case in J2EE application servers.
  • The MyClassLoader class should be part of the agent if you decide to try the code out for yourself in Domino Designer.

Java in Notes/Domino Explained: Classloading


When doing Java development you write your code in classes and hence deal with classes. Each Java class in your source code is compiled into a binary class file.

JavaAgent.java (text) -(compile)-> JavaAgent.class (binary)

The compilation is done automatically for you when you write Java in Notes/Domino or if programming in Eclipse. It does however still help to be aware of what actually goes on under the covers when your agent is run.


“The process of finding the binary classes and loading them into memory is called classloading…”

The fact that each class is compiled into a separate file means that a Java agent consisting of 4 classes will contain 4 compiled classes. Since all the code isn’t combined into a separate file (like an EXE-file on Windows) the Java Virtual Machine (JVM) needs to locate these compiled classes at runtime and load them into memory so it can use them hence the word classloading.

The default classloader in Notes/Domino (lotus.domino.AgentLoader) is capable of loading classes from the classpath of the current agent which consists of:

  • Classes that are part of the agent itself.
  • Classes and JAR-files added to the agent using the “Edit Project”-button.
  • Java Script libraries added to the agent using the “Edit Project”-button.
  • Classes present on the Notes/Domino system classpath.

See the post “Managing external Java dependencies in Domino Designer” for more information on the Notes/Domino system classpath.

The exceptions

There are three exceptional situations that can and do occur frequently when working with Java in relation to classloading. These are the java.lang.ClassNotFoundException, the java.lang.NoClassDefFoundError and the java.lang.UnsupportedClassVersionError. Below are short excerpts from their explanation in the JDK. When programming in Notes/Domino you will probably encounter the first two at some point. The third I do not wish upon you… πŸ™‚

ClassNotFoundException Thrown when an application tries to load in a class through its string name using the forName method in class Class.
NoClassDefFoundError Thrown if the Java Virtual Machine or a ClassLoader instance tries to load in the definition of a class (as part of a normal method call or as part of creating a new instance using the new expression) and no definition of the class could be found.
UnsupportedClassVersionError Thrown when the Java Virtual Machine attempts to read a class file and determines that the major and minor version numbers in the file are not supported.

The ClassNotFoundException exception is encountered when you try to dynamically instantiate a class using a string name (java.lang.Class.forName()) and the class cannot be found in the classpath. This is a checked exception you must catch when doing a Class.forName() call.

The NoClassDefFoundError is raised if you use a class in your agent which in turn uses another class that cannot be loaded at runtime. The most common scenario for this is when using third-party library consisting of multiple JAR-files. In this case you may only have included one of the JAR-files in your agent to make it compile. The agent may compile but if classes in the included JAR-file uses classes in a second JAR-file, that wasn’t included in the agent, this error will occur.

The UnsupportedClassVersionError is less likely to occur if you are on Notes/Domino 6.x or 7.x but does occur quite a lot if you are using third-party libraries on older Notes/Domino versions. The binary Java class format changes slightly over time (much like the On-Disk-Structure of Notes databases) and since the JVM cannot be forward compatible it needs a way to tell you that you are trying to load a class into the JVM it doesn’t know how to handle (the version of the class format is wrong). The way around this is to try and compile the classes using a Java 1.1.8 compiler or using “classic” mode with newer compilers.

So why is this important?

To really appreciate the concept of classloading you need to realize that:

  1. Java classes are not loaded into memory before actually used.
  2. Java supports dynamic classloading.
  3. You can write your own classloader.
  4. Classloaders in Java are hierarchical and thus can delegate classloading to other classes.

You don’t have to worry too much about item 1. I’ll explain item 2 and 3 in detail in subsequent posts to avoid making this post too long. Item 4 deals with delegation of classloading in case a specific classloader cannot find a given class. Suffice it to say that these four concepts allows the JVM to conserve memory and you to write very powerful and highly dynamic agents/classes.

All this fuss about classloading might seem overly complex but consider the fact that many of the classes that you use in your Java agent aren’t some you have written. They are part of the Java Development Kit (the java.lang packages) or part of third-party libraries that you program and execute your agents against.

If there were no classloaders you could not have dynamic classloading and all classes would need to be loaded into memory before starting an agent. This could/would take up a lot of memory and be highly inefficient.