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.

14 thoughts on “Imported Java agent”

  1. Because of your help, I created the Java Agent and imported my jar file, I have one more question, In my base class I am getting information from XML file and I also impoted the xml file, but getting following error,
    2006-03-01 19:00:33,781 INFO main.EdvisorToBlueGroup (EdvisorToBlueGroup.java:62) – START ………….

    2006-03-01 19:00:33,981 FATAL main.EdvisorToBlueGroup (EdvisorToBlueGroup.java:89) – Configuration Error: Invalid properties file!

    2006-03-01 19:00:33,981 INFO main.EdvisorToBlueGroup (EdvisorToBlueGroup.java:90) – System terminates with errors.

    java.lang.SecurityException: Exit with code 0

    at COM.ibm.JEmpower.applet.AppletSecurity.failSecurity(AppletSecurity.java:573)

    at COM.ibm.JEmpower.applet.AppletSecurity.failSecurity(AppletSecurity.java:563)

    at COM.ibm.JEmpower.applet.AppletSecurity.checkPermission(AppletSecurity.java:1416)

    at COM.ibm.JEmpower.applet.AppletSecurity.checkPermission(AppletSecurity.java:1386)

    at java.lang.SecurityManager.checkExit(SecurityManager.java:785)

    at java.lang.Runtime.exit(Runtime.java:119)

    at java.lang.System.exit(System.java:746)

    at com.ibm.cal.edvisor.tstb.main.EdvisorToBlueGroup.NotesMain(EdvisorToBlueGroup.java:36)

    at lotus.domino.AgentBase.runNotes(Unknown Source)

    at lotus.domino.NotesThread.run(NotesThread.java:218)

    Error cleaning up agent threads

    Here is part of my java class..
    private static Logger logger = Logger.getLogger(EdvisorToBlueGroup.class);
    private static final String DEFAULT_CONFIG = “configuration.properties”;
    private String configurationFile = DEFAULT_CONFIG;

    private final static int SYSTEM_SUCCESS = 0;
    private final static int FATAL_SYSTEM_ERROR = 1;

    /**
    * The facade method that should be called to use Edvisor To Blue Group.
    * @return system return code
    */
    public int execute() {
    DatabaseAccessController database = null;
    Iterator trackIDsIterator = null;
    int applicationRetries = 0;
    int applicationWaitTime = 0;

    try {
    logger.info(“START ………….”);
    ConfigurationReaderBean prop = new
    ConfigurationReaderBean(getConfigurationFile());
    logger.info(“START 1 ———————“);

    logger.info(“Configuration properties file loaded.”);

    ResourceFactory.getInstance().createObject(prop);
    logger.info(“End ……………..”);
    logger.info(“START 2 ———————“);

    logger.info(“Resource file loaded.”);
    Resource resource = ResourceFactory.getInstance().getResource();
    logger.info(“START 3 ———————“);
    DatabaseAccessFactory.getInstance().createObject(resource);
    logger.info(“START 4 ———————“);
    logger.info(“Database access created.”);
    logger.info(“START 5 ———————“);
    database =
    DatabaseAccessFactory.getInstance().getDatabaseAccessController();
    trackIDsIterator = resource.getTrackIDs();
    applicationRetries = resource.getApplicationRetries();
    logger.info(“Application retries for each track ID: ” +
    applicationRetries);
    applicationWaitTime = resource.getApplicationWaitTime();
    logger.info(“Application wait time between each retry for each track ID:” + applicationWaitTime);
    } catch (ConfigurationException ce) {
    logger.fatal(“Configuration Error: ” + ce.getMessage());
    logger.info(“System terminates with errors.”);

    Thanks for all help..
    Lisa John

  2. You have to understand that Domino agent runs under a specialized Java SecurityManager (COM.ibm.JEmpower.applet.AppletSecurity) that enforces the agent security model. The SecurityManager for example enforce that you cannot read or write a file on disk from an agent not allowed access to restricted operations (see the second tab of the agent properties). It also enforce that you do not use operations that are illegal from a Domino point of view such as System.exit().

    My recommendation is to set the agent to run with full priviledges for starters to see if that solves the problem. That is normally the easiest way to see if the problems are SecurityManager related. In your case I guess they are due to the reference to COM.ibm.JEmpower.applet.AppletSecurity in the stacktrace.

    You cannot install your own SecurityManager so don’t even try to go down that path… 🙂

    /lekkim

  3. Hi Lekkim
    Thanks for your in-depth response.
    For the agent i am using the following setting for Security.

    Set Runtime Security Level: 3. Allow Restricted Operations with full administration right.

    Default access for viewing and running this agent: checked ->All readers and above

    Checked->All public Access user to view and run this agent

    One question, When I was running this Java Utility using batch file from command prompt, I was using the xml for resource. Following is XML file.

    ———————

    LOCAL
    Lead_ops_rx_copy.nsf
    bluepages.ibm.com;
    bluegroups.ibm.com
    10
    10
    true
    3
    60

    30

    true

    87256E670071031B
    true
    My Basic Blue Group
    ljohn@Lever.com

    12345
    0
    2006
    12
    31

    —————————-

    and following is configuraiton.properties file

    ………………….

    # This configuration is to determine what kind of
    # resource will be used to configure the system.
    # Currently only XML resource file is supported.

    # Only XML resource is supported
    ConfigurationReader.Resource.Type=XML
    # The following two fields are for future extensions
    ConfigurationReader.Resource.Server=
    ConfigurationReader.Resource.Path=
    # This file is the path/filename of the resource
    ConfigurationReader.Resource.File=C:/EdvisorToBlueGroup/resource.xml

    …………………………..

    If you see the error after the line
    (EdvisorToBlueGroup.java:62) – START …………. 2006-03-01 19:00:33,981 FATAL

    It look like it is not reading the XML and I included the xml in jar file, but some how when running the agent it not reading the info from the XML,
    could you please let me know how it can read xml in java agent, should it different in Notes then stand alone java apps.

    Thanks for help.

  4. Well there is nothing special about reading property or xml-files from a Java agent as long as the file is packaged with the agent. You simply load the resource as a stream (see text in bold):

    import lotus.domino.*;
    import java.util.*;
    import java.io.*;
    
    public class JavaAgent extends AgentBase {
    
       public void NotesMain() {
    
          try {
             Session session = getSession();
             AgentContext agentContext = session.getAgentContext();
    
             Properties p = new Properties();
             InputStream in = this.getClass().getClassLoader().getResourceAsStream("lekkim.properties");
             p.load(in);
    
             System.out.println(p.getProperty("firstname") + " " + p.getProperty("lastname"));
    
          } catch(Exception e) {
             e.printStackTrace();
          }
       }
    }
    

    This is code from a standard Java agent not allowed to use restricted operations and it runs without any issues. I have simply added a properties file (lekkim.properties) to the agent using the “Edit Project” button. I’m using a normal Java agent to test this.

    My guess is that the stacktrace you are seeing is not from trying to read the files but from another source. If you look at the stacktrace the problem is your call to java.lang.System.exit() which is illegal in Notes.

    If it was me I would break down the agent into some smaller parts and make sure that you can read the properties file correctly. Then try using your bean to get and parse the xml-file. Take small steps to get acquinted with the environment.

  5. Hi Lekkim
    With you suggestion I removed the
    System.exit().
    and now I am not getting any error related to security.
    But now I am getting the
    “Error cleaning up agent threads” error
    and I treid to figure out class where I am getting, but I am unable to found the class, do please put some light on this error.
    Thanks a lot.
    Lisa

  6. Your agent is probably is creating some additional threads to the one (NotesThread) created as part of extending lotus.domino.AgentBase. If you have multiple threads in your agent make sure that the one creating the lotus.domino.Session class is the last one to be terminted. One solution is to use a separate ThreadGroup.

    The error normally occurs because a thread is still running when the Domino Amgr is terminating the agent thread.

    /lekkim

  7. Hi Lekkim
    In my previous mail, I mention that while connecting to ssl site I am getting error and following is error

    java.lang.SecurityException

    java.lang.SecurityException

    at java.lang.SecurityManager.checkPermission(SecurityManager.java:603)

    at COM.ibm.JEmpower.applet.AppletSecurity.checkSecurityPermission(AppletSecurity.java:1265)

    at COM.ibm.JEmpower.applet.AppletSecurity.checkPermission(AppletSecurity.java:1450)

    at COM.ibm.JEmpower.applet.AppletSecurity.checkPermission(AppletSecurity.java:1386)

    at java.lang.SecurityManager.checkSecurityAccess(SecurityManager.java:1711)

    at java.security.Provider.check(Provider.java:356)

    at java.security.Provider.put(Provider.java:318)

    at com.ibm.jsse.JSSEProvider.(Unknown Source)

    at com.ibm.swat.password.cwa2.(cwa2.java:68)

    at com.ibm.cal.edvisor.tstb.bluegroup.BlueGroupConnection.(BlueGroupConnection.java:35)

    at com.ibm.cal.edvisor.tstb.bluegroup.BlueGroupRequest.(BlueGroupRequest.java:43)

    at com.ibm.cal.edvisor.tstb.bluegroup.BlueGroupUpdate.executeUpdate(BlueGroupUpdate.java:50)

    at com.ibm.cal.edvisor.tstb.main.EdvisorToBlueGroup.execute(EdvisorToBlueGroup.java:123)

    at com.ibm.cal.edvisor.tstb.main.EdvisorToBlueGroup.NotesMain(EdvisorToBlueGroup.java:35)

    at lotus.domino.AgentBase.runNotes(Unknown Source)

    at lotus.domino.NotesThread.run(NotesThread.java:218)

    Could you please look into it.
    Regards
    Lisa

  8. Hi Lekkim
    I will appreciate if you provide the answer to the following questions about java agent.
    1) When using the Edit Project button and looking for Shared Java Libraries the list of databases points to my local machine. How do I get this list to point to the Server on which I am developing? I need this so we can shared code for all developers to use.

    2) Using the Edit project I added all the jar files and compile the agent, then still I need to add the JavaUserClasss parameter in Notes.ini or I need to put the jar files in ext folder in server.

    3) I have the XML file in file system, which I impoted in agent , how I can use the xml file using the notes form and create the xml from notes.
    Thanks for the help.

  9. Lisa I get this question quite a lot so I’ll write a blog post about the issue about where the different Java class files should go tonight or over the weekend. Hope that is ok.

  10. Hi Lekkim
    Did you have a time to write some thing about following……..I don’t want to be pushy

    When using the Edit Project button and looking for Shared Java Libraries the list of databases points to my local machine. How do I get this list to point to the Server on which I am developing? I need this so we can shared code for all developers to use.

    Thanks
    Lisa

  11. Well I wrote a piece on managing external dependencies which is basically what you’re asking about.

    You cannot share script libraries among different databases, that is databases with different replica id. There are of causes ways around this but using the normal approach it isn’t possible. If using the same database the list of script libraries should be the same on the server as on the local machine unless you did something with your replication.

Comments are closed.