Apama Documentation : Connecting Apama Applications to External Components : Working with Connectivity Plug-ins : Developing Connectivity Plug-ins : Map contents used by the apama.eventMap host plug-in
Map contents used by the apama.eventMap host plug-in
The payloads that the apama.eventMap generates for transportward messages and that it requires for hostward messages are maps. For Java chains, this is java.util.Map<Object, Object>. For C++ chains, this is a map_t.
Each key in the map is the name of a field in the EPL event definition and the value the corresponding EPL value. Each event containing other events is represented as a Map value within the top-level field, allowing nesting of events, dictionaries and sequences. For events sent from chains into the correlator, all fields must have non-empty values and must be present as keys in the map, unless the configuration setting allowMissing is set to true. Keys that do not correspond to fields are ignored by default. There is one exception: an empty value that maps to an optional<type> in EPL is permitted even if allowMissing is false (see also optional).
Events can be annotated with the com.softwareag.connectivity.ExtraFieldsDict annotation (see Adding predefined annotations) which names a dictionary<string,string> field, in which case any unmapped keys are placed into this dictionary field. All unmapped keys must be String keys and have string (or numeric) values. This can be disabled with the extraFields configuration property.
The types are converted as described below:
EPL type
Transportward events will contain Java or C++ type
Hostward events can also convert from types
Event
java.util.Map or map_t
dictionary
java.util.Map or map_t
sequence
java.util.List or list_t
location
java.util.Map or map_t (keys are x1, y1, x2, y2)
com.apama.Channel
java.lang.String or const char* (if it is a string channel)
string
java.lang.String or const char*
all numeric types, boolean
integer
java.lang.Long or int64_t
all numeric types (except NaN float values), strings if they can be parsed as an integer
float
java.lang.Double or double
all numeric types, strings if they can be parsed as a float
decimal
java.math.BigDecimal (but see the notes below) or decimal_t
all numeric types, strings if they can be parsed as a float
boolean
java.lang.Boolean or bool
string, if true or false
optional
EPL values of type optional<T> translate into one of the following:
*null or corresponding Java type (see above conversions), or
*a data_t that is either empty or of type T (see the above conversions).
A Java object or data_t that corresponds to an EPL value of type optional<T> is translated if
*the Java object is null or of type T,
*data_t is empty or of type T.
Non-native conversions (a floating point to integer conversion or vice versa) may lose precision, and conversions to/from strings or decimals are more expensive than float or integer conversions. If anything other than an exact match is found, a debug-level log message is generated; you may wish to verify that there are none if the conversion is performance-sensitive.
The following applies to Java only: an EPL decimal value which is NaN (not a number) or an infinity is mapped to/from a Double representation of NaN or infinity, as the BigDecimal Java type does not support them.
Events containing the following types cannot be sent into the correlator, as they cannot be serialized:
*chunk
*listener
*action variables
Events containing the following can be sent in, provided allowMissing is set to true in the host plug-in configuration and no value is provided for that field:
*context
*com.apama.exceptions.Exception
*com.apama.exceptions.StackTraceElement
Events containing cycles cannot be sent into or out of the correlator, but arbitrary nesting is permitted. Aliases will be flattened.
For Java plug-ins, handling messages from the apama.eventMap plug-in thus involves casting the payload of the message from Object to Map, and then accessing members of that, casting as necessary (or, for flexibility, introspecting their types by using the instanceof operator). For example, for the following event definition, the CustomerOrder is translated to a map with deliveryAddress, userId and items keys, and items will be a list of maps containing itemId, price and qty.
event LineItem {
string itemId;
float price;
integer qty;
}
event CustomerOrder {
string deliveryAddress;
string userId;
sequence<LineItem> items;
}
To print the total cost of an order (sum of product of qty and price for each item), the Java code would be as follows:
public void deliverMessageTowardsTransport(Message message) {
Map payload = (Map) message.getPayload();
List<Map> items = (List<Map>) payload.get("items");
double total = 0.0;
for(Map item : items) {
double price = MapHelper.getDouble(item, "price");
long qty = MapHelper.getInteger(item, "qty");
total = total + price * qty;
}
logger.info("Order value is "+total);
}
Note that due to type erasure, the type parameters on Map or List are not checked or guaranteed. In the above example, it is convenient to cast the list representing EPL field sequence<LineItems> to List<Map> to avoid having to cast the entries within it. The Map, however, is still treated as a map of objects as it has different types (String, Double, Long) in it.
For C++ plug-ins, handling messages from the apama.eventMap plug-in involves using the get<map_t> function and accessing the members of that, using get<> as necessary. If code needs to be flexible as to which type it accepts, then use the visitor pattern (see C++ data types). For example, using the event definition above, the following C++ code will print the total cost of the order:
virtual void deliverMessageTowardsTransport(Message &message) {
map_t &payload = get<map_t>(message.getPayload());
list_t &items = get<list_t>(payload[data_t("items")]);
double total = 0.0;
for(auto it = items.begin(); it != items.end(); it++) {
map_t &item = get<map_t>(*it);
double price = MapHelper::getDouble(item, "price");
long qty = MapHelper::getInteger(item, "qty");
total = total + price * qty;
}
logger.info("Order value is %f", total);
}
The following constructs and sends an order with one line item into the correlator:
Map<String,Object> payload = new HashMap<>();
payload.put("deliveryAddress", "1 Roadsworth Avenue");
payload.put("userId", "jbloggs");
List<Map> items = new ArrayList<>();
Map<String,Object> item = new HashMap<String,Object>();
item.put("itemId", "item1");
item.put("price", 3.14);
item.put("qty", 10);
items.add(item);
payload.put("items", items);

Map<String, String> metadata = new HashMap<String, String>();
metadata.put(Message.HOST_MESSAGE_TYPE, "CustomerOrder");
Message msg = new Message(payload, metadata);
hostSide.sendBatchTowardsHost(Collections.singletonList(msg));
The above can also be written more compactly:
hostSide.sendBatchTowardsHost(Collections.singletonList(new
Message(payload).putMetadataValue(Message.HOST_MESSAGE_TYPE,"CustomerOrder")));
This would typically be done in a more automated fashion, translating data from some other form, rather than laboriously setting each field as needed - though some combination will often be needed.
The equivalent C++code is:
map_t payload;
payload.insert(data_t("deliveryAddress"), data_t("1 Roadsworth Avenue"));
payload.insert(data_t("userId"), data_t("jbloggs"));
list_t items;
map_t item;
item.insert(data_t("itemId"), data_t("item1"));
item.insert(data_t("price"), data_t(3.14));
item.insert(data_t("qty"), data_t((int64_t) 10));
items.push_back(data_t(std::move(item)));
payload[data_t("items")] = data_t(std::move(items));

Message msg(data_t(std::move(payload)));
msg.putMetadataValue(Message::HOST_MESSAGE_TYPE(), "CustomerOrder");
hostSide->sendBatchTowardsHost(&msg, (&msg)+1);
Copyright © 2013-2017 Software AG, Darmstadt, Germany. (Innovation Release)

Product LogoContact Support   |   Community   |   Feedback