ShowTable of Contents
Prerequisites: This tutorial will require Eclipse 3.4 with the Expeditor Toolkit for Expeditor 6.2.1 and the Lotus Notes Domino Designer for 8.5.1.
Introduction
This tutorial walks you through the steps of extending the base Notes view container with a custom action. The action will be able to call any arbitrary agent in a database. It will be written completely in Eclipse using Java and the Action Configuration extension point (com.ibm.rcp.composite.container.core.actionConfiguration). This will allow an arbitrary property to be wired up to the Notes view container and have an agent run in the specified database. We start this tutorial by making sure the Expeditor toolkit has configured the Eclipse workspace to run against our installed Lotus Notes installation. I have my Lotus Notes installed to c:\Notes so the configuration screen should look something like this:
Step 1
Creating the Eclipse
Set up an Eclipse plug-in project by selecting File | New | Project from the menu. You will then be presented with a dialog to select which kind of project you want to create. Under the Plug-in Development category select "Plug-in Project". We will call our project name "com.ca.wiki.notes.agent.action", fill in the project name and click the [Next] button. Fill in the fields to match the following screen shot:
Step 2Creating the custom action extension
Now that our project is setup we need to create the basic extension to the action configuration extension point. On the
Dependencies tab click the [Add...] button and then we need to add a dependency to the composite application container core plugin (com.ibm.rcp.composite.container.core). This plugin contains the extension point we are interested in.
Now that we have a dependency we can navigate to the
Extensions tab and click the [Add..] button to create our new extension. Select the com.ibm.rcp.composite.container.core.actionConfiguration extension point and click the [Finish] button.
Step 3Configuring the custom action extension
Now that the base extension definition is created we will fill in the details of the extension point. You can use the Eclipse editors or the straight XML editor to accomplish this. Let's give the extension a unique id and name, type "
com.ca.wiki.notes.agent.actions" for the ID and "Notes Agent Action" for the Name.
We now have to setup the template action that was created for us. The id and the name can be whatever we like, the two important fields is the "type" and "class". The
type field represents the container class we are trying to extend, in our case we want this action to be available for both the re-parented native views and the Java views. The base container class for those views is
com.ibm.notes.view.container.views.BaseNotesViewContainer and that is the value we will use for this field. If we wanted to only extend the re-parented Notes views we would use the id "
com.ibm.notes.view.container.views.ViewContainer", if we wanted to extend the Java view container then we would use "
com.ibm.notes.csi.view.container.views.CSIViewContainer".
Next we are going to add a Data block to our action extension definition. This block will show in the Composite Application Editor UI as fields the assembler has to fill in for the action. We will add three elements to the data section:
server, database, and
agent. These data members are what make our action generic so an assembler can use it to call any agent in any database. You can right click on
com.ca.wiki.notes.run.agent.action (action) label in the extension tree and select
New @nowiki@3data.
We will fill in the data section with the three members we mentioned earlier. In the end, our extension should look like this:
The custom action framework is hierarchical and the Notes views follow this same pattern. You can have custom actions be applicable to any level in the hierarchy, as stated previously. Here is the hierarchy for the Notes view containers:
Step 4Creating the custom action class
In the last step we configured the extension and we defined the class to be "
com.ca.wiki.notes.agent.action.Action", in this step we will create this class. On the extension editor screen we can click the "class*" label and it will present a dialog to have the Java class created. Below is a screen shot where to left click on the "class*" label:
You are then presented with the next dialog where all of the information is filled in for you. Notice it automatically sets up the Superclass for us, com.ibm.rcp.composite.container.core.actions.Action. This is the abstract action class our code will be based on. The great thing about this wizard is it creates the applicable overridden methods for us and we just have to fill in the blanks. Press the [Finish] button to have the code generated for you. The primary method we will be interested in is the
execute() method.
Step 5Writing the code for our action
The next step is to actually do some programming! As stated previously we will primarily be working in the
execute() method in our Action class. This is method that is called by the container framework to execute your action. Some inherited fields you will need to know about are the
field, property, and the
getData() method in the base Action class. First thing we need to do is include a couple of required plug-ins;
com.ibm.notes.java.ui and
com.ibm.notes.java.api plug-ins.
Let's understand where the
field, property, and
getData() come from. These elements can be used in your custom action and are fields that the assembler fills in using the CAE tooling. For the Notes View container the only two we are interested in are the
field, and
property data members. The user interface does not allow for the
getData() extension part, so this is a limitation of the Notes view container. The "Formula" field in the table below is the
field field of your Action, so this is the class field we use to store the server, database and agent name. We will use the format
!!.

