Home > Articles

  • Print
  • + Share This

Java Agents, Servlets, Applets, and Applications

The Java language can be used in several different contexts with Notes and Domino. In particular, you can use Java in agents, servlets, applets, and applications. Each of these different contexts interacts differently with the Domino environment, so let me explain these contexts. In Chapter 2, "Domino Designer and the Integrated Development Environment (IDE)," I told you about the differences between these types of programs and when each language could be used. I'd like to examine each of the Java contexts now in more detail.

Some of the main characteristics of these different types of programs are how they are created, how they are invoked, and how they are terminated. I'll describe these characteristics in each section.

Domino Java Agents

Java agents in Domino are really just special cases of the NotesThread class that we saw earlier. To create an agent, you extend the AgentBase class. However, the AgentBase class itself is just an extension of the NotesThread class, so without necessarily knowing it, your agent is also a NotesThread.

When I showed you how a NotesThread is started, I said that you need to provide only one routine, the runNotes method. When the NotesThread is started, the runNotes method is invoked automatically. In the special case of agents, however, the Notes system has some additional housekeeping chores to perform before it can start your code. So, in the case of agents, Notes commandeers the runNotes method, declares it final so you cannot use it, and substitutes the NotesMain method for your code. Here is how a Notes Java agent actually starts up:

  1. java.lang.Thread:start initializes the new thread environment and calls the thread's run method on the new thread.

  2. NotesThread:run initializes the Notes environment and calls AgentBase:runNotes.

  3. AgentBase:runNotes initializes the agent environment and calls your agent's NotesMain method.

  4. YourAgent:NotesMain is your agent code.

The AgentBase runNotes method sets up an AgentContext object and creates a Session object. Because your agent extends the AgentBase class, you can use this.getSession to get the Session object that was created by runNotes.

If we look at the code that is automatically produced by the Domino Designer IDE for a Java agent, it should now be very clear. Notice that the getSession call omits the this qualifier. You can use either this.getSession or just plain getSession. It is important to understand the shorthand and why you don't need to use the this qualifier. (It's because getSession is defined in AgentBase and your agent extends AgentBase, so in effect your agent is an AgentBase.) Here's the code:

import lotus.domino.*;

