Input and Output handling in a BW6 plugin

Tibco offers the opportunity to create custom BusinessWorks 6 pallets. In order to simplify the development of pallets a BW Development Kit (BWDK) is available here.  

A BW6 Pallet contains one ore more activities. Each of these activities defines: 

1) Attributes. These are properties that can be used to define properties for the activity instance. 

2) Parameters. For each activity input, output and fault parameters can be defined.

These parameters can be used in the Java code that is used to implement the activity. This document contains a detailed description on how to get access to the attributes and input parameters, how to generate output and how to throw a fault.

Assumptions: 

  • Is is assumed the BW6 plug-in development kit is downloaded and installed. See for more information on the installation here.
  • A Pallet is created and the runtime (Java code) for the implementation of the pallet is generated.
  • An XSD is used to define the input, output and fault. In this document the following XSD is used:

 

<?xml version=”1.0″ encoding=”UTF-8″?>

<schema xmlns=”http://www.w3.org/2001/XMLSchema” targetNamespace=”http://www.example.org/requestStore” xmlns:tns=”http://www.example.org/requestStore” elementFormDefault=”qualified”>

    <complexType name=”FaultType”>

        <sequence>

            <element name=”exceptionID” type=”string” maxOccurs=”1″

                minOccurs=”1″>

            </element>

            <element name=”exceptionShort” type=”string” maxOccurs=”1″

                minOccurs=”1″>

            </element>

            <element name=”exceptionDetail” type=”string” maxOccurs=”1″ minOccurs=”1″></element>

        </sequence>

    </complexType>

    <element name=”fault” type=”tns:FaultType”></element>

    <complexType name=”UpdatePayLoadInputType”>

        <sequence>

            <element name=”requestID” type=”string” maxOccurs=”1″

                minOccurs=”1″>

            </element>

            <element name=”tags” type=”string” maxOccurs=”1″

                minOccurs=”0″>

            </element>

            <element name=”payload” type=”string” maxOccurs=”1″ minOccurs=”0″></element>

        </sequence>

    </complexType>

    <complexType name=”UpdatePayLoadOutputType”>

        <sequence>

            <element name=”requestID” type=”string” maxOccurs=”unbounded” minOccurs=”0″></element>

        </sequence>

    </complexType>

    

    <element name=”getPayLoadInput” type=”tns:GetPayLoadInputType”></element>

    <element name=”getPayLoadOutput” type=”tns:GetPayLoadOutputType”></element>

    <complexType name=”NewPayloadInputType”>

        <sequence>

            <element name=”payload” type=”string” maxOccurs=”1″

                minOccurs=”1″>

            </element>

            <element name=”tags” type=”string” maxOccurs=”1″ minOccurs=”0″></element>

        </sequence>

    </complexType>

    

    <complexType name=”NewPayloadOutputType”>

        <sequence>

            <element name=”requestID” type=”string” maxOccurs=”1″ minOccurs=”1″></element>

        </sequence>

    </complexType>

    

    <complexType name=”GetPayLoadInputType”>

        <sequence>

            <element name=”requestID” type=”string” maxOccurs=”1″

                minOccurs=”0″>

            </element>

            <element name=”tag” type=”string” maxOccurs=”1″ minOccurs=”0″></element>

        </sequence>

    </complexType>

    

    <complexType name=”GetPayLoadOutputType”>

        <sequence>

            <element name=”record” type=”tns:RecordType” maxOccurs=”unbounded” minOccurs=”0″></element>

        </sequence>

    </complexType>

    <complexType name=”RecordType”>

        <sequence>

            <element name=”requestID” type=”string” maxOccurs=”1″

                minOccurs=”1″>

            </element>

            <element name=”payload” type=”string” maxOccurs=”1″

                minOccurs=”1″>

            </element>

            <element name=”tags” type=”string” maxOccurs=”1″ minOccurs=”0″></element>

        </sequence>

    </complexType>

    <element name=”newPayloadInput” type=”tns:NewPayloadInputType”></element>

    <element name=”newPayloadOutput” type=”tns:NewPayloadOutputType”></element>

    <element name=”updatePayLoadInput”

        type=”tns:UpdatePayLoadInputType”>

    </element>

    <element name=”updatePayLoadOutput”

        type=”tns:UpdatePayLoadOutputType”>

    </element>

</schema>

 

 

All code listed in this document comes from <package>.palette.resourcetest.runtime.<activityName><activityType>.java 

Example: com.tibco.bw.palette.resourcetest.runtime.ResourceTestSynchronousActivity.jave

Getting the values of Attributes

Attributes are defined in the activity window. See for details Create a hello world BW6 plugin and Modify an existing BW6 plugin.

