Java in Notes/Domino Explained: Test agents in Eclipse by extending AgentBase (part 4)


By now (I assume you read part 1, part 2 and part 3) we have a working AgentBase extension called EclipseAgentBase which is capable of detecting whether the code is running inside Notes/Domino (and hence use the AgentBase functionality supplied by IBM) or outside Notes/Domino. If running outside Notes/Domino we use some custom functionality to “bootstrap” the runtime environment.

In part 3 I showed how to return a Session object from the getSession() method and a PrintWriter from the getAgentOutput() method. The problem with the getSession() method is that the returned Session is unaware of the runtime environment and a call to getAgentContext() will return null which isn’t what we want. Since lotus.domino.Session is an interface we can simply create our own implementation to wrap the returned Session.

To do this we simply create a wrapper for our Session and return the wrapper. Having the wrapper implement the lotus.domino.Session interface makes the caller oblivious to the change (change from part 3 in bold):

public Session getSession() {
   try {
      if (this.pIsNotes) {
         return super.getSession();
      } else {
         if (null == this.pSession) {
            this.pSession = new SessionWrapper(NotesFactory.createSession());
         }
         return this.pSession;
      }
   } catch (NotesException e) {
      throw new RuntimeException("Unable to create session", e);
   }
}

The declaration of the SessionWrapper class is as follows:

private class SessionWrapper implements Session {
   // declarations
   private Session pSession = null;

   public SessionWrapper(Session session) {
      this.pSession = session;
   }
   ...
   ...
}


The only caveat is that we have to implement all the methods of the lotus.domino.Session interface (all 62 of them) which is quite tedious. But here Eclipse comes to the rescue. Once the class and the pSession member variable has been defined you can simply right click and select “Generate Delegate Methods” from the Source-submenu. This will make Eclipse generate stubs for all methods and make the actual call go to the pSession member variable.

In this way we only need to override the methods we atually need to. This is a big time saver.

Once we return a SessionWrapper object instead of the Session from NotesFactory.createSession() we can do what we need to in relation to the AgentContext. The only method I choose to override from the lotus.domino.Session interface is the getAgentContext() method. Again we are in luck since AgentContext is an interface so we can do this using an anonymous inner class (in bold):

public AgentContext getAgentContext() throws NotesException {
   return new AgentContext() {
      ...
   };
}

We have to implement the 16 methods of the AgentContext interface but we can simply use the “Override/Implement Methods” functionality to generate the stubs to save some time and typing. Once we have done this all the methods return either null or 0 which isn’t what we want. Instead delegate all method calls to callback-methods (starting with “callback”) in the top EclipseAgentBase class as shown below for the getCurrentAgent() method which delegates to the callbackGetCurrentAgent() method:

public abstract class EclipseAgentBase extends AgentBase {
   ...
   ...

   protected Agent callbackGetCurrentAgent() throws NotesException {
      return null;
   }

   private class SessionWrapper implements Session {
      // declarations
      private Session pSession = null;

      public SessionWrapper(Session session) {
         this.pSession = session;
      }

      public AgentContext getAgentContext() throws NotesException {
         return new AgentContext() {

            public Agent getCurrentAgent() throws NotesException {
               return callbackGetCurrentAgent();
            }
         };
      }
      ...
      ...
   }
}

The result of using the callback and just returning null is presently the same but using the callback gives us a lot of functionality as you’ll see in the next and final part of the series.

Java in Notes/Domino Explained: Test agents in Eclipse by extending AgentBase (part 3)


Suppose we have this new AgentBase implementation – what we really like is for it to revert back to the lotus.domino.AgentBase functionality whenever the agent is run inside Notes/Domino and only use our new AgentBase look-a-like whenever we run inside Eclipse. Part 2 discussed how to detect where the code is running so by now we have a member variable called pIsNotes that is true if inside Notes/Domino and false otherwise.

To “fool” the agent when running inside Eclipse we need to override the getSession() and the getPrintWriter() methods of the AgentBase class with an implementation that works in Eclise. If we don’t the agent will fail with a NullPointerException whenever the agent is run.

