Oracle Internet File System Developer's Guide Release 1.1 A75172-04 |
|
This chapter covers the following topics:
An agent is a Java program used to automate a task. More specifically, an agent lets an application respond to specific actions taken within the Oracle Internet File System environment. For example, an agent may respond when an instance of a certain document class is inserted, updated, or deleted in the repository.
One common use of agents is to provide notifications. For example, application design may require that when anyone inserts a document in a certain folder, a notification should be sent to a specific person, reporting that fact. An example of using an agent to provide notification is to implement the following business rule: "Whenever a purchase order is placed in the "Ready for Approval" folder, a message should be sent to the vice president of the division, who approves all purchase orders." To implement this functionality in Oracle iFS, write an agent.
You can think of agents as belonging to certain categories, depending on what triggers their actions. Agents can be triggered by time, events, or both. Because most custom agents are event-based agents, the remainder of this chapter will focus on event agents.
The action of a time-based agent is triggered by a timer. A typical use for a time-based agent is to implement clean-up procedures. An example of a time-based agent is the Oracle iFS standard Garbage Collector agent, which can be configured to run one or more times each day. Time-based agents can be used to improve system performance by scheduling tasks that may be CPU-intensive to run outside of peak hours.
A typical use for an event-based agent is to provide a log of changes to a sensitive file. An example of this type of event agent is a custom agent that provides a change log for accounting records, indicating that a specific file was updated at a certain time by a certain person.
A single agent can be written to respond to both time-related and event-based actions. An example of this type of agent is the Oracle iFS Quota agent. The Quota agent is designed to perform a quota check based on "New Document" events, and also to perform periodic timed checks on users who are logged into Oracle iFS.
Agents differ from other programs in that they do not run independently. The ServerManager is responsible for running the agent. The close interaction between the ServerManager and the agent program can be summarized as follows:
To understand the process of using an agent, consider the example of an agent created to log changes to a sensitive file called CurrentSalary. Assume that:
Here is the sequence of events that will occur:
These three steps repeat until the ServerManager stops the agent.
Because agents interact so closely with the ServerManager, it may be useful to look at writing a custom agent in terms of providing the items the ServerManager requires to successfully run the agent. The following table summarizes what the ServerManager requires and lists the Oracle iFS API classes or methods used to meet the requirement.
Here is the structure of a typical event agent program:
Once the agent has been created, you must configure the ServerManager to instantiate and run the agent. For information about this process, see "Registering an Agent with ServerManager".
The event agent sample code used to illustrate this process is for the ColorAgent, which is registered to receive notice of events on instances of the class MyColorObjects.
The simplest way to write an agent is to use Oracle iFS sample code as a template. The Oracle iFS sample code provides a structure to manage interaction with the ServerManager, allowing you to focus on creating the custom code for your agent's specific task.
The agent template sample code, called LoggingAgent.java
, is available in the Documentation section of the Oracle iFS listing on OTN (Oracle Technology Network).
To aid in planning your custom agent, the following table specifies, for each section, whether the section:
Every event agent must:
oracle.ifs.agents.common.IfsAgent
.
oracle.ifs.common.IfsEventHandler
.
The IfsEventHandler interface defines the methods that must be provided for a custom event agent. Both event agents and combination agents, ones that react to both class-based and time-based events, must include both the class and the interface in the class declaration.
Note: The agent name must be one word; no embedded spaces are allowed.
This sample provides all of the required code for this section.
public class ColorAgent extends IfsAgent implements IfsEventHandler
Every agent must implement the standard constructor for an agent.
This sample provides all of the required code for this section. Simply replace the agent name ColorAgent with the name of your custom agent.
public ColorAgent(String name, String[] args, String sectionName, ServerManager manager) throws IfsException { super(name, args, sectionName, manager); }
The following code sample demonstrates registering the agent with the ServerManager and activating event listening for this agent.
The run() method is closely associated with several other methods, so those code samples are also shown here:
This code sample performs the following tasks:
To provide a concise example, this sample does not include exception handling for the run() method. Because it is particularly serious if errors occur in the run() method, the full code example includes comprehensive exception processing. To view the exception handling section, see the full text in the "Event Agent (Complete Code Example)", at the end of this chapter.
The following sample provides the minimum required code for this section.You can add additional custom code in this section to perform any agent-specific initialization required.
public void run() { try { log("Start request"); // perform any agent-specific startup initialization // (none currently) // ensure a connection connectSession(); // enable event listening enableEventListening(); // declare ourselves up publishStatusDetail(); while (true) { if (!isAlive()) { log("Exiting handle loop"); break; } try { // handle any status changes first handleRequests(); // process events processEvents(); // wait for something to do waitAgent(); } } } catch (Exception e) { } }
The following code sample is automatically executed by the ServerManager when the agent breaks out of or returns from the run() method. It provides a place to add code for any required clean-up.
In this code sample, the following tasks are performed:
public void postRun() { super.postRun(); log("postRun"); try { // Perform any special shutdown tasks (none currently) // Disable event listening disableEventListening(); // Disconnect our session. disconnectSession(); } catch (Exception e) { } }
The following code sample registers this agent for events on a specific class by calling the registerClassEventHandler() method. In this code sample, the following tasks are performed:
public void enableEventListening() throws IfsException { try { Library Session sess = getSession(); // Register for events on all new MyColorObjects. Collection c = sess.getClassObjectCollection(); ClassObject myColorClass = (ClassObject)c.getItems(MyColorObject.CLASS_NAME); sess.registerClassEventHandler(myColorClass, true, this); // Also select all existing MyColorObject objects so that we // get events on them also. Selector selector = new Selector(sess); selector.setSearchClassname(MyColorObject.CLASS_NAME); selector.setSearchSelection(null); selector.getItems(); } catch (Exception e) { } }
The following code performs the corresponding deregistration for this agent by calling the deregisterClassEventHandler() method.
public void disableEventListening() { try { LibrarySession sess = getSession(); // Deregister for events on all MyColorObjects. Collection c = sess.getClassObjectCollection(); ClassObject myColorClass = (ClassObject)c.getItems(MyColorObject.CLASS_NAME); sess.deregisterClassEventHandler(myColorClass, true, this); } catch (Exception e) { } }
Every agent must handle the three possible requests from the ServerManager:
The following code sample demonstrates handling a Stop request from the ServerManager.
This section of the agent program makes the call to the IfsAgent.handleStopRequest() method, which logs an indication of the agent's status change.
The following sample provides the minimum required code for this section.You can add additional custom code in this section to perform custom tasks as part of a Stop request.
protected void handleStopRequest() throws IfsException { // the super sets our status to "stopping" super.handleStopRequest(); log("Stop request"); }
The following code sample demonstrates handling a Suspend request from the ServerManager.
This section of the agent program makes the call to the IfsAgent.handleSuspendRequest() method. In this code sample, the following tasks are performed:
The following sample provides the minimum required code for this section.You can add additional custom code in this section to perform custom tasks as part of a Suspend request.
protected void handleSuspendRequest() throws IfsException { // the super sets our status to "suspended" super.handleSuspendRequest(); log("Suspend request"); // disable our event listening & timer disableEventListening(); }
The following code sample demonstrates handling a Resume request from the ServerManager.
This section of the agent program responds to a Resume request from the ServerManager. A Resume request is the opposite of a Suspend request. This section makes the call to the IfsAgent.handleResumeRequest() method.
In this code sample, the following tasks are performed:
The following sample provides the minimum required code for this section.You can add additional custom code in this section to perform custom tasks as part of a Resume request.
protected void handleResumeRequest() throws IfsException { // the super sets our status to "started" super.handleResumeRequest(); log("Resume request"); // re-enable event listening enableEventListening(); }
The Handle Oracle iFS Events section of the agent program consists of two methods:
If there is any category of events that you do not want to process, you can use this method as a filter to exclude those events. In this example, we do not want to process any MyColorObjects that have been deleted from Oracle iFS.
public void handleEvent(IfsEvent event) { // do not queue any FREE events, but queue all others if (event.getEventType() != IfsEvent.EVENTTYPE_FREE) { queueEvent(event); notifyAgent(); }
}
The processEvent() method calls the logObjectFolderPath() method to do the actual work of the agent.
public void processEvent(IfsEvent event) throws IfsException { // log the object with its folder path logObjectFolderPath(event); }
The processEvent() method calls the logObjectFolderPath() method to do the actual work of the agent, which involves obtaining the pieces of information that make the message that will be printed to the log file. Because this sample is trivial, we could have included this code in the processEvent() method. We have shown it as a separate method because a custom agent might well require several methods to perform its work.
Because this is sample code, the agent performs the minimal action of printing out that the agent received the event for the object. However, this is the location where you should add the code for whatever action you want the agent to take on this object, such as sending a notification.
public void logObjectFolderPath(IfsEvent event) throws IfsException { try { Long objectId = event.getId(); int eventType = event.getEventType(); MyColorObject colorObject = (MyColorObject)getSession().getPublicObject(objectId); // Get any folder path to this object, and log it String objectPath = colorObject.getAnyFolderPath(); log("Received Event Type " + eventType + " on object " + objectPath); } catch (Exception e) { } }
All agents run within an instance of the Oracle iFS ServerManager. Although the system administrator will configure definition files for the primary ServerManager, you as a developer will need to create your own definition (.def) files to test your custom agents.
During testing, you can run your agent in a standalone mode, using only your specific .def file. During system integration and for production, you will want to have the system administrator add your custom agent configuration parameters to the primary Oracle iFS ServerManager agent definition file.
The following steps present a high-level view of the registration process for running the agent in standalone mode for testing, assuming that you have already created and compiled the custom agent class:
See "Sample Code: Agent Definition File" for a sample definition file, CustomServerManager.def
.
$ ifssvrmgr
CustomServerManager.def
In this example, the $
represents the Solaris prompt. At the Solaris prompt, enter the command ifssvrmgr
followed by the name of your .def file. Substitute the name of your file for CustomServerManager.def in the example above.
The CustomServerManager.def file registers an agent called "ColorAgent" with the ServerManager. This sample file registers just one custom agent; it could also be used to register multiple agents. Store this file on the Oracle iFS server machine wherever .def files for other agents are stored (usually $ORACLE_HOME/ifs/settings
.)
; CustomServerManager.def ; This file includes the Color Agent. ; ; ServerManager Configuration Information ManagerName = CustomServerManager Interactive = false Outputfile = /myDirectory/CustomServerManager.log ; ; The name of the agent. Agents += ColorAgent ; ; Description of the agent. ; [ColorAgent] Name = ColorAgent Class = oracle.ifs.agents.examples.ColorAgent Start = true
The following table describes the parameters in the agent definition file:
Once the agent is complete and has been registered, your testing scenario will look something like this:
The following agent, ColorAgent, is registered to receive notice of events on objects of the class MyColorObjects.
/* --ColorAgent.java-- */ /package oracle.ifs.agents.examples; import oracle.ifs.common.Collection; import oracle.ifs.common.IfsEvent; import oracle.ifs.common.IfsEventHandler; import oracle.ifs.common.IfsException; import oracle.ifs.common.ParameterTable; import oracle.ifs.beans.ClassObject; import oracle.ifs.beans.LibrarySession; import oracle.ifs.beans.PublicObject; import oracle.ifs.beans.Selector; //This is the custom class this agent deals with. import ifs.demo.colors.type.MyColorObject; import oracle.ifs.agents.common.IfsAgent; import oracle.ifs.agents.manager.ServerManager; /** * A ColorAgent logs messages according to events that are raised * on the class, MyColorObject. */ public class ColorAgent extends IfsAgent implements IfsEventHandler { /** * Constructs a ColorAgent. */ public ColorAgent(String name, String[] args, String sectionName, ServerManager manager) throws IfsException { super(name, args, sectionName, manager); } /** * Runs this ColorAgent. */ public void run() { try { log("Start request"); // perform any agent-specific startup initialization // (none currently) // ensure a connection connectSession(); // enable event listening enableEventListening(); // declare ourselves up publishStatusDetail(); while (true) { if (!isAlive()) { log("Exiting handle loop"); break; } try { // handle any status changes first handleRequests(); // process events processEvents(); // wait for something to do waitAgent(); } catch (IfsException e) { log("IfsException" + " in handle loop; continuing:"); log(e.toLocalizedString(getSession())); } catch (Exception e) { log("Exception" + " in handle loop; continuing:"); log(e.getMessage()); } } } catch (IfsException e) { // exception that takes us out of the run loop; // this will cause a stop. log("IfsException" + " in run(): "); log(e.toLocalizedString(getSession())); printStackTrace(e); } catch (Exception e) { // exception that takes us out of the run loop; // this will cause a stop. log("Exception" + " in run(): "); log(e.getMessage()); printStackTrace(e); } } /** * Handle the Stop request. Subclasses can override this to * perform custom tasks as part of a Stop request. */ protected void handleStopRequest() throws IfsException { // the super sets our status to "stopping" super.handleStopRequest(); log("Stop request"); } /** * Handle the Suspend request. Subclasses can override this to * perform custom tasks as part of a Suspend request. */ protected void handleSuspendRequest() throws IfsException { // The super sets our status to "suspended" super.handleSuspendRequest(); log("Suspend request"); // Disable our event listening disableEventListening(); } /** * Handle the Resume request. Subclasses can override this to * perform custom tasks as part of a Resume request. */ protected void handleResumeRequest() throws IfsException { // the super sets our status to "started" super.handleResumeRequest(); log("Resume request"); // re-enable event listening enableEventListening(); } /** * Performs post-run tasks for this ColorAgent. */ public void postRun() { super.postRun(); log("postRun"); try { // perform any special shutdown tasks (none currently) // disable event listening disableEventListening(); // Disconnect our session. disconnectSession(); } catch (Exception e) { log("Exception" + " in postRun:"); log(e.getMessage()); } } /** * Enable listening for MyColorObject events */ public void enableEventListening() throws IfsException { try { // Register for events on all MyColorObjects Collection c = getSession().getClassObjectCollection(); ClassObject myColorClass = (ClassObject)c.getItems(MyColorObject.CLASS_NAME); getSession().registerClassEventHandler(myColorClass, true, this); // also select all MyColorObject objects so that we get events // on any of them Selector selector = new Selector(getSession()); selector.setSearchClassname(MyColorObject.CLASS_NAME); selector.setSearchSelection(null); selector.getItems(); } catch (IfsException e) { log("IfsException" + " enabling Event Listening; re-throwing:"); log(e.toLocalizedString(getSession())); printStackTrace(e); throw e; } catch (Exception e) { log("Exception" + " enabling Event Listening; re-throwing:"); log(e.getMessage()); printStackTrace(e); // throw "agent unable to enable event listening" throw new IfsException(46002, e); } } /** * Disable listening for MyColorObject events */ public void disableEventListening() { LibrarySession session = getSession(); try { // Deregister for events on all MyColorObjects. Collection c = getSession().getClassObjectCollection(); ClassObject myColorClass = (ClassObject)c.getItems(MyColorObject.CLASS_NAME); session.deregisterClassEventHandler(myColorClass, true, this); } catch (Exception e) { log("Exception" + " disabling Event Listening:"); log(e.getMessage()); } } /** * Handles events on MyColorObjects. This queues the events for * processing by the main agent thread. */ public void handleEvent(IfsEvent event) { // do not queue any FREE events, but queue all others if (event.getEventType() != IfsEvent.EVENTTYPE_FREE) { queueEvent(event); notifyAgent(); } } /** * Process the de-queued event. The processing is simply to log * a message with the object's name and folder path. * * @param event The event to log * */ public void processEvent(IfsEvent event) throws IfsException { // log the object with its folder path logObjectFolderPath(event); } /** * log information about an object received as an event. * * @param event the event to log * */ public void logObjectFolderPath(IfsEvent event) throws IfsException { try { Long objectId = event.getId(); int eventType = event.getEventType(); MyColorObject colorObject = (MyColorObject)getSession().getPublicObject(objectId); // get any folder path to this object, and log it String objectPath = colorObject.getAnyFolderPath(); log("Recieved Event Type " + eventType + " on object " + objectPath); } catch (IfsException e) { // exception getting the information about the obejct // referred in the event log("IfsException" + " in processEvent(): "); log(e.toLocalizedString(getSession())); } catch (Exception e) { // exception getting the information about the obejct // referred in the event log("Exception" + " in processEvent(): "); log(e.getMessage()); } } } //EOF
|
Copyright © 2000 Oracle Corporation. All Rights Reserved. |
|