IIEP - Configure Business Rule Based Message Processor Processing Engine

The Inbound Business Rule Based Message Processor allows you to process inbound messages using either JavaScript-based business actions or Java business actions developed via the Extension API.

For more information on JavaScript business actions, refer to the Business Action: Execute JavaScript topic in the Business Rules documentation. For information on the Extension API, refer to the Technical Documentation accessible at [system]/sdk or from the system Start Page.

As illustrated below, the processor can use an optional 'splitter' business action to split the original inbound message into multiple parts that are to be handled individually, and invokes the 'importer' business action for each part, or for the original message when no splitter is selected.

The importer business action is responsible for updating STEP based on information in the provided messages via the API functionality exposed in the Scripting / Extension API. A new transaction is started for each importer invocation and, via the configuration, it is possible to specify if processing of subsequent messages should be performed when an exception is thrown from the importer business action code. If desired, the business action code author can design the error handling strategy so that some errors are treated as warnings, while others cause the transaction to be rolled back and the processing potentially stopped.

Important: Given the flexibility of this functionality, it is easy to write importer business action code that will not perform well. Generally, avoid long-running queries, extensive traversal of hierarchies, and business actions holding large data structures in memory. Imports via the Business Rule Based Message Processor functionality cannot be expected to perform as well as the standard STEP Importer processing engine. For high load imports of formats not supported by the STEP Importer, an alternative is to transform incoming files / messages to a supported format in an IIEP pre-processor.

Prerequisites

  1. Contact Stibo Systems to activate the Business Action Processor commercial license. This enables the event-based importer and exporter to process inbound messages in custom / generic formats using JavaScript-based business rules, and enables exports to custom / generic formats including JSON using JavaScript business rules.
  2. Business actions used by this processor should be configured to be valid for all object types.
  3. Review theSplitter Business Action Details and Examples and Importer Business Action Details and Examples sections below for more information about the business actions expected for this processor.

Configuration

To display the configuration for this processor, you must first select the Business Rule Based Message Processor on the previous Configure Endpoint step (defined in the IIEP - Configure Endpoint topic).

Set the following parameters as necessary.

  1. Splitter Business Action (optional) - This optional parameter defines a business action to split the incoming file / message into separate messages for individual import. For details, refer to the Splitter Business Action Details and Examples section below.

Click the ellipsis button () and select a business action from the list. Click Select.

  1. Importer Business Action - This required parameter defines a business action used to update STEP based on either the original incoming file / message (if no splitter is configured) or based on messages produced by the selected splitter business action. For details, refer to the Importer Business Action Details and Examples section below.

A new transaction is started for each invocation. If an exception is thrown during the processing of a message, all changes in STEP performed by the action during the specific invocation are reverted.

Click the ellipsis button () and select a business action from the list. Click Select.

  1. Continue on error - Determines if subsequent (split) messages should be processed when an exception is thrown from the importer business action during processing of a message.

Select 'Yes' or 'No' from the dropdown.

  1. Click the Next button to display IIEP - Configure Post-processor when available, or IIEP - Schedule Endpoint.

Splitter Business Action Details and Examples

The InboundBusinessProcessorSplitterSource interface (for JavaScript business actions, available via the Inbound Splitter Source bind option) provides access to the inbound file / message for the splitter business action.

The InboundBusinessProcessorSplitterSource interface offers these methods for reading the file / message:

  • InboundBusinessProcessorSplitterSource.lines()reads the file line by line and no size restrictions are enforced.
  • InboundBusinessProcessorSplitterSource.getContentAsString() reads the entire content as a string and messages may not exceed 20MB.

The action delivers split messages via the InboundBusinessProcessorSplitterResult interface addMessage(String) method that can be called multiple times (for JavaScript business actions, the interface is available via the Inbound Splitter Result bind option).

In addition, the importer business action has access to the standard Logger for logging to the main step log and the InboundBusinessProcessorExecutionReportLogger interface for logging messages to the background process execution report. Notice that the splitter is not executed in a transaction, meaning that it is not possible to modify STEP data from the splitter.

JSON Message Splitter with JavaScript Business Action Example

This example shows how a simple JSON message in JavaScript can be read into memory, parsed to a JavaScript object, and split into multiple messages.

Sample file / message content

{
  "products": [
    {
      "ean": "4905004972222",
      "shortDescription": "Fender AM 60 Jazzmaster",
      "manufacturerName": "Fender",
      "color": "Green",
      "category": "AlternativeDesignGuitars"
    },
    {
      "ean": "4905004972234",
      "shortDescription": "Gibson Les Paul Custom EB GH",
      "manufacturerName": "Gibson",
      "color": "Black",
      "category": "SingleCutGuitars"
    }
  ]
}

