API
@-Formulas
JavaScript
LotusScript
Reg Exp
Web Design
Notes Client
XPages
 
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();
       outputWindow.show();
   }


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("");
      outputWindow.println(msg);
   } 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 {
         agentLog.logAction(msg);
      } catch (NotesException ne) {
         System.out.println("ERROR ATTEMPTING TO LOG A MESSAGE:");
         System.out.println(msg);
         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("");
      System.out.println(msg);
   }
} // 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.

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();
          frame.setLocation((dim.width/2)-(PANEL_WIDTH/2),(dim.height/2)-(PANEL_HEIGHT/2));

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

          frame.setContentPane(newContentPane);
          frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);


          taskOutput = new JTextArea();

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

          taskOutput.setEditable(false);
          taskOutput.setLineWrap(true);
          taskOutput.setWrapStyleWord(true);

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

          okButton = new JButton(BUTTON_TEXT_DEFAULT);

          //okButton.setActionCommand("start");
          okButton.addActionListener(new ActionListener() {
               public void actionPerformed(ActionEvent actionEvent) {
                    frame.setVisible(false);
                    frame.dispose();
               }
          });
          okButton.setEnabled(false);


          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.
          frame.pack();
     }

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

     public void show(){
          frame.setVisible(true);
     }

     public void hide(){
          frame.setVisible(false);
     }

     public void setTitle(String title){
          frame.setTitle(title);
     }

     public void setCloseable(boolean closeable){
          if (closeable){
               frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
               okButton.setText(BUTTON_TEXT_DONE);
               okButton.setEnabled(true);
          }
     }

     public void append(String s){
          taskOutput.append(s);
     }

     public void print(String s){
          append(s);
     }

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