The Executable Portion of an Exit

Business agents are written in standard Java language, and can use any available Java libraries or services.

public void init(String[ ] parms) throws XDException

Parameters are passed to the exit as name:=value pairs in a Map<String,String>. The init() method prepares the map. As it is initially prepared, any iFL (for example, _sreg, _property, and so on) in the value has not yet been evaluated. Doing so can be performed at the appropriate points in the execution of the exit. The wizards insert standard iFL evaluation code at the appropriate points.

Once prepared, parameters are available by name in the Map. The Exit Wizards automatically provide an init() method that handles the parameters in this way. The code in the generated init() method calls upon services of the XDExitBase class from which all exits descend to create the Map. The parms parameter of the method is deprecated and should not be used.

In an init() method, the application should accept and save configuration parameters that relate to the component instance itself, and not to the document passing through it. Because there is no document when the exit is loaded, the iFL evaluation cannot take a value from a document such as by using an _xpath() function. The iFL evaluator will throw an exception should a document be required by a specific configuration of the user.

Programmers generally cannot depend on the order in which parameters (especially user parameters) are stored. Consequently, one parameter should not depend upon the value of another parameter. Special code can be used if such is required, but this is not part of a normal exit.

Exits may be loaded multiple times as they are paged in and out. Developers should not depend upon the init() method being called once. The init() method will, however, be called in a synchronized block so that initialization of any specific exit instance will not conflict with another.

public void term() throws XDException

This method is called as the engine closes down all uses of the exit. It is always called as the engine stops, and may be called at other times if the engine elects to page out the exit. If term() is called in such a case, the init() method is called before the exit is used again.

public String execute(XDDocument indoc, XDDocument outdoc)

The message handling portion of the exit is performed in the execute() method. The exit accepts its input in the indoc and is responsible for loading the result in the outdoc. The outdoc of your exit will be the input to the next exit, regardless of the type or where the exit runs in the channel.

The exit reports the result of its operation by returning a string. The value in the string instructs the process flow interpreter as to which edge is to be followed to the next exit. A successful exit should always return EX_SUCCESS (success) which follows the success edge. Standard EX_ mnemonics represent common causes of failure, and should always be used where applicable. Failures should begin with the characters fail_ (for example, fail_connect), as the interpreter will follow a general wired fail edge if a specific failure edge cannot be located.

Note that the results of an exit that does not return EX_SUCCESS need not represent an error, but can instead simply denote a processing path. For example, an agent that checks for the presence of a record in a data base might return notfound to route the flow down a specific path. If a record is expected to exist and it is not found, this may be a failure, and the exit should return fail_notfound.

Although only agent exits (services in process flows) use wired edge names at this time, your exit should follow the rules of returning results, as future versions of iSM will utilize these returns.

The return statement can also return edge names other than those in the metadata list. The SQL Service object uses this capability to return XOPEN SQL codes. In some cases, the SQL result might not be interpretable by the SQL Service. For example, an SQL GRANT command might result in an XOPEN code of 01007, meaning privilege not granted. The SQL Service returns the following syntax:

return "01007,fail_operation"

This instructs the flow to follow the failure edge or the specific edge if known. The designer allows relations (edges) to be wired for the specific codes returned by getOPEdges as well as user codes, in this case, 01007. Naturally, the process flow designer needs to be aware of the possible (situational) returns and design accordingly.

Note: When making returns with lists of edges, always return the list in the order of the most specific to the least specific. For example, in an http emitter:

return("fail_501,fail_5xx,fail_server");

The flow continues to look for a wired edge, so if your node is wired to take fail_501 as specific and fail_5xx for the general case of all other 500-level errors, then you want the 501 edge to be taken and not the 5xx.

The parent object from which your exit descends, provides a set of standard edge names to make process services appear more consistent. It is recommended to use standard edge names for all agents to simplify process designs and documentation. Note that these edge names may not always denote a failure. For example, a service to check if a key is already in a database should return duplicate, which may be a perfectly reasonable and desired result. In other cases, such as an SQL update, this might be an error.

Edge Name

Description

closed

Resource being tested is closed.

duplicate

An operation denoted a duplicate situation.

fail_connect

Unable to connect to a resource.

fail_operation

Some other activity failed, not covered by another return.

fail_parse

Parsing operation has failed.

fail_partner

External resource issued a failure. For example, an SAP system signaled a failure to update a database.

fail_security

Security failure. Possibly an encryption or decryption operation failed or a password was incorrect.

fail_timeout

Operation timed out.

notfound

An operation denoted that a resource was not found, such as a key in a database.

open

Resource being tested is open.

reissued

Resource that had been previously handled has been provided again. For example, a token extracted from a security system.

replace

Resource was replaced in a database or other collection.

success

Service completed successfully.

There is a distinction between errors and failures. The OnError edge is used when either:

This behavior makes the error edge the last resort. An exit cannot return errors, and signals problems it finds with failures. If the failures are not wired as described above, then the process flow will follow the error edge.

Some agents choose to emit a status document to describe their operation. A standard status document is constructed by the MakeStdStatusTree, which returns an XDNode of a tree that can be stored as the root of the output document of the exit. The exit can populate the tree accordingly, provided that downstream components can work with the changed document.

The following image shows the standard call.

The following syntax is an XML schema that represents the document from the standard call.

