Java in Notes/Domino Explained: Packages

.quote {
font-style: italic;
font-size: 1.1em;
font-weight: bold;
width: 300px;
}
.quote_left {
float: left;
padding-right: 3px;
}
.quote_right {
float: right;
padding-left: 3px;
}


In Java all classes are part of a package. This goes for the classes you write, classes from third-party libraries and the classes from the Java Development Kit (JDK). Think of a package in the words most litteral meaning – something that groups together one or more objects to make them easier to handle. The objects that we package are classes (and interfaces).

All classes for Notes/Domino are grouped together in a single package called “lotus.domino”. Since the name of a class is actually the name of the package combined with the name of the class, the “real”, fully qualified, name of the Document class (the equivalent of the NotesDocument class from LotusScript) is actually “lotus.domino.Document”. Apart from the “lotus.domino” package you will routinely use classes from the core Java development kit (JDK). The packages from the JDK all start with “java”.


“If you do not explicitly put a class in a package it will be part of what’s called the default package”

If you do not explicitly put your classes in a package they will be part of what’s called the default package. For most programming in Java in Notes/Domino there’s no need to worry about putting your classes in a package – they mostly come into play when writing classes for distribution (e.g. designing API’s).

Importing

When referring to classes in Java you need to use the fully qualified name (e.g. lotus.domino.Document). This will quickly become very cumbersome so you can tell the compiler which packages you use in your code and it will automatically insert the package names at compile time.

In Java-speak this is called “importing a package”.


“Importing packages” is telling the compiler which packages you are using in your code…

For instance by importing the lotus.domino package in Java agents you can simply refer to the Document class instead of the lotus.domino.Document class. This can save quite a lot of typing, it makes the code less verbose and easier to read.

The two agents below are exactly the same from the compilers point of view. The first example shows an agent that import the entire lotus.domino package using the asterix notation (line 1 in bold):

import lotus.domino.*;

public class JavaAgent extends AgentBase {
   public void NotesMain() {

      try {
         Session session = getSession();
         AgentContext ac = session.getAgentContext();
         Database db = ac.getCurrentDatabase();
         View view = db.getView("($All)");
         Document doc = view.getFirstDocument();
         while (null != doc) {
            // do stuff with the document...
            doc = view.getNextDocument(doc);
         }
      } catch(Exception e) {
         e.printStackTrace();
      }
   }
}

The second example shows the same agent but this time I didn’t import any packages. This means that I have to prefix each class with the name of its package. It is more verbose and harder to read.

public class JavaAgent extends lotus.domino.AgentBase {
   public void NotesMain() {

      try {
         lotus.domino.Session session = getSession();
         lotus.domino.AgentContext ac = session.getAgentContext();
         lotus.domino.Database db = ac.getCurrentDatabase();
         lotus.domino.View view = db.getView("($All)");
         lotus.domino.Document doc = view.getFirstDocument();
         while (null != doc) {
            // do stuff with the document...
            doc = view.getNextDocument(doc);
         }
      } catch(Exception e) {
         e.printStackTrace();
      }
   }
}

Please note: The java.lang package is implicitly imported – always!

Drawbacks

However great this is, it also means that you must be aware when this approach will give you problems. Consider using and importing two packages that both contain a class of the same name. In this situation the compiler can’t figure out which class to use (from which package) so it wont compile the code. The solution here is to fully qualify the offending classes with the package names to explicitly tell the compiler which class you are referring to.

Shooting with smaller bullets

Apart from importing an entire package at a time by using the asterix notation (lotus.domino.*) you can also import a single class at a time. You do this by substituting the asterix with the name of the actual class (lotus.domino.Database, lotus.domino.Document etc.). This approach is the one automatically used in Eclipse and it helps alleviate the problem of class name collisions described above. The example above would then look like this:

import lotus.domino.AgentBase;
import lotus.domino.Session;
import lotus.domino.AgentContext;
import lotus.domino.Database;
import lotus.domino.View;
import lotus.domino.Document;

