Dynamic Message Mapping in App Connect Enterprise

In a previous blog I introduced the concept of custom integration frameworks, and how some of their solutions might be applied to situations out of the context of such framework.

If previously I focused on the description of dynamic message parsing, in this blog I’ll approach the challenge of dynamic execution of mappings. That means, the execution of mapping artifacts (procedures, graphical mapping routines or even XSL transformations) that are not fixed during design time and are only retrieved from configuration assets in runtime.

 

The Problem

Let’s say that we need to implement a flow that performs a mapping between two messages, an XML document (source) and a DFDL model (target). However, there might be already multiple versions of both source and target messages that need to be supported, which slightly changes the behavior of the mapping. Additionally, the source message might arrive in additional formats depending on the partner sending it (like JSON and XML), or you may need to deliver the message also as a CSV file for a legacy system. How do we approach this?

The more straightforward approach would be to create a flow containing a mapping from the source document to the target document, implemented as any of the supported mappings in ACE (XSLT, graphical mapping, Java, ESQL…). Then if a new version needs to be supported, we modify our mapping, handling the particularities and differences of them. If new formats need to be supported later, we can just throw a few IF statements in the mix to branch all possible behavior.

While this will work for a while, things might start to get messy when the number of formats or versions increase, so you will probably want to refactor your development and create a mapping artifact for each combination of message type and version of the source and target messages.

But does that mean that you need now to add multiple nodes in your flow for executing each of the different mappings you have defined? Or do you need to create multiple flows for handling each of them? Absolutely not.

Let’s assume, as in the case of dynamic parsing, that our execution will be configuration driven. That is, we have a configuration (for instance stored in a database model) that guides the execution. In this particular case, the configuration must indicate which mapping artifact to execute according to the combination of message type and version of source and target messages.

Under these assumptions, we can apply the techniques described in the following sections to achieve dynamic mapping execution.

Note that the handling of the configuration is not the subject of this blog and won’t be described in detail, but it will be noted when parts of the configuration will be required in the proposed solutions.

Additionally, take also into account that most mappings will require parsed messages to work. For dynamically parsing messages in runtime please check my previous blog.

Dynamic Mapping as a Java or ESQL Function

This covers the case in which the mappings are defined either as a Java method or an ESQL function (or procedure).

In the pure Java case in which a Java mapping method is called from Java code (Java compute node) this is no issue since the language provides capabilities to do so. You can for instance define each mapping as a different class, all of them implementing a Mapper interface with a map method. We just need to instantiate each particular mapper class using the Class.forName() method, passing the name of your class as parameter (which you get from your configuration in the database) and then create an object of it with the newInstance() method.

Mapper myMapper = (Mapper)Class.forName(<myMappingClassName>).newInstance();

myMapper.map(<sourceMessage>, …);

 

In the case of calling an ESQL function from ESQL (in an ESQL compute node) the challenge lies in calling a function whose name is unknown during implementation phase but will only be known during runtime.

Although it is not possible to directly resolve a variable as the name of a function to be called via the CALL statement, we can make use of the EVAL function.

The EVAL function takes a character value and interprets that value as an ESQL expression that returns a value. This means that you can generate your call statement to the mapping function as a character string, and then call the EVAL function with such string as parameter in order to execute it.

DECLARE callStatement CHARACTER;

SET callStatement = ‘CALL ’ || varMyMappingFunctionName || ‘(‘ || varParam1 || ‘, ‘ || varParam2 … || varParamN || ‘)’;

EVAL(callStatement);

This will work fine if your function is found in the same broker schema as the code that executes the EVAL function. Otherwise, you need to remember to add the broker schema before the function name in the character expression, as in varMyMappingSchema.varMyMappingFunctionName.

DECLARE callStatement CHARACTER;

SET callStatement ‘CALL ‘ || varMyMappingSchema || ‘.’ || varMyMappingFunctionName || ‘(‘ || varParam1 || ‘, ‘ || varParam2 … || varParamN || ‘)’;

