Class EventPattern.Builder
- java.lang.Object
-
- net.sf.eBus.feed.pattern.EventPattern.Builder
-
- Enclosing class:
- EventPattern
public static final class EventPattern.Builder extends Object
Builderis the only way to create anEventFeedinstance. 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.Defining Event Parameters
Building Parameters
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.Defining Parameter Maps
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 theStringkey is the parameter name used in the preceding example and theFeedInfodefines theESubscribeFeed. The parameter map definition is similar to the previousEventPattern.Builderexample:// 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);Define Event Patterns
With the event parameters defined, it is now time to define the event pattern. Patterns come in two types: ordered and unordered.Ordered Pattern
Events must arrive in the pattern defined order to generate a match. Order patterns are defined by two components: single and multiple.Single Component
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
MatchConditionwhere the two arguments are the latest event and a read-only list of the previously matched events. This method returnstrueif the current event matches the pattern condition, allowing the matching process to continue or complete. Whenfalseis 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.
CapturingGroups
Like
Pattern, one or more named capturing groups map be defined usingbeginGroup(String)andendGroup(String). Any matching events which occur betweenbeginGroupandendGroupare stored in aListassociated 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.User Cache
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 inMatchEvent.userCachein 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 whatObjects may be used as keys and values.Multi-Component
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.Unordered Patterns
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
MatchEventis 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).
Pattern Attributes
There are three attributes which apply to the entire pattern:
until(condition),isExclusive(flag)andpatternCondition(Predicate).Pattern Until Condition
Builder.until(condition)says that the pattern match is valid as long asconditionreturnstrue. If the condition returnsfalse, 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 defaultuntilcondition always returnstrue.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); })Pattern IsExclusive Flag
Builder.isExclusive(flag)specifies whether events appearing in one successful within a pattern may be used for another match within the same pattern. Ifflagistrue, 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);Pattern Condition
A pattern condition is applied to the generated
MatchEvent. Only if the condition returnstrueis 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); });Pattern Instantiation
Once the event parameters, event pattern, and pattern attributes are defined, an
EventPatterninstance is created usingbuild().final EventPattern pattern = builder.build();
-
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description EventPattern.BuilderaddSubordinate(String paramName)Adds a subordinate, unconditional single component to the current multi-component.EventPattern.BuilderaddSubordinate(String paramName, MatchCondition predicate)Adds a subordinate, conditional single component to the current multi-component.EventPattern.BuilderbeginGroup(String groupName)Creates a new named capture group.EventPattern.BuilderbeginMultiComponent()EventPattern.BuilderbeginParameter(String name)Begin a parameter definition for the given parameter name.EventPattern.BuilderbeginParameterMap()Begins the parameter map definition.EventPattern.BuilderbeginSingleComponent(String paramName)Begins the collection of event pattern single parameter component.EventPatternbuild()Returns a new event pattern constructed from the parameter map, components, and until duration entered intothisbuilder.EventPattern.Buildercondition(ECondition condition)Sets the optional subscription feed condition.EventPattern.BuilderendGroup(String groupName)Closes the named capture group.EventPattern.BuilderendMultiComponent()EventPattern.BuilderendParameter()Ends the event pattern parameter definition using the previously specified name, event message key, and event feed scope.EventPattern.BuilderendParameterMap()Ends the parameter map definition which begins the event pattern definition.EventPattern.BuilderendSingleComponent()Adds the defined single event pattern component to the component list.EventPattern.BuilderisExclusive(boolean flag)EventPattern.BuildermatchCondition(MatchCondition p)Sets the component match condition to the given predicate.EventPattern.BuildermatchCount(int minMax)Sets the minimum and maximum match counts to the same value.EventPattern.BuildermatchCount(int min, int max)Sets the minimum and maximum match counts to the given values.EventPattern.BuildermessageKey(EMessageKey key)Sets the parameter notification message key.EventPattern.BuilderpatternCondition(Predicate<MatchEvent> p)EventPattern.Builderscope(EFeed.FeedScope scope)Sets the subscription feed scope.EventPattern.Builderuntil(BiPredicate<List<ENotificationMessage>,ENotificationMessage> p)
-
-
-
Method Detail
-
beginParameterMap
public EventPattern.Builder beginParameterMap()
Begins the parameter map definition.- Returns:
thisevent pattern builder.- Throws:
IllegalStateException- if parameter map cannot be defined in the current state.- See Also:
beginParameter(String),endParameterMap()
-
endParameterMap
public EventPattern.Builder endParameterMap()
Ends the parameter map definition which begins the event pattern definition.- Returns:
thisevent pattern builder.- Throws:
IllegalStateException- if not defining a parameter map or parameter map is empty (no parameters defined).- See Also:
beginParameterMap(),beginSingleComponent(String)
-
beginParameter
public EventPattern.Builder beginParameter(String name)
Begin a parameter definition for the given parameter name. The associated notification message key and feed scope must be defined next. The subscription condition is optional.- Parameters:
name- parameter name.- Returns:
thisevent pattern builder.- Throws:
NullPointerException- ifnameisnull.IllegalArgumentException- ifnameis 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.- See Also:
endParameter(),messageKey(EMessageKey),scope(EFeed.FeedScope),condition(ECondition)
-
endParameter
public EventPattern.Builder endParameter()
Ends the event pattern parameter definition using the previously specified name, event message key, and event feed scope.- Returns:
thisevent pattern builder.- Throws:
IllegalStateException- if a parameter cannot be ended in the current state or the parameter is not completely defined.- See Also:
beginParameter(String)
-
messageKey
public EventPattern.Builder messageKey(EMessageKey key)
Sets the parameter notification message key.- Parameters:
key- notification message key.- Returns:
thisevent pattern builder.- Throws:
NullPointerException- ifkeyisnull.IllegalArgumentException- ifkeyis 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.- See Also:
scope(EFeed.FeedScope),condition(ECondition)
-
scope
public EventPattern.Builder scope(EFeed.FeedScope scope)
Sets the subscription feed scope.- Parameters:
scope- feed scope.- Returns:
thisevent pattern builder.- Throws:
NullPointerException- ifscopeisnull.IllegalStateException- if the scope cannot be defined in the current state or the feed scope is already defined.- See Also:
messageKey(EMessageKey),condition(ECondition)
-
condition
public EventPattern.Builder condition(ECondition condition)
Sets the optional subscription feed condition.- Parameters:
condition- feed condition. May benull.- Returns:
thisevent pattern builder.- Throws:
IllegalStateException- if the condition cannot be defined in the current state or the condition is already defined.
-
beginSingleComponent
public EventPattern.Builder beginSingleComponent(String paramName)
Begins the collection of event pattern single parameter component.- Parameters:
paramName- component uses this feed name.- Returns:
thisevent pattern builder.- Throws:
IllegalStateException- if a component cannot be defined in the current state.NullPointerException- ifparamNameisnull.IllegalArgumentException- ifparamNameis empty or does not reference a known parameter.
-
endSingleComponent
public EventPattern.Builder endSingleComponent()
Adds the defined single event pattern component to the component list.- Returns:
thisevent pattern builder.- Throws:
IllegalStateException- if a single event pattern component is not being defined.
-
beginMultiComponent
public EventPattern.Builder beginMultiComponent()
-
endMultiComponent
public EventPattern.Builder endMultiComponent()
-
beginGroup
public EventPattern.Builder beginGroup(String groupName)
Creates a new named capture group. All captured events between thisbeginGroupand matchingendGroupcall will be stored in this group's capture list.- Parameters:
groupName- capture group name.- Returns:
thisevent pattern builder.- Throws:
IllegalStateException- if not at the top-level event pattern state (that is, not inside a pattern component definition).IllegalArgumentException- ifgroupNameis eithernull, empty, or redundant. A capture group name may only be used once.
-
endGroup
public EventPattern.Builder endGroup(String groupName)
Closes the named capture group. The named group must be the most recently opened group. This is because capture groups must be opened and closed in last-in-first-out (LIFO) order.- Parameters:
groupName- capture group name.- Returns:
thisevent pattern builder.- Throws:
IllegalStateException- if not at the top-level event pattern state (that is, not inside a pattern component definition).IllegalArgumentException- ifgroupNameis eithernull, empty, is unknown, isEventPattern.ALL_EVENTS, or is not the most recently opened capture group.
-
matchCount
public EventPattern.Builder matchCount(int minMax)
Sets the minimum and maximum match counts to the same value.- Parameters:
minMax- minimum and maximum component match count.- Returns:
thisevent pattern builder.- Throws:
IllegalStateException- if a event pattern component is not being defined.IllegalArgumentException- if eitherminormaxis < zero ormin>max.
-
matchCount
public EventPattern.Builder matchCount(int min, int max)
Sets the minimum and maximum match counts to the given values.- Parameters:
min- minimum component match count.max- maximum component match count.- Returns:
thisevent pattern builder.- Throws:
IllegalStateException- if a event pattern component is not being defined.IllegalArgumentException- if eitherminormaxis < zero ormin>max.
-
matchCondition
public EventPattern.Builder matchCondition(MatchCondition p)
Sets the component match condition to the given predicate. Ifconditionisnullthen sets the match condition to the defaultEventPattern.DEFAULT_PREDICATEwhich always returnstrue.- Parameters:
p- component match condition.- Returns:
thisevent pattern builder.- Throws:
IllegalStateException- if a event pattern component is not being defined.
-
addSubordinate
public EventPattern.Builder addSubordinate(String paramName)
Adds a subordinate, unconditional single component to the current multi-component. The single component match condition is set toEventPattern.DEFAULT_PREDICATE.- Parameters:
paramName- valid parameter name.- Returns:
thisevent pattern builder.- Throws:
IllegalArgumentException- ifparamNameis not a valid parameter name.
-
addSubordinate
public EventPattern.Builder addSubordinate(String paramName, MatchCondition predicate)
Adds a subordinate, conditional single component to the current multi-component. The condition is optional and may benull. Ifpredicateisnull, then set toEventPattern.DEFAULT_PREDICATE.- Parameters:
paramName- valid parameter name.predicate- component match condition. May benull.- Returns:
thisevent pattern builder.- Throws:
IllegalArgumentException- ifparamNameis not a valid parameter name.
-
until
public EventPattern.Builder until(BiPredicate<List<ENotificationMessage>,ENotificationMessage> p)
-
isExclusive
public EventPattern.Builder isExclusive(boolean flag)
-
patternCondition
public EventPattern.Builder patternCondition(Predicate<MatchEvent> p)
-
build
public EventPattern build()
Returns a new event pattern constructed from the parameter map, components, and until duration entered intothisbuilder.- Returns:
- the built event pattern.
-
-