Now inside of our execute method we will use the base Action fields to get what information we need to run the Notes agent. The following is the full implementation of the execute() method with comments. The key is we execute the agent and we pass in a "value" item to the NotesAgentData object - this is the item we will retrieve in the LotusScript agent. For now we just pass in the value that came in from the wire. Follow the code flow and read the comments for a better understanding.
public void execute(final AppContainer container, final LandmarkEvent event,
Object context) {
//We only want to get called on "dataChange"
if (event.getId().equals("dataChange") == false) return;
//get the "field" and split it out using the "!" character into separate elements
StringTokenizer tokens = new StringTokenizer(field, ",");
String path = null;
String agent = null;
//probably do a lot more error checking here for properly element number
//but its only a POC
//if there are two tokens assume server is null
if (tokens.countTokens() == 2){
path = tokens.nextToken();
agent = tokens.nextToken();
}
//Make sure at least the path is not null
if (path == null) return;
try{
//Use the new NotesUIWorkspace to get a handle to the UI API's
NotesUIWorkspace ws = new NotesUIWorkspace();
//This is the call back doc which contains the results of the agent
NotesDocumentDataCallback doc = new NotesDocumentDataCallback(){
public void done(NotesDocumentDataEvent arg0) {
// We could print something to the status bar
// that our agent ran or something.
System.out.println(arg0.toString());
super.done(arg0);
}
};
//The database the agent will run against
NotesDatabaseData dbData;
//Get the database from the passed in path
dbData = new NotesDatabaseData(path);
//New up the agent Data
NotesAgentData aData = new NotesAgentData(dbData, agent);
//get the property value from our container
String value = (String)container.getPropertyValue(property);
// add the property to the agent map
// the "value" element will be retrieved in the LotusScript agent
// you can add as many properties as you want here they just need
// to be basic numbers, date, or String
aData.addItem("value", new String(value));
//Execute the agent with a single line call
ws.runAgent(aData, doc, false);
} catch (NotesException e) {
e.printStackTrace();
}
}
Step 6
Writing a basic Lotus Notes Agent in LotusScript
The next step is to create a database that we can use to run an agent in. This can really be anything we want, what we will do is create a Lotus Script agent that shows a dialog box to the end user. This will at least prove the agent can be executed from a normal composite application wire. Using the "File @nowiki@4New" menu item or CTRL+N in the Notes client create a new database:
We will then open that database in Designer by selecting "View @nowiki@5Design" menu item. Once Designer is opened we will create a new Agent under the Code @nowiki@6Agents element in the design outline.
Click the "New Agent" and then name the agent "Show Dialog". We will leave it as a LotusScript type of agent so just click the [Ok] button and Designer will open the agent editor. Notice we simply get the DocumentContext object and then retrieve the "value" item from the in memory note. The entire Lotus Script code is here:
Sub Initialize()
Dim Session As New NotesSession
Dim document As NotesDocument
Dim item As NotesItem
Print "Inside of Show Dialog agent"
Set document = Session.Documentcontext
Set item = document.Getfirstitem("value")
If item Is Nothing then
MessageBox "Value = 'not passed in'",, "This is a Lotus Script Agent"
Else
MessageBox "Value = " + item.Text,, "This is a Lotus Script Agent"
End if
End Sub
The result is when a property change comes into the action the Lotus Script agent displays this dialog box:
Summary
In summary, the concept here is to have LotusScript agents be the receiver of data that is wired through the property broker. This does not use WSDL and you are somewhat limited to what you can do because it only supports strings, dates, and numbers but you can get pretty creative passing around JSON arrays for instance. The Lotus Notes database used in this tutorial is attached to the article (TestNotesAgent.nsf).