public class JavaAgent extends AgentBase {
  public void NotesMain() {
   try {
     Session session = getSession();
     AgentContext agentContext = session.getAgentContext();
     // (Your code goes here)

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

Your Java agent automatically terminates when your NotesMain method ends. After it ends, control is returned in the reverse order to AgentBase:runNotes and then NotesThread:run. When run finishes, the thread itself is finished.

Also notice in the automatically generated code that an AgentContext is obtained. The AgentContext includes information such as the effective username, the current database, and the set of unprocessed documents that the agent should handle, along with several other agent properties.

Remember that an agent can run on either the Notes client or a Domino server. When the agent is running on the Notes client, the effective user is the current workstation user ID. However, when the agent is running on the server, the effective user is the user who last signed the agent. In addition, via the agent properties, you can also set up the agent to run with the identity of a Web user.

You can run a Java agent on a Domino server via a URL. You do this from a Web browser with the following syntax:

http://server/database.nsf/agentname

The database must exist, of course, and the specified agent must be a shared agent within the database. To send output back to the Web user, you must create a PrintWriter object by getting it from the AgentBase object. Here is how you do that:

Session s = getSession();
AgentContext ac = s.getAgentContext();
PrintWriter pw = getAgentOutput(); // Get AgentOutput
pw.println("<h1>Hello World</h1>");  // Send output back to browser

For this to work, make sure that your agent is declared as a shared agent. Note that you can specify this choice only when the agent is created. After it's created, you cannot turn a nonshared agent into a shared agent. You make an agent shared by checking the checkbox directly beneath the agent's name in the Create Agent dialog box.

The capability to run an agent on the server is similar to the servlet capability. There are a few differences, however. First, an agent is stored within a Domino database. Because of this, it can be replicated and can travel along with the database to another server. In addition, Java agents use the Domino security model and are more secure than servlets. Agents are written by extending AgentBase as previously described, and you use a NotesMain method for your agent code.

Java Servlets

Java servlets are stored as Java class files and archive (JAR) files within a directory on the server. Servlets can be initialized and stay active within the Domino server. When resident, a servlet can process many requests in a multithreaded manner from several Web clients at once. The capability to remain in memory can provide servlets with an important performance advantage for certain applications. Because servlets might be handling many requests simultaneously, it is critical that servlets be threadsafe.

One common use for servlets is to access non-Domino databases via JDBC. You can also access Domino databases using the Java techniques described in previous sections. Servlets are an industry standard for server-side Java programming, whereas agents are Domino-specific. Servlets are typically implemented as extensions of the javax.servlet.http.HttpServlet class. There is a full discussion of servlets in Chapter 27, "Using IBM WebSphere for Java Servlets and Java Server Pages (JSP)."

Java Applets

An applet is a set of one or more Java classes that is downloaded to a Web browser and executed within the context of the JVM in the Web browser itself. Regular Java applets are independent of Notes and Domino. You can have Java applets that are created and served by a Web server, such as Domino or any other Web server.

Just as Domino Java agents are special cases of the Java Thread class, with release 5 of Notes and Domino you can have specialized Domino applets as well. Let me first describe a regular Java applet, and then I'll explain how Domino Java applets are different.

An applet in Java is actually invoked by the Web browser. There is no main method in a Java applet. In fact, there are four important methods in a Java applet: init, start, stop, and destroy. Here are their definitions:

  • void init()—This method is invoked when the applet is first loaded. It is called only once.

  • void start()—This method is invoked after the init method. It is also invoked when the page comes into view or the browser is restored from an icon view.

  • void stop()—This method is invoked when the page is left or when the browser is minimized into an icon.

  • void destroy()—This method is invoked when the applet is no longer required. It is called after the stop method.

For completeness, I should mention that a Java applet is not actually a base class. As a matter of fact, it is four layers down in the hierarchy. The upper layers are Component, Container, Panel, and Applet. In other words, Applet extends Panel, which extends Container, which extends Component. These classes can be found in the java.awt package.

If you are using the Java Swing classes, an additional class called JApplet is available. This is similar to the Applet class but uses the Swing classes rather than the standard user interface classes.

It is beyond my scope here to explain all these other classes, but you should be aware of them. Suffice it to say that these other classes deal with user-interface characteristics, such as layout and the graphical appearance of the applet. For more information on applets, see Chapter 15, "Developing Java Applets for Use with Domino."

Domino Java Applets

What exactly is a Domino Java applet? A regular applet that is served by a Domino server to a Web browser might qualify, but that is not what I mean by a Domino Java applet. A Domino Java applet is an applet that has the capability to access Domino objects. In other words, it can do everything that a normal applet can do, but it can also access Domino.

What does it mean to access Domino? This is an important question. Remember that a regular applet is a Java program running within the JVM in the Web browser. Consider this hypothetical case. Suppose you have the newest gadget, a Web-enabled television set. This TV is a pure Java machine. It has a Java Virtual Machine (JVM) installed and can download and execute Java programs, but it certainly isn't a personal computer. Can you execute a Domino Java applet? Yes. In your Web television set, you can access Domino databases, traverse views, and use a Java program to perform functions that you might have used LotusScript for previously.

It is important to understand the capabilities of a Domino Java applet and to understand how this type of applet differs from a regular, ordinary Java applet. Let's take a look at a Domino Java applet.

A Domino Java applet is similar in concept and implementation to a Domino Java agent. If we want to create a Domino Java applet, we must extend the AppletBase class. This is analogous to extending the AgentBase class for agents. After we have extended AppletBase, there are four important methods for our Domino Java applet:

  • void notesAppletInit()—This method is invoked when the applet is first loaded. It is called only once.

  • void notesAppletStart()—This method is invoked after the notesAppletInit method. It is also invoked when the page comes into view or the browser is restored from an icon view.

  • void notesAppletStop()—This method is invoked when the page is left or when the browser is minimized into an icon.

  • void notesAppletDestroy()—This method is invoked when the applet is no longer required. This method is called after the notesAppletStop method.

I'm sure that you can see the immediate similarity to the four methods that are defined for a regular applet. Just as in the case for agents, the four notesApplet methods correspond to the underlying methods. I should also mention that the regular init, start, stop, and destroy methods are declared final within AppletBase, so you are not allowed to override them, and you should not call them directly.

A few additional methods are in the AppletBase class. These methods are openSession, closeSession, and getSession. openSession calls getSession, and I don't think there is any additional function performed in openSession that does not also occur in getSession. Thus, you can probably consider them synonyms, but openSession and its counterpart closeSession are the preferred methods.

The openSession (and getSession) method is similar to the getSession method found in AgentBase. Remember that we need to have a Session object to access the Domino objects. After we have this Session object, we can pretty much traverse the entire object model hierarchy. There are two forms for openSession within AppletBase:

Session s = openSession();  // Anonymous access
Session s = openSession(String userid, String password);

The first of these methods is used for anonymous access, and in the second method, you pass the user ID and password strings.

When you are finished with the Session object, you can close it with closeSession.

closeSession(s);  // Close the previously opened Session.

The last method in AppletBase is the IsNotesLocal method. This routine returns true if the applet is running within a Notes client and is accessing a local database. It returns false if you are accessing a remote server.

If you are using the Java Swing classes, you can extend your applet from the JAppletBase class rather than the AppletBase class. The JAppletBase class supports an identical set of methods to the AppletBase class.

I have not described, until now, the magic that is used to implement Domino access from a Web-enabled television set. Hold on to your hats, here come the acronyms: CORBA and IIOP. These two technologies are important because they basically enable you to perform client/server computing, using Web browsers and Java over the Internet. The client can be any Java-enabled Web browser, and the server is Domino. I describe these technologies in more detail in Chapter 15.

Accessing Domino Databases from Java Applications

There are a couple of scenarios for accessing Domino from standalone Java applications. First, you can access local Domino databases if you have Java and the Notes executable files present on your computer. This will typically be the configuration on your desktop or laptop computer if you are using the Notes client.

Second, with those magic components CORBA and IIOP, you can create a standalone Java application that runs on your desktop but accesses a remote Domino server. In this case, all you need to have present on your local computer is a JVM and the appropriate archive files. You do not need to have the Notes executable files present.

In the earlier section, "Java Applications and Multithreading," I showed you the basics of standalone Java applications and how to initialize the Notes/Domino environment. As mentioned, a standalone application can extend NotesThread, or you can create a class that implements the Runnable interface. In either case, you must also have a static main routine. This main routine is invoked by the JVM machine. Here is an example of a Java program that extends NotesThread. This is an example that must run locally. It does not use CORBA or IIOP.

import lotus.domino.*;

public class MyNotesMain4 {
  public static void main(String args[ ]) {
   try {
    ExtendedThread etMyThread = new ExtendedThread(); // My Thread
    etMyThread.start(); // This will eventually invoke my runNotes();
    etMyThread.join();  // Wait for thread to finish
   }
   catch(InterruptedException e) {
   }
  }
}
public class ExtendedThread extends NotesThread {
  public void runNotes() {
   try {
     Session s = NotesFactory.createSession(); // Create a new Session
     String v = s.getNotesVersion(); // Notes version
     String p = s.getPlatform();   // Platform
     System.out.println("Running version " + v + " on platform " + p);
   }
   catch (Exception e) {
     e.printStackTrace();
   }
  }
}

Here is how this routine starts up:

  1. JVM calls MyNotesMain4:main, which creates an ExtendedThread, which extends NotesThread. The main then calls ExtendedThread:start (which is actually implemented in Thread:start).

  2. Thread:start (ExtendedThread:start) initializes the thread and calls ExtendedThread:run. Because ExtendedThread extends NotesThread, the run method is actually implemented in NotesThread:run.

  3. The NotesThread:run routine initializes the NotesThread environment and calls the ExtendedThread:runNotes method. This is where your code resides.

NOTE

Do not confuse the Thread:start routine with the Applet:start routine. Although they have the same method name, they are completely different methods. Thread:start is a system routine that starts a thread; Applet:start is an optional user-written routine invoked by a browser when an applet starts.

The following example uses CORBA and IIOP. This main program can run on a client that does not have the Notes executables locally.

import lotus.domino.*;

public class MyNotesMain5 {
  public static void main(String args[ ]) {
   try {
    RunnableThread rtMyThread = new RunnableThread(); // My Thread
    // NotesThread extends java.lang.Thread
    NotesThread theThread = new NotesThread(rtMyThread); 
    theThread.start(); // This will eventually invoke my run();
    theThread.join();  // Wait for thread to finish
   }
   catch(InterruptedException e) {
   }
  }
}
class RunnableThread implements Runnable {
  public void run() {
   try {
     String IOR = lotus.domino.NotesFactory.getIOR("ACMESERVER");
     System.out.println("IOR='" + IOR + "'");
     Session s = NotesFactory.createSessionwithIOR(IOR, 
     "John Doe/AcmeCorp", "secretpassword");
     String v = s.getNotesVersion(); // Notes version
     String p = s.getPlatform();   // Platform
     System.out.println("Running version " + v + " on platform " + p);
   }
   catch (Exception e) {
     e.printStackTrace();
   }
  }
}

This code is an example of the Runnable interface. The major point to notice in this example is the fact that we have a new variable called IOR. IOR stands for Interoperable Object Reference. The IOR is specified as a string. If you print it out, you'll notice that it is a huge hexadecimal string. This string is used to set up the CORBA communication between the client and the server. If you are debugging online, you'll also notice a fairly long delay when you create the Session because of all the CORBA initialization. After the CORBA initialization has finished, however, the application will run fairly quickly.

If you want to eliminate the need for the IOR, you can use the createSession method with the three parameters host, userid, and password. Here is the syntax:

Session s = NotesFactory.createSession(hostname, userid, password);

Hostname is the same parameter you pass to the getIOR method. The regular createSession method will obtain the IOR for you, making it a little easier to use.

The two examples MyNotesMain4 and MyNotesMain5 showed two different ways to create a standalone application. MyNotesMain4 created an inherited thread, and MyNotesMain5 created a Runnable class. You can use CORBA via either method.

One final note about this example: If you want to try this example yourself, you must substitute your server name, your user ID, and your password at the appropriate points in the program.

  • + Share This
  • 🔖 Save To Your Account

Related Resources

There are currently no related titles. Please check back later.