Oracle Internet File System Developer's Guide
Release 1.1

A75172-04

Library

Service

Contents

Index

Prev Next

8
Using Agents

This chapter covers the following topics:

What Is an Agent?

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.

What Triggers an Agent's Action?

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.

Time-Based 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.

Event-Based Agents

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.

Combination Agents

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.

How Do Agents Work?

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:

The SalaryFileLog Agent at Work

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:

  1. Once the agent is started and registered, the agent "goes to sleep," waiting for events from the repository.

  2. When the CurrentSalary file is updated, the Oracle iFS repository "wakes up" the SalaryFileLog agent by notifying the agent that a registered event has occurred.

  3. The SalaryFileLog agent processes the event, adding a line to a log file. When the agent has completed its action, it "goes to sleep" again until the Oracle iFS repository notifies it that the next registered event has occurred.

These three steps repeat until the ServerManager stops the agent.

Classes and Methods for an Event 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.


Step  Requirement  Related Class or Method 

1. 

A Java class that:
- Extends IfsAgent
- Implements IfsEventHandler 


oracle.ifs.agents.common.IfsAgent
oracle.ifs.common.IfsEventHandler
 

2. 

To instantiate the class, the agent
needs a constructor.
The agent must register to publish status. 



registerDetails() 

3. 

A valid Oracle iFS connection. 

connectSession() 

4, 

A method to register this agent for the object or objects it will act upon:
- A specific object
- All instances of a specific class

Corresponding methods to deregister
the agent. 

LibrarySession.registerEventHandler()
LibrarySession.registerClassEventHandler()

LibrarySession.deregisterEventHandler()
LibrarySession.deregisterClassEventHandler()
 

5. 

A method to respond to a Start request:
- Start the agent and call its methods 


run()
 

6. 

Methods to handle the agent cycle:
- Handle requests
- Process events
- Wait 


handleRequests()
processEvents()
waitAgent()
 

7. 

Methods to deal with event listening:
- To enable event listening
- To disable event listening 


enableEventListening()
disableEventListening()
 

8. 

Event handling:
- A method to receive the event
and queue it.
- A method to process the event.
- Custom code for processing 

oracle.ifs.common.IfsEventHandler.
handleEvent()
queueEvent()
processEvent()
A custom method, such as logObjectFolderPath() 

9. 

Response to ServerManager requests:
- Publish detail in response to a Start
request
- Stop request
- Clean up after the agent runs
- Suspend request
- Resume request 


publishStatusDetail()

handleStopRequest()
postRun()
handleSuspendRequest()
handleStopRequest()
 

Writing an Event Agent

Here is the structure of a typical event agent program:

  1. Declare the Class

  2. Create the Constructor

  3. Write the run() Method

  4. Handle a Stop Request

  5. Handle a Suspend Request

  6. Handle a Resume Request

  7. Handle Oracle iFS Events

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.

Start with Template Code

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:

Declare the Class

Every event agent must:

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.

The Class Declaration

This sample provides all of the required code for this section.

Sample Code: The Class Declaration

public class ColorAgent extends IfsAgent implements IfsEventHandler

Create the Constructor

Every agent must implement the standard constructor for an agent.

The Constructor Method

This sample provides all of the required code for this section. Simply replace the agent name ColorAgent with the name of your custom agent.

Sample Code: The Constructor Method

public ColorAgent(String name, String[] args, String sectionName,
        ServerManager manager) throws IfsException
{
   super(name, args, sectionName, manager);
}

Write the run() Method

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:

The run() Method

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.

Adding Custom Code

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.

Sample Code: The run() Method

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 postRun() Method

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:

Sample Code: The postRun() Method


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 enableEventListening() Method

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:

Sample Code: The enableEventListening() Method

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 disableEventListening() Method

The following code performs the corresponding deregistration for this agent by calling the deregisterClassEventHandler() method.

Sample Code: The disableEventListening() 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)
    {
    }
}

Handle a Stop Request

Every agent must handle the three possible requests from the ServerManager:

The following code sample demonstrates handling a Stop request from the ServerManager.

The handleStopRequest() Method

This section of the agent program makes the call to the IfsAgent.handleStopRequest() method, which logs an indication of the agent's status change.

Adding Custom Code

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.

Sample Code: The handleStopRequest() Method

protected void handleStopRequest() throws IfsException
{
    // the super sets our status to "stopping"
    super.handleStopRequest();
    log("Stop request");
}

Handle a Suspend Request

The following code sample demonstrates handling a Suspend request from the ServerManager.

The handleSuspendRequest() Method

This section of the agent program makes the call to the IfsAgent.handleSuspendRequest() method. In this code sample, the following tasks are performed:

Adding Custom Code

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.

Sample Code: The handleSuspendRequest() Method

protected void handleSuspendRequest() throws IfsException
{
    // the super sets our status to "suspended"
    super.handleSuspendRequest();

    log("Suspend request");

    // disable our event listening & timer
    disableEventListening();
}

Handle a Resume Request

The following code sample demonstrates handling a Resume request from the ServerManager.

The handleResumeRequest() Method

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:

Adding Custom Code

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.

Sample Code: The handleResumeRequest() Method

protected void handleResumeRequest() throws IfsException
{
    // the super sets our status to "started"
    super.handleResumeRequest();

    log("Resume request");

    // re-enable event listening
    enableEventListening();
}

Handle Oracle iFS Events

The Handle Oracle iFS Events section of the agent program consists of two methods:

The handleEvent() Method

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.

Sample Code: The handleEvent() Method

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

The processEvent() method calls the logObjectFolderPath() method to do the actual work of the agent.

Sample Code: The processEvent() Method

public void processEvent(IfsEvent event) throws IfsException
{
    // log the object with its folder path
    logObjectFolderPath(event);
}

The logObjectFolderPath() Method

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.

Sample Code: The logObjectFolderPath() Method

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)
    {
    }
}

Registering an Agent with ServerManager

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:

  1. Log in to the Solaris environment.

  2. Create a definition file for your custom agent.

    See "Sample Code: Agent Definition File" for a sample definition file, CustomServerManager.def.

  3. Use the following command to run a standalone instance of ServerManager for your custom agent:

    $ 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.

Agent Definition File

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.)

Sample Code: Agent Definition File

; 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:


Parameter  Description 

ManagerName 

Unique name of this instance of ServerManager. 

Interactive 

Whether or not this instance of ServerManager runs in interactive mode. 

Outputfile 

Fully qualified pathname for the log file for this instance of ServerManager. 

Name 

Specifies the name of the agent. Must be one word. 

Class 

Specifies the package hierarchy for the agent .class file. Verify that there is an entry in the CLASSPATH environment variable that the system can use to locate the .class file for the custom agent. 

Start 

Sets whether to start the agent automatically when this instance of ServerManager is started. If set to false, the agent must be started manually. 

Testing the Agent

Once the agent is complete and has been registered, your testing scenario will look something like this:

Event Agent (Complete Code Example)

The following agent, ColorAgent, is registered to receive notice of events on objects of the class MyColorObjects.

Sample Code: Event Agent

/* --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


Prev Next
Oracle
Copyright © 2000 Oracle Corporation.

All Rights Reserved.

Library

Service

Contents

Index