Before you start
WebSphere Business Integration Message Broker provides the source for two sample user-defined nodes call SwitchNode and TransformNode. You can use these nodes in their current state, or you can modify them.
Conceptually, a message processing node is used to process a message in some way, and an output node is used to output a message as a bitstream. However, when you code a message processing node or an output node, they are essentially the same thing. You can perform message processing within in output node, and likewise you can output a message to a bitstream using a message processing node. For simplicity, this topic mainly refers to the node as a message processing node, however, it discusses the functionality of both types of node.
Do not develop Java nodes on z/OS that you intend to deploy to a broker on a distributed platform. This is because the level of Java on z/OS might not produce code that is compatible with the level of Java on the distributed platform.
In many cases, the user-defined node needs to access the contents of the message received on its input terminal. The message is represented as a tree of syntax elements. Groups of utility functions are provided for message management, message buffer access, syntax element navigation, and syntax element access.
The MbElement class provides the interface to the syntax elements. For further details of the Java API, see the Javadoc.
For example:
MbElement rootElement = assembly.getMessage().getRootElement(); MbElement switchElement = rootElement.getLastChild().getFirstChild().getFirstChild();
String terminalName; String elementValue = (String)switchElement.getValue(); if(elementValue.equals("add")) terminalName = "add"; else if(elementValue.equals("change")) terminalName = "change"; else if(elementValue.equals("delete")) terminalName = "delete"; else if(elementValue.equals("hold")) terminalName = "hold"; else terminalName = "failure"; MbOutputTerminal out = getOutputTerminal(terminalName);
The received input message is read-only, so before a message can be transformed, you must write it to a new output message. You can copy elements from the input message, or you can create new elements and attach them to the message. New elements are generally in a parser's domain.
The MbMessage class provides the copy constructors, and methods to get the root element of the message. The MbElement class provides the interface to the syntax elements.
MbMessage newMsg = new MbMessage(assembly.getMessage()); MbMessageAssembly newAssembly = new MbMessageAssembly(assembly, newMsg);
MbElement rootElement = newAssembly.getMessage().getRootElement(); MbElement switchElement = rootElement.getFirstElementByPath("/XML/data/action");
String elementValue = (String)switchElement.getValue(); if(elementValue.equals("add")) switchElement.setValue("change"); else if(elementValue.equals("change")) switchElement.setValue("delete"); else if(elementValue.equals("delete")) switchElement.setValue("hold"); else switchElement.setValue("failure");
MbElement tag = switchElement.createElementAsLastChild(MbElement.TYPE_NAME, "PreviousValue", elementValue);
tag.createElementAsFirstChild(MbElement.TYPE_NAME_VALUE, "NewValue", switchElement.getValue()); MbOutputTerminal out = getOutputTerminal("out");
Nodes can invoke ESQL expressions using Compute node ESQL syntax. You can create and modify the components of the message using ESQL expressions, and you can refer to elements of both the input message and data from an external database.
String dataSourceName = "myDataSource";
String statement = "SET OutputRoot.XML.data = (SELECT Field2 FROM Database.Table1 WHERE Field1 = 1);";
String statement = "PASSTHRU( 'INSERT INTO Database.Table1 VALUES( InputRoot.XML.DataField1, InputRoot.XML.DataField2)');";
int transactionType = MbSQLStatement.SQL_TRANSACTION_AUTO;
MbSQLStatement sql = createSQLStatement(dataSourceName, statement, transactionType);You can use the method createSQLStatement(dataSource, statement) to default the transaction type to MbSQLStatement.SQL_TRANSACTION_AUTO).
MbMessageAssembly newAssembly = new MbMessageAssembly(assembly, assembly.getMessage());
sql.select(assembly, newAssembly);
sql.execute(assembly);
For more information about ESQL, see ESQL.
You use the mbException class to catch and access exceptions. The mbException class returns an array of exception objects representing the children of an exception in the broker exception list. Each element returned specifies its exception type. An empty array is returned if an exception has no children. The following code sample shows an example of the usage of the MbException class.
public void evaluate(MbMessageAssembly assembly, MbInputTerminal inTerm) throws MbException { try { // plug-in functionality } catch(MbException ex) { traverse(ex, 0); throw ex; // if re-throwing, it must be the original exception that was caught } } void traverse(MbException ex, int level) { if(ex != null) { // Do whatever action here System.out.println("Level: " + level); System.out.println(ex.toString()); System.out.println("traceText: " + ex.getTraceText()); // traverse the hierarchy MbException e[] = ex.getNestedExceptions(); int size = e.length; for(int i = 0; i < size; i++) { traverse(e[i], level + 1); } } }
Refer to the javadoc for more details of using the mbException class.
You can develop a user-defined message processing our output node in such a way that it can access all current exceptions. For example, to catch database exceptions you can use the MbSQLStatement class. This class sets the value of the 'throwExceptionOnDatabaseError' attribute, which determines broker behavior when it encounters a database error. When it is set to true, if an exception is thrown it can be caught and handled by the user-defined extension.
The following code sample shows an example of how to use the MbSQLStatement class.
public void evaluate(MbMessageAssembly assembly, MbInputTerminal inTerm) throws MbException { MbMessage newMsg = new MbMessage(assembly.getMessage()); MbMessageAssembly newAssembly = new MbMessageAssembly(assembly, newMsg); String table = assembly.getMessage().getRootElement().getLastChild().getFirstChild().getName(); MbSQLStatement state = createSQLStatement( "dbName", "SET OutputRoot.XML.integer[] = PASSTHRU('SELECT * FROM " + table + "');" ); state.setThrowExceptionOnDatabaseError(false); state.setTreatWarningsAsErrors(true); state.select( assembly, newAssembly ); int sqlCode = state.getSQLCode(); if(sqlCode != 0) { // Do error handling here System.out.println("sqlCode = " + sqlCode); System.out.println("sqlNativeError = " + state.getSQLNativeError()); System.out.println("sqlState = " + state.getSQLState()); System.out.println("sqlErrorText = " + state.getSQLErrorText()); } getOutputTerminal("out").propagate(assembly); }
Before you propagate a message, you have to decide what message flow data you want to propagate, and which of the node's terminals is to receive the data. You should finalize the message before you propagate it. After propagating a message, you must delete the output message.
MbOutputTerminal out = getOutputTerminal("out"); out.propagate(newAssembly);
newMsg.clearMessage();
To write to an output device, the logical (hierarchical) message needs to be converted back into a bitstream. You do this using the getBuffer method in MbMessage, as follows:
public void evaluate( MbMessageAssembly assembly, MbInputTerminal in) throws MbException { MbMessage msg = assembly.getMessage(); byte[] bitstream = msg.getBuffer(); // write the bitstream out somewhere writeBitstream( bitstream ); // user method }
Typically, for an output node the message is not propagated to any output terminal, so you can just return at this point.
The Java Settings panel is displayed.
Any class that implements the MbNodeInterface and is contained in the broker's classpath (or LIL path) is registered with the broker as a message processing node. When you implement the MbNodeInterface, you must also implement an evaluate method for this class. The evaluate method is called by the broker for each message that is passed through the flow.
package com.ibm.jplugins; import com.ibm.broker.plugin.*; public class BasicNode extends MbNode implements MbNodeInterface
When the node is instantiated, the constructor of the user's node class is called. This is where you create the terminals of the node, and initialize any default values for attributes.
A message processing node has a number of input terminals and output terminals associated with it. The methods createInputTerminal and createOutputTerminal are used to add terminals to a node when the node is instantiated. For example, to create a node with one input terminal and two output terminals:
public MyNode() throws MbException { // create terminals here createInputTerminal ("in"); createOutputTerminal ("out"); createOutputTerminal ("failure"); }
You need to declare the name of the node as it will be identified by the workbench. All node names must end with "Node". You declare the name using the following method:
public static String getNodeName() { return "BasicNode"; }
package com.ibm.pluginsamples; public class BasicNode extends MbNode implements MbNodeInterface { ...
You declare node attributes in the same way as Java Bean properties. You are responsible for writing getter and setter methods for the attributes, and the API framework infers the attribute names using the Java Bean introspection rules. For example, if you declare the following two methods:
private String attributeVariable; public String getFirstAttribute() { return attributeVariable; } publc void setFirstAttribute(String value) { attributeVariable = value; }
The broker infers that this node has an attribute called firstAttribute. This name is derived from the names of the get or set methods, not from any internal class member variable names. Attributes can only be exposed as strings, so you must convert any numeric types to and from strings in the get or set methods. For example, the following method defines an attribute called timeInSeconds:
int seconds; public String getTimeInSeconds() { return Integer.toString(seconds); } public void setTimeInSeconds(String value) { seconds = Integer.parseInt(value); }
As described earlier, for message processing or output nodes, you must implement the evaluate method, defined in MbNodeInterface. This is called by the broker to process the message. This method should provide all the processing function for the node.
The message flow data, that is, the message, global environment, local environment, and exception list, is received at the input terminal of the node.
You implement the onDelete method as follows:
public void onDelete() { // perform node cleanup if necessary }
Related concepts
Planning user-defined extensions
User-defined extensions in the runtime environment
Designing user-defined extensions
User-defined message processing nodes
User-defined output nodes
ESQL
Related tasks
Developing user-defined extensions
Implementing the provided samples
Compiling a Java user-defined node
Related reference
Java user-defined node API
Exception list structure
Notices |
Trademarks |
Downloads |
Library |
Support |
Feedback
![]() ![]() |
as09970_ |