Apama 10.7.2 | Connecting Apama Applications to External Components | Standard Connectivity Plug-ins | Codec Connectivity Plug-ins | The Mapper codec connectivity plug-in
 
The Mapper codec connectivity plug-in
The Mapper codec can be used to take messages from a transport which do not match the schema expected by the host and turn them into messages which are suitable for the host. Typically this means making sure that the fields in the message have the same names as the fields in the corresponding EPL event type if you are using the apama.eventMap host plug-in (see also Translating EPL events using the apama.eventMap host plug-in). This codec can move fields around between the payload and the metadata and set the values of fields which have no value from the transport. It is bidirectional and can also map messages coming from the host into a format suitable for the transport.
The source code for this plug-in is also shipped as a sample in the samples/connectivity_plugin/cpp/mapper directory of your Apama installation.
To reference the Mapper codec, an entry such as the following is required in the connectivityPlugins section of the configuration file (see also Configuration file for connectivity plug-ins):
mapperCodec:
libraryName: MapperCodec
class: MapperCodec
You then need to add mapperCodec into your connectivity chains with the configuration for that instance. If you are also using the Classifier codec to assign types to incoming messages, then you must have that codec on the transport side of the Mapper codec. An example configuration may look as follows:
- mapperCodec:
allowMissing: true
SomeType:
towardsHost:
mapFrom:
- metadata.targetField1: metadata.sourceField1
- payload.myField2: metadata.myField2
- metadata.targetField3: payload.sourceField3
# to set the correlator channel on a per-message basis:
- metadata.sag.channel: payload.mychannel
# to move all fields from payload to metadata, use:
# - metadata: payload
copyFrom:
- metadata.targetField4: metadata.sourceField4
forEach:
- payload.listA:
mapFrom:
- targetFieldA: sourceFieldA
copyFrom:
- targetFieldB: sourceFieldB
set:
- payload.fieldName: An overridden value
defaultValue:
- payload.targetFieldX: A default value

towardsTransport:
mapFrom:
- metadata.myField2: payload.myField2
- payload.sourceField3: metadata.targetField3

"*":
towardsHost:
defaultValue:
- payload.targetFieldY: A different value
An example message input and output for the above mapping a SomeType event towards the host, as logged by the Diagnostic codec (with extra spacing to make it clearer), is:
[premap] Towards Host: {myField2:Field2,
sag.type:SomeType,
sourceField4:Field4,
sourceField1:Field1} /
{listA:[{sourceFieldB:Beta,
sourceFieldA:Alpha},
{sourceFieldB:Brian,
sourceFieldA:Andrew}],
fieldName:Gamma,
sourceField3:Field3}


[postmap] Towards Host: {targetField3:Field3,
sag.type:SomeType,
targetField1:Field1,
sourceField4:Field4,
targetField4:Field4} /
{listA:[{targetFieldA:Alpha,
sourceFieldB:Beta,
targetFieldB:Beta},
{targetFieldA:Andrew,
sourceFieldB:Brian,
targetFieldB:Brian}],
fieldName:An overridden value,
myField2:Field2,
targetFieldX:A default value,
targetFieldY:A different value}
The configuration of the Mapper codec is nested, with a map of type names, each containing directions, each containing actions, each containing rules. The type name corresponds to the sag.type metadata field (see Metadata values). Instead of the name of a type, the special symbol "*" (which must include the quotes so that it can be parsed in the YAML format correctly) can be used to list rules to apply to all types. Messages are first processed with any rules matching their specific type, then any rules under "*" are applied.
The rules for a type are split into two directions:
*towardsHost - Messages going from the transport to the host.
*towardsTransport - Messages going from the host to the transport.
If you are writing a bidirectional chain, these rules will usually be the converse of each other.
Within a direction, the following actions can be applied. Each action operates on one or two fields. Each field can be the entire payload, a field within the payload or metadata, or a nested field; see below for details of field names.
*mapFrom - Move a value to a new field from the specified field (target: source).
For the above example configuration, this means that if a message of type SomeType is being passed from the transport towards the host, then the field sourceField1 from the metadata is removed and its value is put into the field targetField1 of the metadata. The second mapFrom rule moves the value of myField2 from the metadata to the payload, using the same field name. It is always the field on the left-hand side of the rule which is the target of the move operation, regardless of whether messages are moving towards the transport or towards the host. For bidirectional message types, it is quite common to have rules in towardsTransport that are the inverse of the towardsHost rules, as is the case for myField2 in this example.
*copyFrom - This action is exactly the same as the mapFrom action except that the source field is not removed after the copy.
*forEach - Iterate through all elements of a given sequence and apply the supplied mapping actions.
For the above example configuration, this means that if a message of type SomeType is being passed from the transport towards the host and if the message payload contains a sequence field listA, then for each element of listA the subrules of mapFrom and copyFrom are applied. That is, for every child element of listA, the field sourceFieldA is mapped to targetFieldA (mapFrom) and the value of field sourceFieldB is copied to targetFieldB (copyFrom).
Note that the rules can only be applied if the child elements of the sequence are another event or a dictionary (with string keys).
*set - Set a metadata field, payload field or the top-level payload to a specific value, regardless of whether that field already exists or not. For the above example configuration, this means that if a message of the type SomeType is being passed from the transport towards the host, then the field fieldName will be set to An overridden value.
*defaultValue - If a metadata field, payload field or top-level payload is unset or empty/null, then set it to a specified value. For the above example configuration, this means that if a message of any type is being passed from the transport towards the host, then the field targetFieldY of its payload is set to A different value if - and only if - that field does not already exist in the map. The following applies:
*A top-level payload can be mapped to a string or map.
*A payload field or metadata field can be mapped to a string, list or map.
Each of the above actions has a list of rules of the form target_field: source (where source is either a field name or a string value). Notes:
*The actions are applied in the following order: copyFrom, mapFrom, forEach, set, defaultValue.
*Rules are applied in order within each action section, so you can move the contents out of a field and then replace it with a different value.
*The left-hand side is the field whose value is being set.
In the case of forEach, the left-hand side field corresponds to the sequence to which the subrules are applied.
*Field names must start with metadata. or payload., or must be the string payload or metadata - except for those within a forEach action, in which case they only name a field within an element of the sequence.
*Field names which contain a period (.) refer to nested map structures within the metadata or payload. For example, payload.http.headers.accept refers to a map called http within the payload, which contains a map called headers, which contains an element called accept.
Special cases: in metadata source expressions, a field name with a period (.) in it is looked up at the top-level and used if it is found, otherwise as a nested name. Using the sag. prefix as a target does not create a new map within the metadata.
*A copyFrom or mapFrom rule where the source field does not exist uses the default value if the defaultValue exists or if a subsequent copyFrom or mapFrom rule exists for the same destination field. If none of these fallback options exist (like a defaultValue), then the message is discarded with an error.
*The Mapper codec also accepts an allowMissing configuration item at the top level. This affects all rules in the Mapper codec and defaults to false. If allowMissing is set to true, an error is not raised when a defaultValue (or a subsequent copyFrom or mapFrom rule) has not been set and a source field is missing. allowMissing needs to be defined at the same level as the event types.
*If setting a payload field on a payload that is not a map, the payload is first overwritten with an empty map.
*payload in the left-hand side or right-hand side of a rule (rather than payload.fieldname) refers to the entire payload object. This allows you, for example, to map an entire string payload into a field in a map in the resulting message's payload, or vice-versa.
*Any rules that mention payload.fieldname assume that the payload is a java.util.Map (Java) or map_t (C++) with string keys.