public static final class EventPattern.Builder extends Object
Builder is the only way to create an
EventFeed instance. Event patterns are built in
two stages: parameters and pattern. Since the pattern
references the parameters, parameters must be defined
first. This can be done by either providing a parameters
map to the builder or defining parameters in the builder.
The following annotated code example demonstrates how
event parameters are defined using a an
EventPattern.Builder:
// Pattern name "Trade Blip" is the MatchEvent subject.
// This is an ordered pattern meaning events must arrive in the specified order to match the pattern.
final EventPattern.Builder builder = EventPattern.builder("Trade Blip", EventPattern.PatternType.ORDERED);
// First parameter is an order report for the ACME equity symbol.
final MessageKey orderKey = new EMessageKey(OrderReport.class, "ACME");
// Second parameter is a trade report for the ACME equity symbol.
final MessageKey tradeKey = new EMessageKey(EquityTrade.class, "ACME");
builder.beginParameterMap() // Must specify this before defining parameters
.beginParameter("ord") // Parameter name is used in the pattern below.
.messageKey(orderKey) // 1. Specify a ESubscribeFeed (required).
.scope(EFeed.FeedScope.REMOTE_ONLY) // 2. Specify the subscribe feed scope (required).
// 3. Subscription condition is optional and not defined.
.endParameter() // Parameter "ord" defined.
.beginParameter("trd")
.messageKey(tradeKey)
.scope(EFeed.FeedScope.REMOTE_ONLY)
.endParameter() // Parameter "trd" defined.
.endParameterMap() // All parameters defined.
// Ordered pattern defined starting here.
If multiple event parameters are based on the same
parameters, then defining a parameter map once for all
patterns is desirable. The map definition is
Map<String, EventPattern.FeedInfo> where the
String key is the parameter name used in the
preceding example and the FeedInfo defines the
ESubscribeFeed. The parameter map definition is
similar to the previous EventPattern.Builder
example:
// All parameters use the new word feed.
final EMessageKey orderKey = new EMessageKey(OrderReport.class, "ACME");
final EMessageKey tradeKey = new EMessageKey(EquityTrade.class, "ACME");
final Map<String, EventPattern.FeedInfo> params = new HashMap<>();
// Defining "ord" parameter.
params.put("ord", // Parameter name is used in pattern definition.
new EventPattern.FeedInfo(orderKey, // 1. Define ESubscribeFeed message key (required).
EFeed.FeedScope.REMOTE_ONLY // 2. Define subscribe feed scope (required).
// 3. Subscription condition is optional and not provided here.
));
// Defining "trd" parameter.
params.put("trd",
new EventPattern.FeedInfo(tradeKey,
EFeed.FeedScope.REMOTE_ONLY));
// Create builder using the parameter map.
final EventPattern.Builder builder = EventPattern.builder("Trade Blip", EventPattern.PatternType.ORDERED, params);
A single component is associated with a single parameter and has two optional properties: match count and match condition.
A match count specifies how the minimum and maximum times
an event must contiguously appear in the pattern.
matchCount(2, 4) means that the event must appear
at least twice in succession and at most four times. If
the event occurs only once and is followed by a different
event or more than 4 times in succession, then the pattern
match fails.
A match condition is a
MatchCondition where the two
arguments are the latest event and a read-only list of
the previously matched events. This method returns
true if the current event matches the pattern
condition, allowing the matching process to continue or
complete. When false is returned, then this
current match fails.
The match condition takes three arguments: the latest, unmatched event, the capturing groups map, and the user-defined data map.
Like Pattern, one or more named
capturing groups map be defined using
beginGroup(String) and
endGroup(String). Any matching events
which occur between beginGroup and
endGroup are stored in a List associated
with the group name. Capturing group lists are retrieved
from the group map using the group name as the key.
All event patterns have one capturing group:
EventPattern.ALL_EVENTS. The "all events" group
contains all matched events.
eBus provides pattern client with a map to store
user-defined data. This map is carried through the
matching process, allowing MatchConditions to
access information calculated in earlier matches. If a
pattern is successfully matched, then this forwarded in
MatchEvent.userCache in case this user-defined
information is needed for post-match processing.
The user-defined map is typed
Map<Object, Object> so as to allow the
user full flexibility with respect what Objects
may be used as keys and values.
A multi-component acts like a Java regular expression
character class with a quantifier
[abc]{n, m}.
Multi-components are composed of multiple single
components. Each single component may have an optional
match condition but not a match count. That is
because the match count is applied to the multi-component
as a whole. The following is a multi-component example
picks up where the previous examples left off. The pattern
parameters are defined and the pattern builder
instantiated. Now it is time to define the event pattern
itself.
builder.beginGroup("g0") // opening the "g0" named capturing group
.beginMultiComponent() // Begin the multi-component definition.
.matchCount(1, 2) // The subcomponents may appear once or twice
// MatchCondition parameters:
// e: latest event
// g: named capturing groups map where key is the group name.
// u: user-defined data cache.
.addSubordinate("ord", // Either the first event is an order with quantity > 1,000 OR ...
(e, g, u) -> {
final OrderReportMessage ord = (OrderReportMessage) e;
final boolean retcode = (ord.tradedQuantity > 1_000);
// If the order event meets the condition, then store the trade.
if (retcode) {
// Average price calculation requires:
// 1. Sumation of trade prices.
// 2. Number of trades.
u.put(sum, BigDecimal.valueOf(ord.tradedPrice));
u.put(count, BigDecimal.ONE);
}
return (retcode);
})
.addSubordinate("trd", // ... a trade at the currently lowest price for the trading session.
(e, g, u) -> {
final EquityTradeMessage trd = (EquityTradeMessage) e;
final boolean retcode = (trd.tradeType == PriceType.LOW);
if (retcode) {
u.put(sum, (trd.trade).price);
u.put(count, BigDecimal.ONE);
}
return (retcode);
})
.endMultiComponent() // Multi-component definition ended.
.endGroup("g0")
.beginGroup("g1") // Collect all the middle trades.
.beginSingleComponent("trd")
.matchCount(4, Integer.MAX_VALUE) // Look for at least four trades with increasing prices.
.matchCondition( // Get the all matched events list (so far) and calculate the average trade price.
(e, g, u) -> {
final EquityTradeMessage trd = (EquityTradeMessage) e;
final BigDecimal trdPx = (trd.trade).price;
final BigDecimal pxSum = (BigDecimal) u.get(sum);
final BigDecimal numTrades = (BigDecimal) u.get(count);
final BigDecimal avgPx = pxSum.divide(numTrades);
final boolean retcode = (trdPx.compareTo(avgPx) > 0);
// If this trade met the condition, then add its price to the sum.
if (retcode) {
u.put(sum, pxSum.add(trdPx));
u.put(count, numTrades.add(BigDecimal.ONE));
}
return (retcode);
})
.endSingleComponent()
.endGroup("g1")
.beginSingleComponent("trd") // Look for a final trade with a quantity less than 80% of the previous trade.
.matchCondition(
(e, g, u) -> {
final EquityTrade trade = (EquityTrade) e;
final List<ENotificationMessage> trades = g.get(EventPattern.ALL_EVENTS);
final EquityTrade prevTrade = (EquityTrade) (trades.get(trades.size() - 1));
return ((trade.trade).size < (int) (0.8 * (prevTrade.trade).size));
})
.endSingleComponent(); // End of pattern definition.
An unordered pattern matches events based on match count
only, allowing events to arrive in no particular order.
Once the desired number of events are collected, then a
MatchEvent is generated and passed to the
subscriber.
The following looks for at least 5 consecutive orders and trades demonstrating a price rise and there must be at least one order and one trade. This example uses the same parameter map as used in the ordered pattern example.
builder.beginSingleComponent("ord")
.matchCount(4)
.endSingleComponent()
.beginSingleComponent("trd")
.matchCount(4)
.endSingleComponent()
The above pattern is not enough to guarantee the pattern requirement for at least one order and one trade. This is done using a pattern condition (which see).
There are three attributes which apply to the entire
pattern:
until(condition),
isExclusive(flag) and
patternCondition(Predicate).
Builder.until(condition) says that the pattern
match is valid as long as condition returns
true. If the condition returns false, then
the current match is abandoned. The most common use is
by comparing the first and latest message timestamps and
continuing the match as long as the time difference is
within a time limit. The default until condition
always returns true.
builder.until(// Keep matching as long as the first and latest events are within one hour.
// t: all collected matching events so far.
// e: latest event.
(t, e) ->
{
final long duration = (e.timestamp - (t.get(0)).timestamp);
return (duration <= ONE_HOUR_LIMIT);
})
Builder.isExclusive(flag) specifies whether events
appearing in one successful within a pattern may be used
for another match within the same pattern. If
flag is true, then events may not be
shared between matches. This means that once a match
occurs, then all in-progress matches are thrown away and
matching starts from scratch.
Please note that exclusivity applies only within a pattern and note between patterns. The same event may be used to satisfy two different patterns.
builder.isExclusive(true);
A pattern condition is applied to the generated
MatchEvent. Only if the condition returns
true is the match event posted to the subscriber
and if the pattern is exclusive are the other
in-progress matches discarded.
The pattern condition is optional. If not defined, the
default pattern condition always returns true.
Continuing with the unordered pattern example, the following pattern condition guarantees at least one order and one trade.
builder.patternCondition(
p ->
{
final List<ENotificationMessage> events = p.group(EventPattern.ALL_EVENTS);
final boolean hasOrder = containsClass(OrderReport.class, events); // containsClass returns true if the list contains at least one instance of the class.
final boolean hasTrade = containsClass(EquityTrade.class, events);
return (hasOrder && hasTrade);
});
Once the event parameters, event pattern, and pattern
attributes are defined, an EventPattern instance
is created using build().
final EventPattern pattern = builder.build();| Modifier and Type | Method and Description |
|---|---|
EventPattern.Builder |
addSubordinate(String paramName)
Adds a subordinate, unconditional single component to
the current multi-component.
|
EventPattern.Builder |
addSubordinate(String paramName,
MatchCondition predicate)
Adds a subordinate, conditional single component to
the current multi-component.
|
EventPattern.Builder |
beginGroup(String groupName)
Creates a new named capture group.
|
EventPattern.Builder |
beginMultiComponent() |
EventPattern.Builder |
beginParameter(String name)
Begin a parameter definition for the given parameter
name.
|
EventPattern.Builder |
beginParameterMap()
Begins the parameter map definition.
|
EventPattern.Builder |
beginSingleComponent(String paramName)
Begins the collection of event pattern single parameter
component.
|
EventPattern |
build()
Returns a new event pattern constructed from the
parameter map, components, and until duration entered
into
this builder. |
EventPattern.Builder |
condition(ECondition condition)
Sets the optional subscription feed condition.
|
EventPattern.Builder |
endGroup(String groupName)
Closes the named capture group.
|
EventPattern.Builder |
endMultiComponent() |
EventPattern.Builder |
endParameter()
Ends the event pattern parameter definition using the
previously specified name, event message key, and
event feed scope.
|
EventPattern.Builder |
endParameterMap()
Ends the parameter map definition which begins the
event pattern definition.
|
EventPattern.Builder |
endSingleComponent()
Adds the defined single event pattern component to the
component list.
|
EventPattern.Builder |
isExclusive(boolean flag) |
EventPattern.Builder |
matchCondition(MatchCondition p)
Sets the component match condition to the given
predicate.
|
EventPattern.Builder |
matchCount(int minMax)
Sets the minimum and maximum match counts to the same
value.
|
EventPattern.Builder |
matchCount(int min,
int max)
Sets the minimum and maximum match counts to the given
values.
|
EventPattern.Builder |
messageKey(EMessageKey key)
Sets the parameter notification message key.
|
EventPattern.Builder |
patternCondition(Predicate<MatchEvent> p) |
EventPattern.Builder |
scope(EFeed.FeedScope scope)
Sets the subscription feed scope.
|
EventPattern.Builder |
until(BiPredicate<List<ENotificationMessage>,ENotificationMessage> p) |
public EventPattern.Builder beginParameterMap()
this event pattern builder.IllegalStateException - if parameter map cannot be defined in the current
state.beginParameter(String),
endParameterMap()public EventPattern.Builder endParameterMap()
this event pattern builder.IllegalStateException - if not defining a parameter map or parameter map is
empty (no parameters defined).beginParameterMap(),
beginSingleComponent(String)public EventPattern.Builder beginParameter(String name)
name - parameter name.this event pattern builder.NullPointerException - if name is null.IllegalArgumentException - if name is an empty string.IllegalStateException - if the parameter map is already defined, a parameter
may not be defined in the current state, or the
parameter map already contains the named parameter.endParameter(),
messageKey(EMessageKey),
scope(EFeed.FeedScope),
condition(ECondition)public EventPattern.Builder endParameter()
this event pattern builder.IllegalStateException - if a parameter cannot be ended in the current state or
the parameter is not completely defined.beginParameter(String)public EventPattern.Builder messageKey(EMessageKey key)
key - notification message key.this event pattern builder.NullPointerException - if key is null.IllegalArgumentException - if key is not a notification message key.IllegalStateException - if the notification message key cannot be defined in
the current state or the notification message key is
already defined.scope(EFeed.FeedScope),
condition(ECondition)public EventPattern.Builder scope(EFeed.FeedScope scope)
scope - feed scope.this event pattern builder.NullPointerException - if scope is null.IllegalStateException - if the scope cannot be defined in the current state or
the feed scope is already defined.messageKey(EMessageKey),
condition(ECondition)public EventPattern.Builder condition(ECondition condition)
condition - feed condition. May be null.this event pattern builder.IllegalStateException - if the condition cannot be defined in the current
state or the condition is already defined.public EventPattern.Builder beginSingleComponent(String paramName)
paramName - component uses this feed name.this event pattern builder.IllegalStateException - if a component cannot be defined in the current state.NullPointerException - if paramName is null.IllegalArgumentException - if paramName is empty or does not reference
a known parameter.public EventPattern.Builder endSingleComponent()
this event pattern builder.IllegalStateException - if a single event pattern component is not being
defined.public EventPattern.Builder beginMultiComponent()
public EventPattern.Builder endMultiComponent()
public EventPattern.Builder beginGroup(String groupName)
beginGroup and matching
endGroup call will be stored in this group's
capture list.groupName - capture group name.this event pattern builder.IllegalStateException - if not at the top-level event pattern state (that is,
not inside a pattern component definition).IllegalArgumentException - if groupName is either null, empty, or
redundant. A capture group name may only be used once.public EventPattern.Builder endGroup(String groupName)
groupName - capture group name.this event pattern builder.IllegalStateException - if not at the top-level event pattern state (that is,
not inside a pattern component definition).IllegalArgumentException - if groupName is either null, empty, is
unknown, is EventPattern.ALL_EVENTS, or is not the most
recently opened capture group.public EventPattern.Builder matchCount(int minMax)
minMax - minimum and maximum component match
count.this event pattern builder.IllegalStateException - if a event pattern component is not being defined.IllegalArgumentException - if either min or max is < zero or
min > max.public EventPattern.Builder matchCount(int min, int max)
min - minimum component match count.max - maximum component match count.this event pattern builder.IllegalStateException - if a event pattern component is not being defined.IllegalArgumentException - if either min or max is < zero or
min > max.public EventPattern.Builder matchCondition(MatchCondition p)
condition is null then
sets the match condition to the default
EventPattern.DEFAULT_PREDICATE which always returns
true.p - component match condition.this event pattern builder.IllegalStateException - if a event pattern component is not being defined.public EventPattern.Builder addSubordinate(String paramName)
EventPattern.DEFAULT_PREDICATE.paramName - valid parameter name.this event pattern builder.IllegalArgumentException - if paramName is not a valid parameter name.public EventPattern.Builder addSubordinate(String paramName, MatchCondition predicate)
null. If predicate is
null, then set to EventPattern.DEFAULT_PREDICATE.paramName - valid parameter name.predicate - component match condition. May be
null.this event pattern builder.IllegalArgumentException - if paramName is not a valid parameter name.public EventPattern.Builder until(BiPredicate<List<ENotificationMessage>,ENotificationMessage> p)
public EventPattern.Builder isExclusive(boolean flag)
public EventPattern.Builder patternCondition(Predicate<MatchEvent> p)
public EventPattern build()
this builder.Copyright © 2020. All rights reserved.