EVAL(callStatement);

This will work the same even if your function is defined in a shared library (as long as the dependency to the library is correctly declared in your calling application of course).

 

The mixed scenario in which we call a Java method from ESQL (from an ESQL compute node) works the same as the previous use case, with the only prerequisite of redefining the Java method in ESQL using the LANGUAGE clause with the JAVA value and EXTERNAL NAME pointing to the path of your Java method (including package and class name). This is standard behavior in ACE, if you require more information, please check the documentation.

 

Dynamic Mapping as a Graphical Mapping

 

When you drop a mapping node in your flow canvas, both the node and a mapping routine are created. What you may not be aware of, is that you may define additional mapping routines (even in a shared library) and set them as the one to be executed in your mapping at runtime. You do so by creating a Message Map object and configuring the required information.

 

 

Once your mapping is created and implemented you can execute it in any mapping node declared in an application with access to the message map object. This is done by using LocalEnvironment overrides, which will take precedence over the values configured in the mapping node itself. The value to modify is Mapping.MappingRoutine, that can be set in a compute node prior to the mapping node.

SET OutputLocalEnvironment.Mapping.MappingRoutine = ‘{‘ || varMyMappingRoutineName || ‘}’;

Note that the whole string needs to be provided enclosed in curly braces. In case it is necessary to specify a broker schema then it needs to be concatenated before the mapping routine name, with a colon symbol as separator, and enclosed itself in curly braces as well:

SET OutputLocalEnvironment.Mapping.MappingRoutine = ‘{{‘ || varMyMappingSchema || ‘}:’ || mapping.MappingRoutineName || ‘}’;

Something else to consider in this use case, is that you always need to define a default or dummy mapping routine in design time and assign it to your mapping node, otherwise your flow will show compilation errors.

 

Dynamic Mapping as XSL Mapping

 

Just as in the case of graphical mapping, an XSL transformation node can see some of its node properties overridden in the local environment.

In this case we can make use of the override XSL.StyleSheetName which can be configured in a compute node prior to the XSL transform node by assigning the name of the XSL transformation file, which needs to be available in your application.

SET OutputLocalEnvironment.XSL.StyleSheetName = varMyXslMappingName;

Unfortunately, XSL transformations can’t be stored in shared libraries, so if you want to store them externally to your application, the only alternative is to do it in the file system in a location reachable by your integration server. In tion file in the file system must be assigned to the local environment override LocalEnvironment/XSL/StyleSheetName.

You can also set local environment overrides to configure the parsing options of the XSL transformation output message, which are analogous to the ones in the PARSE clause of the CREATE statement as described in the previous blog:

XSL.MessageDomain

XSL.MessageSet

XSL.MessageType

XSL.MessageFormat

XSL.OutputCharSet

Uniquely, XSL transformations can be also determined by the content of the message. If an input message contains the following declaration:

<?xml-stylesheet type=”text/xsl” href=”myXslTransformation.xsl”?>

Then myXslTransformation.xsl will be executed by the XSL transformation node.

The message content takes in fact the highest precedence over both the local environment and the node properties.

 

Closing

In this blog we have focused on the concept of dynamic message mapping in App Connect Enterprise, describing first the options for code base mappings. This includes Java mappings called from Java code, ESQL mappings called from ESQL code and Java mappings called from ESQL code.

We have continued describing how to achieve dynamic mapping in the context of graphical mappings, defined locally or in a library, by using local environment overrides.

Finally, we have described how to apply dynamic mapping to XSL transformations (either described locally or stored in the file system) via two methods: via local environment overrides and by declaring it in the message content.

 

Written by Eduardo Cabezas

IBM Integration Specialists

Enabling Digital Transformations.

Let's get in touch...

info@integrationdesigners.com

​ Find us here

Belgium
Veldkant 33B
2550 Kontich

Netherlands
Cruquiusweg 110F
1019 AK Amsterdam

© 2019 Integration Designers - Privacy policy - Part of Cronos Group CBX