Reg Exp
Web Design
Notes Client
Run Java Agent In 3 Environments
Some of the work I've been doing lately has involved scheduled Java agents. But some of these agents I also wanted to be able to run manually. So I set up the agent to run 3 different ways: On a schedule, Manually from the Notes client, and Manually with a web browser. Each way of running has logging, so the logging needs to be different in the 3 ways as well.

First off, to give credit where credit is due. My logging in the Notes client uses the Java Output Window written by Jake at CodeStore: http://www.codestore.net/store.nsf/unid/BLOG-20120327-0501?OpenDocument. I put all the code into a script library and then use that whenever I'm using Java in the Notes client. It's an easy way to include a progress window instead of forcing the user to open up their Java console.

In the agent, I define 3 global objects (plus the session object) to make logging easier. This is way easier than passing all the different objects around to all my methods.

public class JavaAgent extends AgentBase {
   private static OutputWindow outputWindow = null; // Output window if running in the Notes client
   private static PrintWriter agentOutput = null; // Web output if running manually
   private static Log agentLog = null; // Web output if running on a schedule
   private static Session session;

Next, at the top of the code, I figure out what environment I'm running under and then set one (and only one) of those 3 objects accordingly:

   AgentContext agentContext = session.getAgentContext();
   Document currDoc = agentContext.getDocumentContext();
   if (session.isOnServer()) { // Running in web browser or on a schedule
         if (currDoc == null) { // Running on a schedule
            agentLog = session.createLog(agentContext.getCurrentAgent().getName());
            agentLog.openNotesLog("", "subdir\\path.nsf");
         } else { // Running manually in a web browser
            agentOutput = getAgentOutput(); // Get the console output
   } else { // Running on the Notes client
       // Open up the output status window for the user to see
       outputWindow = new OutputWindow();

Finally, to make logging easier, I wrote a "logIt" method that takes a string of what to log and an integer of how many blank lines to include before the log message.

private void logIt(String msg, int numBlanks) {
   if (outputWindow != null) {
      for (int i=0; i<numBlanks; i++) outputWindow.println("");
   } else if (agentOutput != null) {
      for (int i=0; i<numBlanks; i++) agentOutput.println("<br />");
      agentOutput.println(msg + "<br />");
   } else if (agentLog != null) {
      // Don't log the blank lines when going to the agent log
      try {
      } catch (NotesException ne) {
         System.out.println("ERROR ATTEMPTING TO LOG A MESSAGE:");
         System.out.println("ERROR MESSAGE = " + ne.getMessage());
   } else {      // On the off-chance none of the above have been defined
      for (int i=0; i<numBlanks; i++) System.out.println("");
} // logIt

That's about it. If I want to know what environment I'm running under later on for whatever reason, I can just check which one of those 3 global objects have been set and the code can proceed accordingly.

Additionally, I set up some standard error trapping in every method. First line of the method is "try" and then it runs through all the code. At the bottom is the "catch" block that logs the error:
} catch (Exception e) {
   logIt("---------------------------------------------------------------", 2);
   logIt("ERROR in method \"<method name>\"!!!!! ", 0);
   logIt(e.getMessage(), 0);
   logIt(e.toString(), 0);
   logIt("---------------------------------------------------------------", 0);
   if (outputWindow != null) outputWindow.setCloseable(true); // Change "please wait" to "OK" and allow user to close status window
   return null; // Get out of any looping that might be happening when there is an error

By the way, in case that Code Store web site ever goes away, here's the code. I created a Java script library (NOT a JavaScript library) called javaOutputWindow and then just bring it in whenever I need it. Here's the code for the library:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;
import javax.swing.text.DefaultCaret;

public class OutputWindow {
     private final static String DEFAULT_PANEL_TITLE = "Agent Output";
     private final static String ERROR_DIALOG_TITLE = "Error";
     private final static String NEW_LINE = "\n";

     private final static String BUTTON_TEXT_DEFAULT = "Please wait...";
     private final static String BUTTON_TEXT_DONE = "OK";

     private final static int PANEL_WIDTH = 600;
     private final static int PANEL_HEIGHT = 400;

     private static JTextArea taskOutput;
     private static JFrame frame;
     private static JButton okButton;

     public OutputWindow(){
          frame = new JFrame(DEFAULT_PANEL_TITLE);
          frame.setMinimumSize( new Dimension(PANEL_WIDTH, PANEL_HEIGHT) );

          //Center the window on screen
          Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();

          //Create and set up the content pane.
          BorderLayout layout = new BorderLayout();
          JComponent newContentPane = new JPanel(layout);
          newContentPane.setOpaque(true); //content panes must be opaque


          taskOutput = new JTextArea();

          taskOutput.setMargin(new Insets(5,5,5,5));


          DefaultCaret caret = (DefaultCaret)taskOutput.getCaret();

          okButton = new JButton(BUTTON_TEXT_DEFAULT);

          okButton.addActionListener(new ActionListener() {
               public void actionPerformed(ActionEvent actionEvent) {

          JScrollPane scrollPane =new JScrollPane(taskOutput);
          scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER );

          frame.add(scrollPane, BorderLayout.CENTER);
          frame.add(okButton, BorderLayout.PAGE_END);

          newContentPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

          //Display the window.

     public void showErrorMessage(String message){
          JOptionPane.showMessageDialog(null, message, ERROR_DIALOG_TITLE, JOptionPane.ERROR_MESSAGE);

     public void show(){

     public void hide(){

     public void setTitle(String title){

     public void setCloseable(boolean closeable){
          if (closeable){

     public void append(String s){

     public void print(String s){

     public void println(String s){
          append(s + NEW_LINE);