Skip to content
This repository was archived by the owner on Feb 12, 2022. It is now read-only.

Commit 6a9bae5

Browse files
authored
Remove FilterChainBuilder and serialize the steps directly (#130)
* Remove FilterChainBuilder and serialize the steps directly * Simplify and cleanup serialization * Switch to checkNotNull * Move TriggerEvent identification generation into it's self
1 parent e9ca82c commit 6a9bae5

File tree

13 files changed

+255
-302
lines changed

13 files changed

+255
-302
lines changed

pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@
374374
<plugin>
375375
<groupId>org.apache.maven.plugins</groupId>
376376
<artifactId>maven-checkstyle-plugin</artifactId>
377-
<version>2.17</version>
377+
<version>3.1.0</version>
378378
<executions>
379379
<execution>
380380
<id>checkstyle-validate</id>
@@ -467,12 +467,12 @@
467467
<plugin>
468468
<groupId>org.apache.maven.plugins</groupId>
469469
<artifactId>maven-checkstyle-plugin</artifactId>
470-
<version>2.17</version>
470+
<version>3.1.0</version>
471471
<dependencies>
472472
<dependency>
473473
<groupId>com.puppycrawl.tools</groupId>
474474
<artifactId>checkstyle</artifactId>
475-
<version>8.18</version>
475+
<version>8.26</version>
476476
</dependency>
477477
</dependencies>
478478
</plugin>

script/checkstyle-ruleset.xml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020

2121
<module name="SuppressWarningsFilter" />
2222

23+
<module name="LineLength">
24+
<property name="max" value="140"/>
25+
<property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
26+
</module>
27+
2328
<module name="TreeWalker">
2429
<module name="SuppressWarningsHolder" />
2530
<module name="OuterTypeFilename"/>
@@ -33,10 +38,6 @@
3338
<property name="allowByTailComment" value="true"/>
3439
<property name="allowNonPrintableEscapes" value="true"/>
3540
</module>
36-
<module name="LineLength">
37-
<property name="max" value="140"/>
38-
<property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
39-
</module>
4041
<module name="AvoidStarImport"/>
4142
<module name="RedundantImport"/>
4243
<module name="UnusedImports"/>
@@ -175,7 +176,6 @@
175176
<property name="allowMissingParamTags" value="true"/>
176177
<property name="allowMissingThrowsTags" value="true"/>
177178
<property name="allowMissingReturnTag" value="true"/>
178-
<property name="minLineCount" value="2"/>
179179
<property name="allowedAnnotations" value="Override, Test"/>
180180
<property name="allowThrowsTagsForSubclasses" value="true"/>
181181
</module>

src/main/java/com/salesforce/storm/spout/documentation/ConfigDocumentation.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,5 +89,6 @@ public String toString() {
8989
/**
9090
* Default class type for use on the type field.
9191
*/
92-
final class Default {}
92+
final class Default {
93+
}
9394
}

src/main/java/com/salesforce/storm/spout/dynamic/JSON.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import com.salesforce.storm.spout.dynamic.filter.FilterChainStep;
3131
import com.salesforce.storm.spout.sideline.persistence.FilterChainStepSerializer;
3232

33+
import java.util.HashMap;
3334
import java.util.Map;
3435

3536
/**
@@ -47,15 +48,26 @@ public class JSON {
4748
*/
4849
private final Gson gson;
4950

51+
/**
52+
* Create JSON serializer/deserializer instance.
53+
*/
54+
public JSON() {
55+
this(new HashMap<>());
56+
}
57+
5058
/**
5159
* Create JSON serializer/deserializer instance with default configuration.
5260
* @param config configuration.
5361
*/
5462
public JSON(final Map<String, Object> config) {
55-
this.gson = new GsonBuilder()
56-
.setDateFormat("yyyy-MM-dd HH:mm:ss")
57-
.registerTypeAdapter(FilterChainStep.class, new FilterChainStepSerializer(config))
58-
.create();
63+
final GsonBuilder gsonBuilder = new GsonBuilder()
64+
.setDateFormat("yyyy-MM-dd HH:mm:ss");
65+
66+
if (!config.isEmpty()) {
67+
gsonBuilder.registerTypeAdapter(FilterChainStep.class, new FilterChainStepSerializer(config));
68+
}
69+
70+
this.gson = gsonBuilder.create();
5971
}
6072

6173
/**
Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,26 @@
2525

2626
package com.salesforce.storm.spout.sideline.recipes.trigger;
2727

28+
import com.salesforce.storm.spout.dynamic.Message;
2829
import com.salesforce.storm.spout.dynamic.filter.FilterChainStep;
2930

30-
import java.util.Map;
31+
import java.util.List;
3132

3233
/**
33-
* Given a map of a data from a {@link TriggerEvent} implementations of this generate {@link FilterChainStep} instances.
34+
* Filter for filtering messages by their key.
3435
*/
35-
public interface FilterChainStepBuilder {
36+
public class KeyFilter implements FilterChainStep {
3637

37-
/**
38-
* Given a map of a data from a {@link TriggerEvent} implementations of this generate {@link FilterChainStep} instances.
39-
* @param data data from a trigger event.
40-
* @return filter chain step.
41-
*/
42-
FilterChainStep build(final Map<String,Object> data);
38+
private final List<String> filteredKeys;
39+
40+
public KeyFilter(final List<String> filteredKeys) {
41+
this.filteredKeys = filteredKeys;
42+
}
43+
44+
@Override
45+
public boolean filter(Message message) {
46+
final String key = String.valueOf(message.getValues().get(0));
47+
// If the key for this message is contained in our list we filter it out
48+
return filteredKeys.contains(key);
49+
}
4350
}

src/main/java/com/salesforce/storm/spout/sideline/recipes/trigger/TriggerEvent.java

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,13 @@
2626
package com.salesforce.storm.spout.sideline.recipes.trigger;
2727

2828
import com.google.common.base.Preconditions;
29+
import com.salesforce.storm.spout.dynamic.JSON;
30+
import com.salesforce.storm.spout.dynamic.Tools;
31+
import com.salesforce.storm.spout.dynamic.filter.FilterChainStep;
2932
import com.salesforce.storm.spout.sideline.trigger.SidelineType;
3033

3134
import java.time.LocalDateTime;
32-
import java.util.Map;
35+
import java.time.ZoneOffset;
3336
import java.util.Objects;
3437

3538
/**
@@ -40,7 +43,7 @@ public class TriggerEvent {
4043

4144
private SidelineType type;
4245

43-
private Map<String,Object> data;
46+
private FilterChainStep filterChainStep;
4447

4548
private LocalDateTime createdAt;
4649

@@ -55,49 +58,80 @@ public class TriggerEvent {
5558
/**
5659
* An event to a {@link com.salesforce.storm.spout.sideline.trigger.SidelineTrigger} that communicates the desired type of
5760
* sideline state for the system.
58-
*
61+
* <p>
5962
* When you create a TriggerEvent in Zookeeper always set processed = false, the trigger implementation will flip this to true
6063
* after it has been picked up and handled by the trigger. This allows you to distinguish an event that's been handled by the
6164
* trigger and one that has not.
6265
*
63-
* @param type sideline type.
64-
* @param data data bag of key value pairs.
65-
* @param createdAt when the event was created.
66-
* @param createdBy who created the event.
66+
* @param type sideline type.
67+
* @param filterChainStep filter chain step
68+
* @param createdAt when the event was created.
69+
* @param createdBy who created the event.
6770
* @param description a description of the reason for the sideline request.
68-
* @param processed whether or not the event (in its current state has been processed)
69-
* @param updatedAt Timestamp the event was last updated.
71+
* @param processed whether or not the event (in its current state has been processed)
72+
* @param updatedAt Timestamp the event was last updated.
7073
*/
7174
public TriggerEvent(
7275
final SidelineType type,
73-
final Map<String,Object> data,
76+
final FilterChainStep filterChainStep,
7477
final LocalDateTime createdAt,
7578
final String createdBy,
7679
final String description,
7780
final boolean processed,
7881
final LocalDateTime updatedAt
7982
) {
8083
Preconditions.checkNotNull(type, "Type is required.");
81-
Preconditions.checkNotNull(data, "Data payload is required (But we do accept empty maps!).");
84+
Preconditions.checkNotNull(filterChainStep, "FilterChainStep is required.");
8285
Preconditions.checkNotNull(createdAt, "Created at time is required.");
8386
Preconditions.checkNotNull(createdBy, "Created by is required.");
8487
Preconditions.checkNotNull(description, "Description is required.");
8588

8689
this.type = type;
87-
this.data = data;
90+
this.filterChainStep = filterChainStep;
8891
this.createdAt = createdAt;
8992
this.createdBy = createdBy;
9093
this.description = description;
9194
this.processed = processed;
9295
this.updatedAt = updatedAt;
9396
}
9497

98+
/**
99+
* Generate an identifier for this {@link TriggerEvent}.
100+
*
101+
* The identifier generated here is a JSON serialized version of the {@link FilterChainStep} which we then make
102+
* an md5 hash of. If we have a created date we tack on it's millis to the end for extra uniqueness. It's the
103+
* {@link FilterChainStep} that is the important part of a {@link TriggerEvent} and the assumption here is that
104+
* there are properties that make the given filter unique. For example, if you're filtering out a tenant on a
105+
* multi tenant stream you probably have a generic filter which has a property to hold the given tenant.
106+
*
107+
* If you don't have uniqueness represented in the properties of your filter this whole recipe probably isn't a
108+
* great fit for your use case.
109+
*
110+
* @return string representing the event.
111+
*/
112+
public String getIdentifier() {
113+
// Note: This only works for to() because we only need the implementation name for from()
114+
final String data = (new JSON()).to(getFilterChainStep());
115+
116+
final StringBuilder identifier = new StringBuilder(Tools.makeMd5Hash(data));
117+
118+
// If we were provided a date time in the event, append the time stamp of that event to the identifier
119+
if (this.getCreatedAt() != null) {
120+
identifier.append("-");
121+
identifier.append(
122+
this.getCreatedAt().atZone(ZoneOffset.UTC).toInstant().toEpochMilli()
123+
);
124+
}
125+
126+
return identifier.toString();
127+
}
128+
95129
public SidelineType getType() {
96130
return type;
97131
}
98132

99-
public Map<String,Object> getData() {
100-
return data;
133+
public FilterChainStep getFilterChainStep() {
134+
return filterChainStep;
101135
}
102136

103137
public LocalDateTime getCreatedAt() {
@@ -131,7 +165,7 @@ public boolean equals(Object obj) {
131165
TriggerEvent that = (TriggerEvent) obj;
132166
return processed == that.processed
133167
&& type == that.type
134-
&& Objects.equals(data, that.data)
168+
&& Objects.equals(filterChainStep, that.filterChainStep)
135169
&& Objects.equals(createdAt, that.createdAt)
136170
&& Objects.equals(createdBy, that.createdBy)
137171
&& Objects.equals(description, that.description)
@@ -140,14 +174,14 @@ public boolean equals(Object obj) {
140174

141175
@Override
142176
public int hashCode() {
143-
return Objects.hash(type, data, createdAt, createdBy, description);
177+
return Objects.hash(type, filterChainStep, createdAt, createdBy, description);
144178
}
145179

146180
@Override
147181
public String toString() {
148182
return "TriggerEvent{"
149183
+ "type=" + type
150-
+ ", data=" + data
184+
+ ", filterChainStep=" + filterChainStep
151185
+ ", createdAt=" + createdAt
152186
+ ", createdBy='" + createdBy + '\''
153187
+ ", description='" + description + '\''

src/main/java/com/salesforce/storm/spout/sideline/recipes/trigger/TriggerEventHelper.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import com.google.common.base.Preconditions;
2929
import com.salesforce.storm.spout.dynamic.JSON;
3030
import com.salesforce.storm.spout.dynamic.Tools;
31+
import com.salesforce.storm.spout.dynamic.filter.FilterChainStep;
3132
import com.salesforce.storm.spout.dynamic.persistence.zookeeper.CuratorFactory;
3233
import com.salesforce.storm.spout.dynamic.persistence.zookeeper.CuratorHelper;
3334
import com.salesforce.storm.spout.sideline.recipes.trigger.zookeeper.Config;
@@ -83,34 +84,34 @@ public TriggerEventHelper(final Map<String, Object> config) {
8384
/**
8485
* Create a {@link TriggerEvent} to start a sideline.
8586
*
86-
* @param data data for the trigger event, this will be handed off to the {@link FilterChainStepBuilder}.
87+
* @param filterChainStep a {@link FilterChainStep} object to be applied for the trigger event.
8788
* @param createdBy the name or a way of identifying who or what started the sideline.
8889
* @param reason the reason for starting the sideline.
8990
* @return the identifier of the sideline.
9091
*/
9192
public String startTriggerEvent(
92-
final Map<String, Object> data,
93+
final FilterChainStep filterChainStep,
9394
final String createdBy,
9495
final String reason
9596
) {
96-
Preconditions.checkArgument(
97-
data != null && !data.isEmpty(),
98-
"TriggerEvent's require data"
97+
Preconditions.checkNotNull(
98+
filterChainStep,
99+
"TriggerEvent's require a FilterChainStep"
99100
);
100101

101102
final LocalDateTime createdAt = LocalDateTime.now();
102103

103104
final TriggerEvent triggerEvent = new TriggerEvent(
104105
SidelineType.START,
105-
data,
106+
filterChainStep,
106107
createdAt,
107108
createdBy,
108109
reason,
109110
false,
110111
createdAt
111112
);
112113

113-
final String id = getMd5Hash(data);
114+
final String id = getMd5Hash(filterChainStep);
114115
final String path = getZkRoot() + "/" + id;
115116

116117
logger.info("Sending trigger event to start sideline {}", id);
@@ -160,7 +161,7 @@ private void updateTriggerEventType(final String id, SidelineType type) {
160161

161162
final TriggerEvent triggerEvent = new TriggerEvent(
162163
type,
163-
originalTriggerEvent.getData(),
164+
originalTriggerEvent.getFilterChainStep(),
164165
originalTriggerEvent.getCreatedAt(),
165166
originalTriggerEvent.getCreatedBy(),
166167
originalTriggerEvent.getDescription(),
@@ -173,8 +174,8 @@ private void updateTriggerEventType(final String id, SidelineType type) {
173174
logger.info("Saved to {}", path);
174175
}
175176

176-
private String getMd5Hash(final Map<String, Object> data) {
177-
return Tools.makeMd5Hash(new JSON(new HashMap<>()).to(data));
177+
private String getMd5Hash(final FilterChainStep filterChainStep) {
178+
return Tools.makeMd5Hash(new JSON(new HashMap<>()).to(filterChainStep));
178179
}
179180

180181
private String getZkRoot() {

src/main/java/com/salesforce/storm/spout/sideline/recipes/trigger/zookeeper/Config.java

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
package com.salesforce.storm.spout.sideline.recipes.trigger.zookeeper;
2727

2828
import com.salesforce.storm.spout.documentation.ConfigDocumentation;
29-
import com.salesforce.storm.spout.sideline.recipes.trigger.FilterChainStepBuilder;
3029

3130
import java.util.List;
3231

@@ -40,15 +39,6 @@ public class Config {
4039
*/
4140
public static final String PREFIX = "sideline.zookeeper_watch_trigger.";
4241

43-
/**
44-
* (String) Class name for the class of the {@link FilterChainStepBuilder} instance.
45-
*/
46-
@ConfigDocumentation(
47-
description = "Class name for the class of the FilterChainStepBuilder instance.",
48-
type = String.class
49-
)
50-
public static final String FILTER_CHAIN_STEP_BUILDER_CLASS = PREFIX + "filter_chain_step_builder_class";
51-
5242
/**
5343
* (List[String]) Holds a list of Zookeeper server Hostnames + Ports in the following format:
5444
* ["zkhost1:2181", "zkhost2:2181", ...]

0 commit comments

Comments
 (0)