<?xml version="1.0" encoding="UTF-8" ?>
-	<!--	edited with XMLSpy v2009 (http://www.altova.com) by Richard Beck (Information Builders) -->
	<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified" attributeFormDefault="unqualified">
	<xs:element name="emitstatus">
	<xs:annotation>
<xs:documentation>General error document from agents that emit a status
document</xs:documentation>
</xs:annotation>
	<xs:complexType>
	<xs:sequence>
	<xs:element name="protocol">
	<xs:annotation>
<xs:documentation>Value is the type of protocol, such as File, MQ,
etc.</xs:documentation>
</xs:annotation>
</xs:element>
	<xs:element name="parms">
	<xs:annotation>
<xs:documentation>Evaluated parameters used for this instance of the
service</xs:documentation>
</xs:annotation>
	<xs:complexType>
	<xs:sequence minOccurs="0">
	<xs:element name="parm" maxOccurs="unbounded">
	<xs:annotation>
<xs:documentation>Value is the evaluated value of the
parameter.</xs:documentation>
</xs:annotation>
	<xs:complexType>
<xs:attribute name="name" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
	<xs:element name="timestamp">
	<xs:annotation>
<xs:documentation>The time to millisecond at which this document was
created.</xs:documentation>
</xs:annotation>
</xs:element>
	<xs:element name="status" type="xs:integer">
	<xs:annotation>
<xs:documentation>Status code relating to the error. By standards, status
0 is success, but the status code is decided by the
component.</xs:documentation>
</xs:annotation>
</xs:element>
	<xs:element name="msg" minOccurs="0">
	<xs:annotation>
<xs:documentation>Explanatory message</xs:documentation>
</xs:annotation>
	<xs:complexType>
	<xs:sequence minOccurs="0">
	<xs:element name="SUB_MSG" minOccurs="0" maxOccurs="unbounded">
	<xs:annotation>
<xs:documentation>Zero or more further messages better describing the
error.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
	<xs:element name="channel" minOccurs="0">
	<xs:annotation>
<xs:documentation>The name of the channel from which this error
originated</xs:documentation>
</xs:annotation>
</xs:element>
	<xs:element name="nodename" minOccurs="0">
	<xs:annotation>
<xs:documentation>The name of the pflow node that generated this
 error</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

Dealing With iFL In the Execute Method

Once the init() method has loaded the parameter map (called parmMap as a standard), the execute method needs to retrieve actual values of the parameters during the execute() method. This occurs because the parameter value may depend upon information in the incoming XDDocument. For example, if the applicatoion user configured a filename to be something such as _xpath(/root/input/filename), then the value will vary per message.

Standard code in the execute() can evaluate the iFL each time that the method is entered.

Map<String, String> tmap = (Map<String, String>) parmMap.clone();
       try
	{
		XDUtil.evaluateWithException(tmap, docIn, getSRM(), logger);
	}
	catch (Exception e)
	{
XDDocument errorDoc = new XDErrorDocument(worker, docIn,                                                         XDErrorDocument.PIPE_AGENT,  getNodeName(), null, e);
		errorDoc.moveTo(docOut);
		return EX_FAIL_PARSE;  // set for the proper edge
	}

The parmMap is cloned so that the original map with the iFL values is not changed. Instead, the temporary map serves as the source of the values to the method.

String filename = FileNameParm.getString(tMap);

The above syntax returns the value. The methods for dealing with values for the actual XDPropertyInfo describing the file name are available in the Javadoc for iSM.

public void cancel()

Called on an external thread, this instructs the exit to attempt to cancel its operation. Functioning exits try to implement cancel(). For example, the provided SQL agent attempts to send the cancel to the data base, and if it is in retrieval phase (reading messages from the data base), it will close the result set and return on the EX_CANCELLED edge.

public void onError(XDNode rulenode, XDNode errornode, int thePosition, int thePiece, String theSegID) throws XDException

This method exists only in acknowledgment business agents. It is called by the rule engine to post errors that can be handled when the actual execute() method is called later. The input consists of the rule node (the node of the rule that detected the error, the node on which the error was detected, the child of the node in error, the offset component into that child, and the identifier of the EDI segment in error). Some of these fields may not be meaningful in non-EDI situations.

Acknowledgment business agents are expected to mark the document tree with the error, using the getAssociatedVector() and setAssociatedVector() calls to post the error objects to the appropriate node. Later, in the execute() method, a tree walk can locate the errors for construction of the acknowledgment.

Acknowledgment business agents can be scheduled for input rules violations and for output document rules violations. The execute() method for the input case generates an output document that is immediately emitted. The business agent scheduled for the output case receives the document and can modify it, but is not expected to emit its own document. It can redirect the output by using set/addReplyTo() and set/addErrorTo() calls to change destinations. It can also set special registers that can be used in routing logic later in the cycle, such as in selection of a reviewer or preemitter.

Although the exit is not restricted in the edge names that it uses, it is a best practice to use standard edge names. A list of these can be found under the execute() method description, and iSM offers standard mnemonics for common edge names.

Example: Source Code for the XDMoveAgent

For simplicity, metadata calls are not shown.

import com.ibi.edaqm.*;
/**
*	This is the plug-in agent used to move the document from input to output.
*	This is the simplest possible agent. It can be called to service any
 document type.
*
*	This class extends the XDAgent class, which provides several services,
 such as tracing.
*
*/public final class XDMoveAgent extends XDAgent 
/**
*	Agents have a null constructor. It must be public as it is reached from
 the edaqm package.
*/
public XDMoveAgent()
{
			super();
}
/**
*	Execution of the agent begins at the execute method. The input document and
*	the output document are passed in. This particular execute() method simply
*	copies the message tree from the input document to the output document.
*	This agent is, in effect, a NOP. Upon completion of this agent, the output
 document
*	is passed to the next stage.
*
*	@param docIn Input document.
*	@param docOut Output document to create.
*	@exception XDException (unused in this implementation)
*/
public String execute(XDDocument docIn, XDDocument docOut) throws XDException
{
docIn.moveTo(docOut); //service method in XDExitBase return "success";
}
}