String based attributes

In order to fetch the value of an attribute one has to use the function getInputAttributeStringValueByName.

Example:

In evalOutput use:  String yourAttribute = getInputAttributeStringValueByName(inputData, processingContext, “AttrName”);  to fetch the value of the ‘AttrName’ attribute.

In execute use: String yourAttribute = getInputAttributeStringValueByName(input, processContext.getXMLProcessingContext(), “AttrName”);

Unfortunately (for unknown reasons) this doesn’t seem to work.

Alternatively you can use the function: activityConfig.get<Attribute Name>()

Example: String yourAttribute2 = activityConfig.getAttrName(); // this will fetch the attribute ‘AttrName’. It works both in the methods evalOutput and execute.

HTTP Client connection

If a HTTP Client connection is selected, the generated runtime code in <activityName>SynchronousActivity or <activityName>AsynchronousActivity will contain the following lines

@Property(name = “Resource”)

public HTTPClientDriverFactory resource;

private HttpClient resourceHttpClient = null;

See for use: HttpClient

Getting the value of Input Parameters

In order to use input parameters you have to define a XSD. One way to do this, is by using the Simple XSD editor:

See for details Create a hello world BW6 plugin and Modify an existing BW6 plugin.

The parameters in the root can be fetched with the function getInputParameterStringValueByName. Examples:

  • In evalOutput use:  String yourInput = getInputParameterStringValueByName(inputData, processingContext, “input”); // to fetch the value of the ‘input’ parameter.
  • In execute use: String yourInput = getInputParameterStringValueByName(input,processContext.getXMLProcessingContext(), “input”);

If the input is hierarchical (contains a complex type),  the XMLUtils.serializeNode() function can be used. This function will provide the input XML as a string.

In evalOutput you could use:

String serializedNode = XMLUtils.serializeNode(inputData, this.activityContext.getXMLProcessingContext());

System.out.println(serializedNode);

 

In order to fetch an individual attribute use the javax.xml.xpath library. The following sample code can be used to retrieve ‘//complexType/inputInCT1′  in the function evalOutput in the <activity name>SynchronousActivity.java or <activity name>AsynchronousActivity.java 

 

Step 1) Add the following imports to 

 

// begin-custom-code

// add your own business code here

import javax.xml.xpath.XPath;

import javax.xml.xpath.XPathConstants;

import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;

import org.xml.sax.InputSource;

// end-custom-code

 

Step 2) Add the following code to the evalOutput() method.

// begin-custom-code

// add your own business code here

System.out.println(“******input**********”);

String serializedNode = XMLUtils.serializeNode(inputData, this.activityContext.getXMLProcessingContext());         

System.out.println(serializedNode);

DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();

DocumentBuilder builder = builderFactory.newDocumentBuilder();

InputSource is = new InputSource(new StringReader(serializedNode));

Document xmlDocument = builder.parse(is);

XPath xPath = XPathFactory.newInstance().newXPath();

String expression = “//complexType/inputInCT1”;

System.out.println(“//complexType/inputInCT1=”+xPath.compile(expression).evaluate(xmlDocument, XPathConstants.STRING));    

System.out.println(“******input**********”);

// end-custom-code

See for more information: http://www.baeldung.com/java-xpath

Setting the value of output

In order to use input parameters you have to define a XSD. One way to do this, is by using the Simple XSD editor:

See for details Create a hello world BW6 plugin and Modify an existing BW6 plugin.

Based on the output defined above, in the evalOutput the following code generated.

ResouceTestOutput resouceTestOutput = new ResouceTestOutput();

resouceTestOutput.setOutput(“StringValue”);

ResouceTestOutput.OutputComplexType outputComplexType = new ResouceTestOutput.OutputComplexType();

outputComplexType.setOutputField1(“StringValue”);

outputComplexType.setOutputField2(“StringValue”);

resouceTestOutput.setOutputComplexType(outputComplexType);

Copy this code between the following tags and modify it.

        // add your own business code here

        // end-custom-code

 

Throwing a Fault

Plugins support the use of activity faults. These are faults that can be cached in BW6. In order to be able to use a fault, you must define it upfront at design time. In order to populate and throw an activity fault a number of modification are required:

 

Step 1) throw a fault.

Faults can be thrown from any of the methods that implement an activity (<package>.palette.<pallet name>.runtime.<activity><actviitytype>, for example: com.tibco.bw.palette.requeststore.runtime.NewRecordSynchronousActivity.Java).

In order to throw a fault use the following function:

throw new Fault(ActivityContext<N> activityContext, Integer code, BundleMessage bundleMessage, Object[] data). This function requires the following parameters:

  • ActivityContext<N> activityContext ==> The data structure that contains the current activity context. This parameter is provided as in input parameter for most methods that implement an activity.
  • Integer code ==> BW internal error code number.
  • BundleMessage bundleMessage ==> type of error.  Choose either use RuntimeMessageBundle.ERROR_OCCURED_INVOKE_EXECUTE_METHOD or RuntimeMessageBundle.ERROR_OCCURED_INVOKE_EXECUTE_METHOD.INVOKE_EXECUTE_METHOD. 
  • Object[] data ==> array of strings that contains data you need to populate the 

 

Example: the following Fault is thrown if a restful invocation fails (statusCode!=200):

throw new Fault(this.activityContext,1,RuntimeMessageBundle.ERROR_OCCURED_INVOKE_EXECUTE_METHOD,new String[] {activityContext.getActivityName().toString(), “Err02”, “Rest error”, “The invocation of “+post_url+” failed with status code=”+statusCode+” and request body=”+new String(responseBody)});

Step 2) Modify the Fault class.

The Fault class is located in the package (<package>.palette.<pallet name>.runtime.fault (for example:  com.tibco.bw.palette.requeststore.runtime.fault)

 

a) Add the following private fields to the class:

 

 

private String[] excpMsg = null; // ==> to be used to hold the strings needed to populate a fault.

private String namespaceURI = “http://www.example.org/requestStore“; //use the targetNamespace used in the XSD that contains the definition of fault. See example XSD below.

private String nodeName = “fault”; // name of the element that contains the fault. See example XSD below.

private String prefix = “tns”; // set to “tns”.

 

 

 

 

b) Add the line ‘this.excpMsg = (String[])data;’  to the Fault constructor. This line will ‘save’ the injected data to field excpMsg.

 

Example: 

public <N> Fault(ActivityContext<N> activityContext, Integer code, BundleMessage bundleMessage, Object[] data) {

        super(activityContext, code, bundleMessage, data);

        this.data = data;

        

        // START added for fault management

        this.excpMsg = (String[])data;

        // END added for fault management

        

    }

c) Return the nameSpace for the fault in the method getFaultElementQNamed. Use the following line:

return new QName(namespaceURI,nodeName);

Example:

public QName getFaultElementQName() {

        // begin-custom-code

        // add your own business code here

        // START added for fault management

        return new QName(namespaceURI,nodeName);

        // END added for fault management

        // end-custom-code 

    }

d) Implement private <N, A> N constructErrData(N fault, ProcessingContext<N> processingContext)

Every attribute of the activity fault must be set separately in the method constructErrData. The following code can be used to do so:

<attributeName> = nodeFactory.createElement(namespaceURI, “<attributeName>”, prefix);

N <attributeName>ValueNode = null;

if (this.excpMsg[1] != null)

{

    <attributeName>ValueNode = nodeFactory.createText(this.excpMsg[1]);  // assumed that the value of <attributeName> is passed in the first excpMsg 

}

else

{

    <attributeName>ValueNode = nodeFactory.createText(“default value”);

}

mutableModel.appendChild(<attributeName>, <attributeName>ValueNode);

 

 

Example: set the attribute ‘exceptionID’

N exceptionID = nodeFactory.createElement(namespaceURI, “exceptionID”, prefix);

N exceptionIDValueNode = null;

System.out.println(“this.excpMsg[1]=”+this.excpMsg[1]);

if (this.excpMsg[1] != null)

{

    exceptionIDValueNode = nodeFactory.createText(this.excpMsg[1]);

}

else

{

    exceptionIDValueNode = nodeFactory.createText(“default value”);

}

System.out.println(“exceptionIDValueNode=”+ exceptionIDValueNode.toString());

mutableModel.appendChild(exceptionID, exceptionIDValueNode);

Example of the code used for Fault:

package com.tibco.bw.palette.requeststore.runtime.fault;

import javax.xml.namespace.QName;

import org.genxdm.ProcessingContext;

import com.tibco.bw.runtime.ActivityContext;

import com.tibco.neo.localized.BundleMessage;

import org.genxdm.mutable.MutableModel;

import org.genxdm.mutable.NodeFactory;

// begin-custom-code

// add your own business code here

// end-custom-code

public class Fault extends RequestStoreActivityBaseException

{

    // begin-custom-code

    // add your own business code here

    // START added for fault management

    private String[] excpMsg = null;

    private String namespaceURI = “http://www.example.org/requestStore“;

    private String nodeName = “fault”;

    private String prefix = “tns”;

    // END added for fault management

    // end-custom-code

    private static final long serialVersionUID = 1L;

    

    @SuppressWarnings(“unused”)