Using our pIsNotes member variable it is almost trivial to create a java.io.PrintWriter that maps to System.out and create a lotus.domino.Session using lotus.domino.NotesFactory whenever we are outside Notes/Domino. When inside Notes/Domino we simply call the super-implementation that is the code of the AgentBase class supplied by IBM:

public abstract class EclipseAgentBase extends AgentBase {
   // declarations
   private boolean pIsNotes = false;
   private Session pSession = null;

   {
      try {
         Class.forName("lotus.domino.servlet.DominoSessionContext");
         this.pIsNotes = true;
      } catch (ClassNotFoundException e) {
         // ignore - we're not in Notes/Domino
      }
   }

   public abstract void NotesMain();

   protected boolean isNotes() {
      return this.pIsNotes;
   }

   public PrintWriter getAgentOutput() {
      try {
         if (this.pIsNotes) {
            return super.getAgentOutput();
         } else {
            return new PrintWriter(new OutputStreamWriter(System.out, "ISO-8859-1"));
         }
      } catch (Exception e) {
         throw new RuntimeException("Unable to convert System.out to PrintWriter", e);
      }
   }

   public Session getSession() {
      try {
         if (this.pIsNotes) {
            return super.getSession();
         } else {
            if (null == this.pSession) {
               this.pSession = NotesFactory.createSession();
            }
            return this.pSession;
         }
      } catch (NotesException e) {
         throw new RuntimeException("Unable to create session", e);
      }
   }
   ...
   ...
}

In the next part we’ll dive a little deeper by looking at a crucial part we are missing – the AgentContext returned by the Session object. At present it simply returns null which won’t work when testing agents.

Stay tuned.

Java in Notes/Domino Explained: Test agents in Eclipse by extending AgentBase (part 2)


Part 1 discussed the need for a new base class for “Imported Java”-agents by extending the lotus.domino.AgentBase class to allow writing, testing and debugging agents from within Eclipse. Suppose we have this new AgentBase implementation – what we really like is for it to revert back to the lotus.domino.AgentBase functionality whenever the agent is run inside Notes/Domino and only use our new AgentBase look-a-like whenever we run inside Eclipse. To do this we need to detect where the code is running.

There are really not that many ways to detect whether the code is running inside Notes/Domino or Eclipse for that matter. My first choice was to look for a System property and found a property called package.restrict.definition.lotus.notes that would allow me to detect whether the code was running inside Notes/Domino. Using this property I could set a flag in the base class that I could query later on:

public abstract class EclipseAgentBase extends AgentBase {
   // declarations
   private boolean pIsNotes = false;

   {
      String prop_name = "package.restrict.definition.lotus.notes";
      this.pIsNotes = (null != System.getProperty(prop_name));
   }
   ...
   ...
}

The “strange” construct I use to initialize this pIsNotes member variable is called an initializer. If you would like to learn more about initializers I can recommend an article at Javaworld.com.

There is a problem with using System properties in Notes/Domino since you are only allowed to query a subset of them without having access to restricted operations. Strange but true… This meant I had to scratch that approach since I would really like an approach viable for all agents without requiring restricted access.

I finally settled on using the availability of a class for my detection. Since the Domino Servlet Container classes are only available inside Notes/Domino I could use a class from there. I settled on the DominoSessionContext class from the lotus.domino.servlet-package. The Domino Servlet Container classes are also available in agents since the dservlet.jar is placed in jvm/lib/ext. The detection is now as simple as trying to load the class:

public abstract class EclipseAgentBase extends AgentBase {
   // declarations
   private boolean pIsNotes = false;

   {
      try {
         Class.forName("lotus.domino.servlet.DominoSessionContext");
         this.pIsNotes = true;
      } catch (ClassNotFoundException e) {
         // ignore - we're not in Notes/Domino
      }
   }
   ...
   ...
}

In this case a java.lang.ClassNotFoundException simply means that the classloader cannot find the class hence we are outside Notes/Domino. Simple but it works.

Java in Notes/Domino Explained: Test agents in Eclipse by extending AgentBase (part 1)


This post way sparked by a post in the Notes/Domino forum on developerWorks.