Sample JavaScript

// Splitter Source bound to splitterSource
// Splitter Result bound to splitterResult

var mesg = JSON.parse(splitterSource.getContentAsString());

if (mesg.products) {
  mesg.products.forEach(function(element) {
    splitterResult.addMessage(JSON.stringify(element));
  });
}

CSV Message Splitter with JavaScript Business Action Example

This example shows how a CSV message can be split into one message per line. As opposed to the previous example, the entire message will not be read into memory.

Sample file / message content

4905004972222|Fender AM 60 Jazzmaster|Fender|Green|AlternativeDesignGuitars
4905004972234|Gibson Les Paul Custom EB GH|Gibson|Black|SingleCutGuitars

Sample JavaScript

// Splitter source bound to splitterSource
// Splitter Result bound to splitterResult

var ite = splitterSource.lines();
while (ite.hasNext()) {
  splitterResult.addMessage(ite.next());

}

Importer Business Action Details and Examples

The importer business action is invoked for each message produced by the splitter or once for the inbound message in case no splitter is selected. The importer business action has access to the message to process via the InboundBusinessProcessorImporterSource interface getMessage(): String method (for JavaScript business actions, the interface is available via the Inbound Importer Source bind option). Further, the action has access to a standard Logger, a Manager, an InboundBusinessProcessorExecutionReportLogger and for JavaScript business actions, 'static binds' to attributes, reference types, etc., can be used.

Important: Take care to ensure that messages passed to the importer action do not exceed 1MB. An exception is thrown if getMessage() is called for larger messages.

JSON Message Importer with JavaScript Business Action Example

This example shows how STEP can be updated based on an inbound message. Notice how some errors cause an exception to be thrown (and the transaction to be rolled back) while others only cause a warning to be logged in the background process execution report.

Note: This script uses keys to identify products in STEP. Lookup by ID or key is always preferred over queries.

Sample message content

{
  "ean": "4905004972222",
  "shortDescription": "Fender AM 60 Jazzmaster",
  "manufacturerName": "Fender",
  "color": "Green",
  "category": "AlternativeDesignGuitars"
}

Sample script

// InboundMessage bound to inboundMessage
// Manager bound to manager
// ExecutionReportLogger bound to executionReportLogger

function getCategory(category) {
  if (!category) {
    throw new java.lang.RuntimeException("No Category specified. This is a required field.");
  }
  var categoryProduct = manager.getProductHome().getProductByID(category);
  if (!categoryProduct) {
    throw new java.lang.RuntimeException("No Category with ID '" + category + "'.");
  }
  return categoryProduct;
}

function setValue(product, attributeId, value, isMandatory) {
  try {
    product.getValue(attributeId).setSimpleValue(value);
  } catch (e) {
    if (e.javaException instanceof com.stibo.core.domain.ValidatorException) {
      var message = "Could not set value '" + value + "' for attribute with ID '" + attributeId + "' on product with ID '" + product.getID() + "': " + e.javaException.getMessage();
      if (isMandatory) {
        throw new java.lang.RuntimeException(message);
      } else {
        executionReportLogger.logWarning(message);
      }
    } else {
      throw(e);
    }
  }
}

var prodMessage = JSON.parse(inboundMessage.getMessage());
var ean = prodMessage.ean;

if (!ean) {
  throw new java.lang.RuntimeException("No EAN specified. This is a required field.");
}
var prod = manager.getNodeHome().getObjectByKey("EAN", ean);
var category = getCategory(prodMessage.category);

if (!prod) {	
  try {
    prod = category.createProduct(null, "BuyItem");
  } catch (e) {
    if (e.javaException instanceof com.stibo.core.domain.ObjectTypeConstraintException || e.javaException instanceof com.stibo.core.domain.NodeIdUniqueConstraintException) {
      throw new java.lang.RuntimeException("Could not create new product: " + e.javaException.getMessage());
    }
    throw(e);
  }
  setValue(prod, "EAN", ean, true);
}
if (!prod.getParent().equals(category)) {
  try {
    prod.setParent(category);
  } catch (e) {
    if (e.javaException instanceof com.stibo.core.domain.ObjectTypeConstraintException || e.javaException instanceof com.stibo.core.domain.CycleConstraintException) {
      throw new java.lang.RuntimeException("Could not move product: " + e.javaException.getMessage());
    }
    throw(e);
  }
}
setValue(prod, "ShortDescription", prodMessage.shortDescription, false);
setValue(prod, "ManufacturerName", prodMessage.manufacturerName, false);
setValue(prod, "Color", prodMessage.color, false);