    private Object[] data = null;

    

    public <N> Fault(ActivityContext<N> activityContext, Integer code,

            BundleMessage bundleMessage, Object[] data) {

        super(activityContext, code, bundleMessage, data);

        this.data = data;

        

        // START added for fault management

        this.excpMsg = (String[])data;

        // END added for fault management

        

    }

    

    /**

     * <!– begin-custom-doc –>

     *

     * <!– end-custom-doc –>

     * @generated

     */

    public QName getFaultElementQName() {

        // begin-custom-code

        // add your own business code here

        // START added for fault management

        return new QName(namespaceURI,nodeName);

        // END added for fault management

        // end-custom-code

    }

    /**

     * <!– begin-custom-doc –>

     *

     * <!– end-custom-doc –>

     * @generated

     *

     * This method to set fault data according to design time

     * @param processingContext

     *            XML processing context.  

     */

    public <N> void buildFault(ProcessingContext<N> pcx) {

        N fault = this.createFaultMessageElement(pcx);

        fault = this.constructErrData(fault, pcx);

        this.setData(fault);

        // begin-custom-code

        // add your own business code here

        // end-custom-code

    }

    

    /**

     * <!– begin-custom-doc –>

     *

     * <!– end-custom-doc –>

     * @generated

     *

     * This method to generate fault data

     * @param fault

     *            the root element of fault        

     * @param processingContext

     *            XML processing context.  

     * @return An XML Element which adheres to the fault schema of the activity

     */

    private <N, A> N constructErrData(N fault, ProcessingContext<N> processingContext) {

        MutableModel<N> mutableModel = processingContext.getMutableContext().getModel();

        

        NodeFactory<N> nodeFactory = mutableModel.getFactory(fault);

        

        // if the element’s MaxOccurs and MinOccurs are 1, that means this element must be generated

        // mutableModel.appendChild(fault, exceptionID);

        //set default value here, please set value by your business

        // N exceptionIDvalueNode = noteFactory.createText(“default value”);

        // mutableModel.appendChild(exceptionID, exceptionIDvalueNode);

        

        // START added for fault management

        N exceptionID = nodeFactory.createElement(namespaceURI, “exceptionID”, prefix);

        N exceptionIDValueNode = null;

        System.out.println(“this.excpMsg[1]=”+this.excpMsg[1]);

        if (this.excpMsg[1] != null)

        {

            exceptionIDValueNode = nodeFactory.createText(this.excpMsg[1]);

        }

        else

        {

            exceptionIDValueNode = nodeFactory.createText(“default value”);

        }

        System.out.println(“exceptionIDValueNode=”+ exceptionIDValueNode.toString());

        mutableModel.appendChild(exceptionID, exceptionIDValueNode);

        // END added for fault management

        mutableModel.appendChild(fault, exceptionID);

        System.out.println(“mutableModel”+mutableModel.toString());

        // if the element’s MaxOccurs and MinOccurs are 1, that means this element must be generated

        // mutableModel.appendChild(fault, exceptionShort);

        //set default value here, please set value by your business

        //N exceptionShortvalueNode = nodeFactory.createText(“default value”);

        //mutableModel.appendChild(exceptionShort, exceptionShortvalueNode);

        // START added for fault management

        N exceptionShort = nodeFactory.createElement(namespaceURI, “exceptionShort”, prefix);

        N exceptionShortValueNode = null;

        if (this.excpMsg[2] != null)

        {

            exceptionShortValueNode = nodeFactory.createText(this.excpMsg[2]);

        }

        else

        {

            exceptionShortValueNode = nodeFactory.createText(“default value”);

        }

        mutableModel.appendChild(exceptionShort, exceptionShortValueNode);

        // END added for fault management

        mutableModel.appendChild(fault, exceptionShort);

        

        

        // if the element’s MaxOccurs and MinOccurs are 1, that means this element must be generated

        // N exceptionDetailvalueNode = nodeFactory.createText(“default value”);

        // START added for fault management

        N exceptionDetail = nodeFactory.createElement(namespaceURI, “exceptionDetail”, prefix);

        N exceptionDetailValueNode = null;

        if (this.excpMsg[3] != null)

        {

            exceptionDetailValueNode = nodeFactory.createText(this.excpMsg[3]);

        }

        else

        {

            exceptionDetailValueNode = nodeFactory.createText(“default value”);

        }

        mutableModel.appendChild(exceptionDetail, exceptionDetailValueNode);

        // END added for fault management

        mutableModel.appendChild(fault, exceptionDetail);

        //set default value here, please set value by your business

        // begin-custom-code

        // add your own business code here

        // end-custom-code

        return fault;

    }

Leave a Reply