Let me start by saying that you could probably use the AgentRunner if you can figure it out and if it still works. I haven’t used it for a LONG time and I doubt that it still works with the changes made to the Java API in Notes/Domino 6.x and 7.x. The Using Document of the AgentRunner database hasn’t been updated since 1999!! Anyways – there are other options.

Write the code in a separate class hierarchy

The first one is to write the agent functionality in separate classes and then have the agent code call these classes to do its job. This is a viable approach though it means you have to maintain the actual business code and the agent code in separate places (the business code in Eclipse and the agent code in Notes/Domino).

Extend lotus.domino.AgentBase

Another option is to extend the AgentBase class and implement some of the intializing functionality yourself for testing. The approach isn’t optimal and still makes you implement some boilerplate code but it’s a start and a viable option for writing and testing your agents in Eclipse. The new AgentBase class can be made to detect whether it runs inside Eclipse or inside Notes/Domino so it’s easy to move the code into Notes/Domino once it works.

The boilerplate code has to do with initializing a thread to Notes in a main() method before calling the NotesMain() method of your agent class. The below example shows the required boilerplate code for the ExampleAgent1 class:

public static void main(String[] args) {
   try {
      NotesThread.sinitThread();
      new ExampleAgent1().NotesMain();

   } catch (Exception e) {
      e.printStackTrace();
   } finally {
      NotesThread.stermThread();
   }
}

The new AgentBase class (called EclipseAgentBase) means you can write agents in Eclipse. The only change is that you extend EclipseAgentBase instead of AgentBase:

import lotus.domino.NotesThread;
import lotus.domino.Session;

public class ExampleAgent1 extends EclipseAgentBase {

   public static void main(String[] args) {
      try {
         NotesThread.sinitThread();
         new ExampleAgent1().NotesMain();

      } catch (Exception e) {
         e.printStackTrace();
      } finally {
         NotesThread.stermThread();
      }
   }

