|
iPAM Developer Documentation
|
|
- Asynchronous Agents |
Asynchronous agents must implement the interfaceorg.mitre.pam.interfaces.AsynchronousAgent
. That interface has two key methods,enableService()
anddisableService()
that are used to control the thread or service that must persist across invocations of the agent. There are other methods that are part of the AsynchronousAgent interface but there is a default implementation for those methods by the agent base class. Only the two methods mentioned above need to be implemented. The methodpushProductToAllClients(Product)
is an inherited method that allows an input agent to send a product to all outputs.Agents must never create threads or open connections in their constructors because the agent may never actually get used even though it has been instantiated! In general, the executive always creates one copy of every agent for reference purposes that is never actually used.
Below are two examples showing how this interface is used for input agents and output agents.
The example below shows an input agent that subclasses from org.mitre.pam.PIMShell1. This is a code fragment example derived fromorg.mitre.pam.getter.TestAsyncSource
.
An Asynchronous Input Agent
import org.mitre.pam.getter.PIMShell1; import org.mitre.pam.interfaces.AsynchronousAgent; import org.mitre.pam.interfaces.Product; public class SampleAsyncInput extends PIMShell1 implements AsynchronousAgent, Runnable { private final static String PRIORITY = "priority"; Thread thread; boolean running; public SampleAsyncInput () { setProperty(PRIORITY,""); metaIntegerInfo(PRIORITY, 5,"Java Thread priority for input thread"); } public void setProperty(String name, String value) { super.setProperty(name,value); if (name.equals(PRIORITY)) { if (thread != null) { thread.setPriority(getIntegerProperty(PRIORITY,5)); } } } public void enableService() { if (thread == null) { thread = new Thread(this); thread.setPriority(getIntegerProperty(PRIORITY,5)); running = true; thread.start(); } } public void disableService() { running = false; } public void run() { Product product; /* code deleted here */ while(running) { /* code here to build the product */ pushProductToAllClients(product); // inherited method } thread = null; if (logActivity) { reporter.log("done"); } } }
The code below illustrates how the AsynchronousAgent interface can be used to create an output connection that is maintained for multiple product outputs. The example below uses an agent property named "targetURL" to identify the target of the output connection. There is a slight complication in this code because the enable/disable service calls may come before or after the setProperty() calls that contain the target URL. The human operator that is defining the target may also change targets. These cases are all handled properly by the sample below.
An Asynchronous Output Agent
import org.mitre.pam.putter.DIMShell1; import org.mitre.pam.interfaces.AsynchronousAgent; import org.mitre.pam.interfaces.Product; public class SampleAsyncOutput extends DIMShell1 implements AsynchronousAgent, Runnable { Socket outputSocket; static final String TARGET_URL = "targetURL"; boolean receivedEnable; public SampleAsyncOutput () { setProperty(TARGET_URL,""); metaStringInfo(TARGET_URL, "","URL of the output service to connect to"); } public void setProperty(String name, String value) { if (name.equals(TARGET_URL)) { if (!value.equals(getStringProperty(TARGET_URL,"") && outputSocket != null) { closeConnection(); } } if (value.length() > 0 && outputSocket == null && receivedEnable) { buildConnection(value); } } } super.setProperty(name,value); } public void enableService() { receivedEnable = true; String targetURL = getStringProperty(TARGET_URL,""); if (outputSocket == null && targetURL.length()>0) { buildConnection(targetURL); } } public void disableService() { receivedEnable = false; if (outputSocket != null) { closeConnection(); } } private buildConnection(String targetURL) { /* * Make new connection. We are guaranteed * there is not an active connection already. */ } private closeConnection(S) { /* * Close connection. We are guaranteed * there is an active connection * Be sure to set outputSocket = null */ } public void putProduct(Product prod) { /* * Code here to take the product, render it into * some meaningful external form, and then send or publish it. * Can assume that the connection is open because * putProduct will not be called unless * enableService() has already been called. */ } }
Revised: 27 April 1999