public class JavaAgent extends AgentBase {
   public void NotesMain() {

      try {
         Session session = getSession();
         AgentContext ac = session.getAgentContext();
         Database db = ac.getCurrentDatabase();
         View view = db.getView("($All)");
         Document doc = view.getFirstDocument();
         while (null != doc) {
            // do stuff with the document...
            doc = view.getNextDocument(doc);
         }
      } catch(Exception e) {
         e.printStackTrace();
      }
   }
}

If you do not care about creating your own packages this is all you need to know about packages. If you do care about creating your own packages stay tuned for the next post on packages.

Managing external Java dependencies in Domino Designer

Please note: Lotus Notes/Domino will ignore the CLASSPATH variable set on the local machine. Likewise Notes/Domino doesn’t use Manifest files in jar-files.


One of the major advantages of developing in Java is the abundance of high quality open source libraries available to help you dramastically cut development time. Apache Jakarta and OpenSymphony are just two examples of sites that hosts high quality components you can leverage in your day-to-day developments (make sure to look into Jakarta Commons). The libraries are most often distributed in the form of one or multiple JAR files that you need link to when developing and compiling your code.

If you are unfamiliar with JAR files they are bascially ZIP files with a special directory structure. They are used to package compiled classes and let you handle one file instead of a whole directory tree. Much easier. For more information on JAR files refer to the page Packaging Programs in JAR Files at java.sun.com.

With external dependencies come complexity and issues as to where to place the JAR files so Domino Designer, the Notes client and the Domino server can find the code at design and runtime. When having external dependencies you basically have four options:

  • Include the classes in the agent/web service you are writing.
  • Put the classes in a Java script library and include the script library.
  • Use the JavaUserClasses notes.ini setting.
  • Put the classes in the jvm/lib/ext folder.

Below I’ll explain a little about each approach.

Include the classes in the agent/web service you are writing

This means using the “Edit Project” button in the Domino Designer Java IDE to include JAR files from the local file system in the agent/web service itself. This approach is valid and very easy to use but can mean dublicating the classes across multiple agents/web services in the same database. It is perfect for not having any dependencies outside the database.

Put the classes in a Java script library and include the script library

This means importing the JAR file(s) into a Java script library and then including the script library from agents/web services. This approach is for most cases the preferred way of using JAR files with Domino Designer since you avoid dublicating the code across design elements while avoiding dependencies outside the database. It also means that the code is easily shared among developers working on different agents concurrently.

Use the JavaUserClasses notes.ini setting

The JavaUserClasses notes.ini setting is the equivalent of the CLASSPATH setting used when developing in Java outside Notes. The setting makes the classes universally available so you can use them just like the classes from the java.*-packages lotus.domino.*-package. The setting is restricted in length (due to the limits imposed on notes.ini settings) and isn’t sharable across clients.

Put the classes in the jvm/lib/ext folder

Putting external JAR files in the jvm/lib/ext folder under your binary Notes directory affords you the same universal availability of the classes as the JavaUserClasses setting but without having to manually edit the notes.ini file. This possibility was introduced with Notes 6. Putting the classes in the jvm/lib/ext folder has some additional advantages when it comes to security but that’s for another post.

The table below shows the applicability of the different approaches.

td.center {
text-align: center;
}

Designer Notes Domino Replication Sharable Agent Web service Servlet
Include in agent + + + + +
Include in web service + + + + +
Script library + + + + + + +
JavaUserClasses + + + + + + +
jvm/lib/ext + + + + + + +

As the table shows it is important to note that the JavaUserClasses and jvm/lib/ext approach are specific to the local machine that is it doesn’t replicate. This means that all installations (clients and servers) must maintain the setting manually. This can really be a hassle and doesn’t lend itself for use in applications deployed to end users. The approaches are very usable for servers though.

The table also shows that classes imported into a specific agent are not sharable that is you have to import the JAR file in every agent that uses the classes thus you have to remember updating the JAR file in every agent if upgradering to a new version of the JAR file. It can be a strength though if different versions are required. I recommend avoiding this approach whenever possible. Use script libraries instead.

Finally only the JavaUserClasses and jvm/lib/ext approaches can be used to load classes for servlets running under the Domino servlet manager.

Conclusion

In conclusion you should pay attention to what you are trying to accomplish when choosing the location for the JAR files you depend on. Each approach has its strengths and weeknesses.

For most cases the preferred way is using Java script libraries.

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.