   public void NotesMain() {
      try {
         Session session = this.getSession();
         System.out.println("Username: " + session.getUserName());
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}

In the next part of the post I’ll dive into how do build the EclipseAgentBase class.

Java in Notes/Domino Explained: Visibility modifiers


The Java programming language has 4 access modifiers:

  • public
  • private
  • protected
  • (none) aka “friendly”

Below I’ll tell you a little about each of the modifiers.

Modifier Description
public This is the least restrictive of the modifiers and it should be understood as literal as the word. Member variables and methods are visible to code inside and outside the class independent on class inheritance hierarchy and package.
private This is the most restrictive of the modifiers. Member variables and methods are private to the inclosing class and isn’t visible to any code outside the class itself. Variables and methods marked private are however visible to inner classes.
protected Protected is somewhere in between public and private and means that the variable or method is visible to the inclosing class and its subclasses. This makes it very usable when designing class hierarchies since it allows you to put code in a generic super class without making it visible to outside classes.
(none) aka “friendly” Leaving out the modifier gives the variable or method the same properties as a public variable or method but only inside the same package. This is beneficial if you are designing an API and you need some public methods that shouldn’t be exposed to outside code. Be aware that there isn’t any mechanism for disallowing programmers to create new classes in your packages so caution should still be exhibited when using the “friendly” modifier.

Java in Notes/Domino Explained: Testing for equality


When comparing strings in Java you are actually comparing the objects and not the string itself. If you read my resent post on common operators in Java you would have read the following explanation for the == operator: “Test for object reference equality or equality of primitive data types.”

So what does “object reference equality” mean? It means that the == operator will object return true if the references are pointing to the same object. It doesn’t look inside the object or make any assertations as to whether the “real world” value of the objects are the same. The below example should clarify:

String s1 = new String("lekkimworld");
String s2 = new String("lekkimworld");
String s3 = s1;
String s4 = s2;
System.out.println(s1 == s2);
System.out.println(s1 == s3);
System.out.println(s2 == s4);
System.out.println(s1 == s4);

The above code will provide the following output:

false
true
true
false

The above output shows you that the string s1 and s2 are different references and hence are not equal in the == sense. Once we create s3 and s4 pointing to s1 and s2 respectively, == return true since s1/s3 and s2/s4 are pointing to the same object.

So the rule of thumb is: Only use == to compare primitive datatypes (int, long etc.) or objects if you need to see if it is the same object (being referenced) – not necessarily the same value.

It’s actually a more general problem

To alleviate the problem of comparing references all objects in Java has a method called equals. The method is inherited from java.lang.Object, from which all classes inherit, and if not overridden by the class will revert to using the == operator for comparisons.

The String class overrides the equals() method to test whether the value of the strings are the same. Since the equals() method is case sensitive the String class also have an equalsIgnoreCase() method. Let’s see the equals() method in action:

String s1 = new String("lekkimworld");
String s2 = new String("lekkimworld");
String s3 = s1;
String s4 = s2;
System.out.println(s1.equals(s2));
System.out.println(s1.equals(s3));
System.out.println(s2.equals(s4));
System.out.println(s1.equals(s4));

The above code will provide the following output:

true
true
true
true

Notice the difference between the output of this code and the code in the first example. Now we test the “real world” value of the objects hence all comparisons are true.

The concept of the equals() method carry across to custom objects you write. If you plan to test if two objects are the same, which is almost always the case, you should override the equals() method. Let me show how this works in the case of a simple Employee class. I have decided that comparisons should be based on the employee id and not the name:

public class Employee {
   private String id = null;
   private String firstname = null;
   private String lastname = null;

   public Employee(String first, String last, String id) {
      this.firstname = first;
      this.lastname = last;
      this.id = id;
   }

   public boolean equals(Object obj) {
      // if null it can never be the same
      if (null == obj) return  false;

      // if of another type if can never be the same
      if (!(obj instanceof Employee)) return false;

      // same class - compare
      return ((Employee)obj).getId().equals(this.id);
   }

   public String getFirstname() {
      return firstname;
   }
   public String getId() {
      return id;
   }
   public String getLastname() {
      return lastname;
   }
}

Notice how I start by verifying that the supplied object isn’t null and that it is of the same type. If not the objects can never be equal. If both the supplied object passes both tests I use the equals() method of the String class to compare the ids. Below is a snippet of code to illustrate:

Employee e1 = new Employee("John", "Doe", "111");
Employee e2 = new Employee("Jane", "Doe", "222");
Employee e3 = new Employee("John", "Doe", "111");
System.out.println(e1 == e2);
System.out.println(e1 == e3);
System.out.println(e1.equals(null));
System.out.println(e1.equals(new String("lekkimworld")));
System.out.println(e1.equals(e2));
System.out.println(e1.equals(e3));

…and the output

false
false
false
false
false
true

Pay special notice to the fact that e1 == e3 returns false since it is different objects. Only our own custom equals() method will return true.

Did you notice? – the caveat about strings in Java

The astute reader might have noticed that I used the new keyword to create new strings in the first example instead of the “normal” approach:

String s1 = new String("lekkimworld");
instead of
String s1 = "lekkimworld";

The result will actually be quite different if you use the latter approach instead:

String s1 = "lekkimworld";
String s2 = "lekkimworld";
String s3 = s1;
String s4 = s2;
System.out.println(s1 == s2);
System.out.println(s1 == s3);
System.out.println(s2 == s4);
System.out.println(s1 == s4);

The above code will produce the following output:

true
true
true
true

Isn’t that wierd? To understand it we need to dive a little deeper into how strings are managed in Java.

How strings are managed in Java

In Java strings are imutable that is they cannot change once created. If you concatenate two strings the result will be the creation of a new third object:

String full = "Mikkel " + "Heisterberg";

The problem is actually due to the fact that we cannot redimension arrays in Java (the char[] array that backs the string object) as described in an earlier post. You can imagine that concatenating a lot of strings can yield quite a lot of objects. To alleviate this potential performance problem you can use the java.lang.StringBuffer class.

Since strings are used so much and because they are imutable the String class holds an internal pool of created Strings (a “cache” if you will). It can hold on to the previously created strings since the imutable property makes the class thread-safe and hence safe to reuse. It also means that if you create the same string twice the String class will return the cached object the second time around. This isn’t the case when using the new keyword which is why there is a difference between the examples above.

So what do you do if the returned string was created using the new keyword but you really want the one from the string pool? Well you’re in luck – you can use the intern() method of the String class:

String s1 = "lekkimworld";
String s2 = "lekkimworld";
String s3 = new String("lekkimworld");
System.out.println(s1 == s2);
System.out.println(s1 == s3);
System.out.println(s2 == s3);

String s4 = s3.intern();
System.out.println(s1 == s4);

This will produce the following output:

true
false
false
true

The last line is true since the intern() method returns the copy of “lekkimworld” from the string pool and not the one from the s3 object. Normally you don’t have to spend too much time thinking about the intern() method but now you know… 🙂

Happy comparisons…

Java in Notes/Domino Explained: Operators


Java has a series of operators that can make the code less verbose, quicker to write and more readable. Below is a table of the most commonly used operators and an explanation of how to use them. At the bottom of the post you’ll find all the code if you want to play around with it.

Operator Description
== Test for object reference equality or equality of primitive data types.

int i=1;
int j=1;
System.out.println(i == j);
Output: true

String s1 = "lekkim";
String s2 = "lekkimworld";
System.out.println(s1 == s2);
Output: false

System.out.println(s1 == s1);
Output: true
!= Test for object reference non-equality or non-equality of primitive data types.

int i=1;
int j=2;
System.out.println(i != j);
Output: true

String s1 = "lekkim";
String s2 = "lekkimworld";
System.out.println(s1 != s2);
Output: true

System.out.println(s1 != s1);
Output: false
&& Logical AND operator.

boolean b1 = true;
boolean b2 = true;
System.out.println(b1 && b2);
Output: true
|| Logical OR operator.

boolean b1=true;
boolean b2=false;
System.out.println(b1 || b2);
Output: true
++ This operator can mean two things depending on which side of the variable the operator is on.

If the operator is to the right of the variable it means to use the value of the variable, increment the value and then store result back in the same variable.

int i=0;
System.out.println("i=" + (i++));
Output: i=0
System.out.println("i=" + (i++));
Output: i=1

If the operator is to the left of the variable it means that the JVM should increment the variable, use the variable and store the result back in the variable.

int i=0;
System.out.println("i=" + (++i));
Output: i=1
System.out.println("i=" + (++i));
Output: i=2

Much used in for-loops:

for (int i=0; i<3; i++) {
  System.out.print(i + " ");
}
Output: 0 1 2
Same as ++ but subtracting instead of incrementing.

int k=2;
System.out.println("k=" + (k--));
Output: k=2
System.out.println("k=" + (k--));
Output: k=1

int k=2;
System.out.println("k=" + (--k));
Output: k=1
System.out.println("k=" + (--k));
Output: k=0

Can also be used in for-loops:

for (int i=2; i>=0; i--) {
  System.out.print(i + " ");
}
Output: 2 1 0
+= Evaluate the + operator using the value in the variable on the left hand side and the right hand side and store result back in the same variable.

String s1 = "Mikkel";
s1 += " ";
s1 += "Heisterberg";
System.out.println("s1=" + s1);
Output: s1=Mikkel Heisterberg
-= Evaluate the – operator using the value in the variable on the left hand side and the right hand side and store result back in the same variable.

int i=10;
int k=5;
i -= k;
System.out.println("i=" + i);
Output: i=5

Below is the code for the above examples if you want to play around with it:

public class Main {

   public static void main(String[] args) {
      equal_equal();
      exclamation_equal();
      ampersand_ampersand();
      pipe_pipe();
      plus_plus1();
      plus_plus2();
      plus_plus3();
      minus_minus1();
      minus_minus2();
      minus_minus3();
      plus_equal();
      minus_equal();
   }

   public static void equal_equal() {
      int i=1;
      int j=1;
      System.out.println(i == j);

      String s1 = "lekkim";
      String s2 = "lekkimworld";
      System.out.println(s1 == s2);
      System.out.println(s1 == s1);
   }

   public static void exclamation_equal() {
      int i=1;
      int j=2;
      System.out.println(i != j);

      String s1 = "lekkim";
      String s2 = "lekkimworld";
      System.out.println(s1 != s2);
      System.out.println(s1 != s1);
   }

   public static void ampersand_ampersand() {
      boolean b1 = true;
      boolean b2 = true;
      System.out.println(b1 && b2);
   }

   public static void pipe_pipe() {
      boolean b1=true;
      boolean b2=false;
      System.out.println(b1 || b2);
   }

   public static void plus_plus1() {
      int i=0;
      System.out.println("i=" + (i++));
      System.out.println("i=" + (i++));
   }

   public static void plus_plus2() {
      int i=0;
      System.out.println("i=" + (++i));
      System.out.println("i=" + (++i));
   }

   public static void plus_plus3() {
      for (int i=0; i=0; i--) {
         System.out.print(i + " ");
      }
      System.out.println("");
   }

   public static void plus_equal() {
      String s1 = "Mikkel";
      s1 += " ";
      s1 += "Heisterberg";
      System.out.println("s1=" + s1);
   }

   public static void minus_equal() {
      int i=10;
      int k=5;
      i -= k;
      System.out.println("i=" + i);
   }
}

Java in Notes/Domino Explained: Security 201


As of Notes 6.x the JVM installed with Notes/Domino is a real Java 2 virtual machine which means that you have greater control over how security is handled. As mentioned previously you cannot install your own SecurityManager but you have the possibility to grant or restrict which access third-party libraries get.

As mentioned in my post called “Managing external Java dependencies in Domino Designer” you have a directory called jvm/lib/ext under your binary Notes/Domino directory. This directory can be used to install third-party or custom libraries which will always be on the classpath of Notes/Domino. What you maybe did not know is that the libraries placed in this directory is granted all permissions which means that they can really wreak havok on your system if they are malicious.

The permissions granted to external JAR-files in Notes/Domino are controlled through two files that are located in the jvm/lib/security directory called java.security and java.policy. The java.security file is a property file for classes in the java.security package – there is no need to worry about this file unless you start installing custom cryptographic extensions or modify the ones that are installed by default. The other file, java.policy, is however very usable and it is here you can control which permissions individual libraries get. This file is used by the installed SecurityManager to decide which operations to allow.

Below is a snippet from the default java.policy file:

// Standard extensions get all permissions by default
grant codeBase "file:${java.home}/lib/ext/*" {
	permission java.security.AllPermission;
};

// Notes java code gets all permissions
grant codeBase "file:${notes.binary}/*" {
	permission java.security.AllPermission;
};

As you can see above the java.security.AllPermission permission is granted to all the files in jvm/lib/ext and to all files in the binary Notes/Domino directory. You can refer to the Javadocs for indepth information on java.security.AllPermission but suffice it to say that it allows everything. The syntax of the java.policy file also allows you to grant permissions if a library is digitally signed (see below for a link to a page describing the syntax of the java.policy in detail).

The java.security.AllPermission is a lot of access to any given library and it shouldn’t be granted lightly. Consider the source of the library, who compiled it and what the library should do before granting access. As always only grant the access that is actually needed – don’t just give java.security.AllPermissions because it is easier…

java.security.AllPermission shouldn’t be granted lightly…
There are a host of other types of permissions that may be granted (see the sub-classes of java.security.Permission) incl. access to reading and writing specific files or directories to access to network resources etc. In fact the java.security.FilePermission is probably the permission most commonly used since it allows you to grant a library access to files in a specific directory. Using java.security.FilePermission you can distinguish between reading, writing and executing files.

This is a point where Java allows you much more fine grained control than LotusScript. In LotusScript you have access to I/O or you don’t – in Java you can actually control which files a library may work with.

That is all for now. The next and final installment on security will discuss how third-party libraries actually use the permissions granted to them by the SecurityManager.

Further reading

Java in Notes/Domino Explained: Security 101


As a Notes/Domino programmer you are probably familiar with the fact that the agent manager (AMgr) distinguishes between operations consider restricted and those considered unrestricted. Among restricted operations are those that access the file system, set the system clock etc. Whether an agent is allowed to use restricted operations are based on settings in two different locations:

  • Whether the signer is granted access to restricted operations on the Security tab of the server document.
  • Whether the agent is set to allow restricted operations on the second tab of the agent properties.

The default setting in the agent properties is not to allow access to restricted operations.

When running Java agents the access to restricted operations are governed by a SecurityManager “installed” (configured) when the JVM is initialized and before the NotesMain() method of the agent is invoked. Once a SecurityManager has been installed in the JVM (using the setSecurityManager() method of the java.lang.System class) a new one cannot be set. If you try a java.lang.SecurityException is thrown. This guarantees that the default installed SecurityManager cannot be replaced at runtime.

A SecurityManager is a class extending java.lang.SecurityManager. If a SecurityManager is installed in the JVM it is asked before a security sensitive operation is executed. The SecurityManager then has the option of overruling the execution of the operation by throwing a java.lang.SecurityException.

The following types of operations are controlled by the SecurityManager in agents:

  • The ability to read files on disk
  • The ability to write files on disk
  • The ability to access the network
  • The ability to work with class loaders
  • The ability to execute external programs
  • The ability to use Java classes calling with native code
  • The ability to access system properties

The Java API of Notes/Domino contains two different SecurityManagers – one for agents and one for servlets. The SecurityManager for agents is COM.ibm.JEmpower.applet.AppletSecurity and the SecurityManager for servlers is lotus.notes.AgentSecurityManager. Both inherit directly from java.lang.SecurityManager.

Java in Notes/Domino Explained: Casting 101


To discuss and understand casting you must know that when you instantiate an object in Java you create an object on the heap and a reference to the object on the stack. In your Java agents you only have direct access to what’s on the stack which means that what you manipulate in your code are the references. Since you do not work with the objects on the heap directly the reference on the stack must tell the JVM which type of object is at the memory location pointed to on the heap.

Casting means taking an existing object reference and making it of another type. When most Java developers talk about casting they refer to “casting objects” which strictly speaking is wrong. It is however one of those things you learn to live with… 🙂

A simple example

As you might know every class in Java ultimatively inherits from java.lang.Object which means that a java.lang.Object reference can point to anything (much like a Variant in LotusScript). This means that you can always cast an object to java.lang.Object since it is a more generic type.

However you cannot store a java.lang.Object reference in a java.lang.String reference without casting since String is more specific than Object. As you can see I have to cast the obj reference to a String reference in line 3. If I don’t the code wont compile.

String sample1 = "This is my string..."; // create a String
Object obj     = sample1;                // store String in java.Object reference
String sample2 = (String)obj;            // we must cast to store an Object in a String
                                         // reference

To sum up you need to cast when refering to an object with a more specific reference than the current reference.

When casting references you may encounter the java.lang.ClassCastException which is an unchecked exception. This exception is the way the JVM can signal that you are doing an illegal cast for example casting a lotus.domino.Document to a lotus.domino.Database.

Knowing when it’s okay to cast

So how do you check if a cast is legal? Well apart from knowing which references you are dealing with you can use the instanceof keyword. The below example checks that the object really does inherit from lotus.domino.RichTextItem before casting:

// declarations
RichTextItem rt = null;
Item item = null;

// get document
Document doc = db.getDocumentByUnid("<some unid>");

// loop all items and put them into an ArrayList
Vector items = doc.getItems();
for (int i=0; i<items.size(); i++) {
   // get next element from the Vector (returns java.lang.Object)
   Object obj = items.elementAt(i);

   // is the item a RichTextItem?
   if (obj instanceof RichTextItem) {
      // yes it is - cast it as such
      rt = (RichTextItem)obj;
   } else {
      // nope - cast it as an Item
      item = (Item)obj;
   }
}

The above example is equivalent to the below code exept that I use the ClassCastException to find out that the cast is invalid.

// declarations
RichTextItem rt = null;
Item item = null;

// get document
Document doc = db.getDocumentByUnid("<some unid>");

// loop all items and put them into an ArrayList
Vector items = doc.getItems();
for (int i=0; i<items.size(); i++) {
   // get next element from the Vector (returns java.lang.Object)
   Object obj = items.elementAt(i);

   try {
      // try to cast as RichTextItem
      rt = (RichTextItem)obj;

      // coming here means that the item is a RichTextItem
      ...
   } catch (ClassCastException e) {
      // not a RichTextItem - cast it as an Item
      item = (Item)obj);
   }
}