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.
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.
An input node can receive data from any type of external source, such as a file system, a queue or a database, in the same way as any other Java program, as long as the output from the node is in the correct format.
You provide an input buffer (or bitstream) to contain input data, and associate it with a message object. You create a message from a byte array using the createMessage method of the MbInputNode class, and then generate a valid message assembly from this message. (See the Javadoc for details of these methods). For example, to read the input from a file:
FileInputStream inputStream = new FileInputStream("myfile.msg");
byte[] buffer = new byte[inputStream.available()];
inputStream.read(buffer);
inputStream.close();
MbMessage msg = createMessage(buffer);
msg.finalizeMessage(MbMessage.FINALIZE_VALIDATE); MbMessageAssembly newAssembly = new MbMessageAssembly(assembly, msg);
When you have created a message assembly, you can then propagate it to one of the node's terminals.
MbOutputTerminal out = getOutputTerminal("out"); out.propagate(newAssembly);
The broker infrastructure handles transaction issues such as controlling the commit of any WebSphere MQ or database unit of work when message processing has completed. However, if a user-defined node is used, any resource updates cannot be automatically committed by the broker.
Each message flow thread is allocated from a pool of threads maintained for each message flow, and starts execution in the run method.
The user-defined node uses return values to indicate whether a transaction has been successful, to control whether transactions are committed or rolled-back, and to control when the thread is returned to the pool. Any unhandled exceptions are caught by the broker infrastructure, and the transaction is rolled back.
You determine the behavior of transactions and threads using an appropriate return value from the following:
public int run( MbMessageAssembly assembly ) throws MbException { byte[] data = getDataWithTimeout(); // user supplied method // returns null if timeout if( data == null ) return TIMEOUT; MbMessage msg = createMessage( data ); msg.finalizeMessage( MbMessage.FINALIZE_VALIDATE ); MbMessageAssembly newAssembly = new MbMessageAssembly( assembly, msg ); dispatchThread(); getOutputTerminal( "out" ).propagate( newAssembly ); return SUCCESS_RETURN; }
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); }
The Java Settings panel is displayed.
Any class that implements the MbInputNodeInterface, and is contained in the broker's classpath (or LIL path) is registered with the broker as an input node. When you implement the MbInputNodeInterface, you also need to implement a run method for this class. The run method represents the start of the message flow, contains the data that formulates the message, and propagates it down the flow. The broker calls the run method when threads become available in accordance with your specified threading model.
For example, to declare the input node class:
package com.ibm.jplugins; import com.ibm.broker.plugin.*; public class BasicInputNode extends MbInputNode implements MbInputNodeInterface { ...
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 the attributes.
An input node has a number of output terminals associated with it, but does not typically have any input terminals. Use the createOutputTerminal method to add output terminals to a node when the node is instantiated. For example, to create a node with three output terminals:
public BasicInputNode() throws MbException { createOutputTerminal ("out"); createOutputTerminal ("failure"); createOutputTerminal ("catch"); setAttribute ("firstParserClassName","myParser"); attributeVariable = new String ("none"); }
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 "BasicInputNode"; }
package com.ibm.pluginsamples; public class BasicInputNode extends MbInputNode implements MbInputNodeInterface { ...
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 already described, the run method is called by the broker to create the input message. This method should provide all the processing function for the input node.
An input node implementation normally determines what message parser initially parses an input message. For example, the primitive MQInput node dictates that an MQMD parser is required to parse the MQMD header. A user-defined input node can select an appropriate header or message parser, and the mode in which the parsing is controlled, by using the following attributes that are included as default, which you can override:
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 Input nodes
Related tasks
Developing user-defined extensions
Implementing the provided samples
Compiling a Java user-defined node
Related reference
MQInput node
Exception list structure
Java user-defined node API
Notices |
Trademarks |
Downloads |
Library |
Support |
Feedback
![]() ![]() |
as09950_ |