Skip to content

Commit 4581510

Browse files
author
Mike Davis
authored
Add LogEvent notification. (#318)
* Add explicit LogEvent notification. * Deprecate LogEvent from "activate" and "track" notifications.
1 parent 00a7765 commit 4581510

File tree

11 files changed

+97
-11
lines changed

11 files changed

+97
-11
lines changed

core-api/src/main/java/com/optimizely/ab/Optimizely.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,13 @@ public int addUpdateConfigNotificationHandler(NotificationHandler<UpdateConfigNo
963963
return addNotificationHandler(UpdateConfigNotification.class, handler);
964964
}
965965

966+
/**
967+
* Convenience method for adding LogEvent Notification Handlers
968+
*/
969+
public int addLogEventNotificationHandler(NotificationHandler<LogEvent> handler) {
970+
return addNotificationHandler(LogEvent.class, handler);
971+
}
972+
966973
/**
967974
* Convenience method for adding NotificationHandlers
968975
*/
@@ -1097,11 +1104,6 @@ public Optimizely build() {
10971104
decisionService = new DecisionService(bucketer, errorHandler, userProfileService);
10981105
}
10991106

1100-
// For backwards compatibility
1101-
if (eventProcessor == null) {
1102-
eventProcessor = new ForwardingEventProcessor(eventHandler);
1103-
}
1104-
11051107
if (projectConfig == null && datafile != null && !datafile.isEmpty()) {
11061108
try {
11071109
projectConfig = new DatafileProjectConfig.Builder().withDatafile(datafile).build();
@@ -1125,6 +1127,11 @@ public Optimizely build() {
11251127
notificationCenter = new NotificationCenter();
11261128
}
11271129

1130+
// For backwards compatibility
1131+
if (eventProcessor == null) {
1132+
eventProcessor = new ForwardingEventProcessor(eventHandler, notificationCenter);
1133+
}
1134+
11281135
return new Optimizely(eventHandler, eventProcessor, errorHandler, decisionService, userProfileService, projectConfigManager, notificationCenter);
11291136
}
11301137
}

core-api/src/main/java/com/optimizely/ab/event/BatchEventProcessor.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.optimizely.ab.event.internal.EventFactory;
2121
import com.optimizely.ab.event.internal.UserEvent;
2222
import com.optimizely.ab.internal.PropertyUtils;
23+
import com.optimizely.ab.notification.NotificationCenter;
2324
import org.slf4j.Logger;
2425
import org.slf4j.LoggerFactory;
2526

@@ -54,15 +55,17 @@ public class BatchEventProcessor implements EventProcessor, AutoCloseable {
5455
private final int batchSize;
5556
private final long flushInterval;
5657
private final ExecutorService executor;
58+
private final NotificationCenter notificationCenter;
5759

5860
private Future<?> future;
5961
private boolean isStarted = false;
6062

61-
private BatchEventProcessor(BlockingQueue<Object> eventQueue, EventHandler eventHandler, Integer batchSize, Long flushInterval, ExecutorService executor) {
63+
private BatchEventProcessor(BlockingQueue<Object> eventQueue, EventHandler eventHandler, Integer batchSize, Long flushInterval, ExecutorService executor, NotificationCenter notificationCenter) {
6264
this.eventHandler = eventHandler;
6365
this.eventQueue = eventQueue;
6466
this.batchSize = batchSize == null ? PropertyUtils.getInteger(CONFIG_BATCH_SIZE, DEFAULT_BATCH_SIZE) : batchSize;
6567
this.flushInterval = flushInterval == null ? PropertyUtils.getLong(CONFIG_BATCH_INTERVAL, DEFAULT_BATCH_INTERVAL) : flushInterval;
68+
this.notificationCenter = notificationCenter;
6669

6770
if (executor == null) {
6871
final ThreadFactory threadFactory = Executors.defaultThreadFactory();
@@ -196,6 +199,10 @@ private void flush() {
196199

197200
LogEvent logEvent = EventFactory.createLogEvent(currentBatch);
198201

202+
if (notificationCenter != null) {
203+
notificationCenter.send(logEvent);
204+
}
205+
199206
try {
200207
eventHandler.dispatchEvent(logEvent);
201208
} catch (Exception e) {
@@ -215,6 +222,7 @@ public static class Builder {
215222
private Integer batchSize = null;
216223
private Long flushInterval = null;
217224
private ExecutorService executor = null;
225+
private NotificationCenter notificationCenter = null;
218226

219227
public Builder withEventHandler(EventHandler eventHandler) {
220228
this.eventHandler = eventHandler;
@@ -241,8 +249,13 @@ public Builder withExecutor(ExecutorService executor) {
241249
return this;
242250
}
243251

252+
public Builder withNotificationCenter(NotificationCenter notificationCenter) {
253+
this.notificationCenter = notificationCenter;
254+
return this;
255+
}
256+
244257
public BatchEventProcessor build() {
245-
return new BatchEventProcessor(eventQueue, eventHandler, batchSize, flushInterval, executor);
258+
return new BatchEventProcessor(eventQueue, eventHandler, batchSize, flushInterval, executor, notificationCenter);
246259
}
247260
}
248261

core-api/src/main/java/com/optimizely/ab/event/ForwardingEventProcessor.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import com.optimizely.ab.event.internal.EventFactory;
2020
import com.optimizely.ab.event.internal.UserEvent;
21+
import com.optimizely.ab.notification.NotificationCenter;
2122
import org.slf4j.Logger;
2223
import org.slf4j.LoggerFactory;
2324

@@ -30,15 +31,21 @@ public class ForwardingEventProcessor implements EventProcessor {
3031
private static final Logger logger = LoggerFactory.getLogger(ForwardingEventProcessor.class);
3132

3233
private final EventHandler eventHandler;
34+
private final NotificationCenter notificationCenter;
3335

34-
public ForwardingEventProcessor(EventHandler eventHandler) {
36+
public ForwardingEventProcessor(EventHandler eventHandler, NotificationCenter notificationCenter) {
3537
this.eventHandler = eventHandler;
38+
this.notificationCenter = notificationCenter;
3639
}
3740

3841
@Override
3942
public void process(UserEvent userEvent) {
4043
LogEvent logEvent = EventFactory.createLogEvent(userEvent);
4144

45+
if (notificationCenter != null) {
46+
notificationCenter.send(logEvent);
47+
}
48+
4249
try {
4350
eventHandler.dispatchEvent(logEvent);
4451
} catch(Exception e) {

core-api/src/main/java/com/optimizely/ab/notification/ActivateNotification.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,12 @@ public Variation getVariation() {
7474
return variation;
7575
}
7676

77+
/**
78+
* This interface is deprecated since this is no longer a one-to-one mapping.
79+
* Please use a {@link NotificationHandler} explicitly for LogEvent messages.
80+
* {@link com.optimizely.ab.Optimizely#addLogEventNotificationHandler(NotificationHandler)}
81+
*/
82+
@Deprecated
7783
public LogEvent getEvent() {
7884
return event;
7985
}

core-api/src/main/java/com/optimizely/ab/notification/NotificationCenter.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.optimizely.ab.notification;
1818

1919
import com.optimizely.ab.OptimizelyRuntimeException;
20+
import com.optimizely.ab.event.LogEvent;
2021
import org.slf4j.Logger;
2122
import org.slf4j.LoggerFactory;
2223

@@ -94,6 +95,7 @@ public NotificationCenter() {
9495
validManagers.put(TrackNotification.class, new NotificationManager<TrackNotification>(counter));
9596
validManagers.put(DecisionNotification.class, new NotificationManager<DecisionNotification>(counter));
9697
validManagers.put(UpdateConfigNotification.class, new NotificationManager<UpdateConfigNotification>(counter));
98+
validManagers.put(LogEvent.class, new NotificationManager<LogEvent>(counter));
9799

98100
notifierMap = Collections.unmodifiableMap(validManagers);
99101
}

core-api/src/main/java/com/optimizely/ab/notification/TrackNotification.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ public String getUserId() {
6868
return eventTags;
6969
}
7070

71+
/**
72+
* This interface is deprecated since this is no longer a one-to-one mapping.
73+
* Please use a {@link NotificationHandler} explicitly for LogEvent messages.
74+
* {@link com.optimizely.ab.Optimizely#addLogEventNotificationHandler(NotificationHandler)}
75+
*/
76+
@Deprecated
7177
public LogEvent getEvent() {
7278
return event;
7379
}

core-api/src/test/java/com/optimizely/ab/OptimizelyRule.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ public void before() {
8787

8888
public void after() {
8989
if (optimizely == null) {
90-
return;
90+
// Build so we can shut everything down.
91+
build();
9192
}
9293

9394
// Blocks and waits for graceful shutdown.

core-api/src/test/java/com/optimizely/ab/OptimizelyTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4186,6 +4186,16 @@ public void testAddUpdateConfigNotificationHandler() {
41864186
assertTrue(manager.remove(notificationId));
41874187
}
41884188

4189+
@Test
4190+
public void testAddLogEventNotificationHandler() {
4191+
Optimizely optimizely = optimizelyBuilder.withConfigManager(() -> null).build();
4192+
NotificationManager<LogEvent> manager = optimizely.getNotificationCenter()
4193+
.getNotificationManager(LogEvent.class);
4194+
4195+
int notificationId = optimizely.addLogEventNotificationHandler(message -> {});
4196+
assertTrue(manager.remove(notificationId));
4197+
}
4198+
41894199
//======== Helper methods ========//
41904200

41914201
private Experiment createUnknownExperiment() {

core-api/src/test/java/com/optimizely/ab/event/BatchEventProcessorTest.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.optimizely.ab.EventHandlerRule;
2020
import com.optimizely.ab.config.ProjectConfig;
2121
import com.optimizely.ab.event.internal.*;
22+
import com.optimizely.ab.notification.NotificationCenter;
2223
import org.junit.After;
2324
import org.junit.Before;
2425
import org.junit.Rule;
@@ -52,13 +53,15 @@ public class BatchEventProcessorTest {
5253

5354
private BlockingQueue<Object> eventQueue;
5455
private BatchEventProcessor eventProcessor;
56+
private NotificationCenter notificationCenter;
5557

5658
@Before
5759
public void setUp() throws Exception {
5860
when(projectConfig.getRevision()).thenReturn("1");
5961
when(projectConfig.getProjectId()).thenReturn("X");
6062

6163
eventQueue = new ArrayBlockingQueue<>(100);
64+
notificationCenter = new NotificationCenter();
6265
}
6366

6467
@After
@@ -173,12 +176,28 @@ public void testFlushOnMismatchProjectId() throws Exception {
173176
}
174177
}
175178

179+
@Test
180+
public void testNotificationCenter() throws Exception {
181+
CountDownLatch countDownLatch = new CountDownLatch(1);
182+
notificationCenter.addNotificationHandler(LogEvent.class, x -> countDownLatch.countDown());
183+
setEventProcessor(logEvent -> {});
184+
185+
UserEvent userEvent = buildConversionEvent(EVENT_NAME);
186+
eventProcessor.process(userEvent);
187+
eventProcessor.close();
188+
189+
if (!countDownLatch.await(MAX_DURATION_MS * 3, TimeUnit.MILLISECONDS)) {
190+
fail("Exceeded timeout waiting for notification.");
191+
}
192+
}
193+
176194
private void setEventProcessor(EventHandler eventHandler) {
177195
eventProcessor = BatchEventProcessor.builder()
178196
.withEventQueue(eventQueue)
179197
.withBatchSize(MAX_BATCH_SIZE)
180198
.withFlushInterval(MAX_DURATION_MS)
181199
.withEventHandler(eventHandler)
200+
.withNotificationCenter(notificationCenter)
182201
.build();
183202
}
184203

core-api/src/test/java/com/optimizely/ab/event/ForwardingEventProcessorTest.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import com.optimizely.ab.config.ProjectConfig;
2020
import com.optimizely.ab.event.internal.*;
21+
import com.optimizely.ab.notification.NotificationCenter;
2122
import org.junit.Before;
2223
import org.junit.Test;
2324
import org.junit.runner.RunWith;
@@ -38,6 +39,7 @@ public class ForwardingEventProcessorTest {
3839

3940
private ForwardingEventProcessor eventProcessor;
4041
private AtomicBoolean atomicBoolean = new AtomicBoolean();
42+
private NotificationCenter notificationCenter = new NotificationCenter();
4143

4244
@Mock
4345
private ProjectConfig projectConfig;
@@ -50,16 +52,26 @@ public void setUp() throws Exception {
5052
assertEquals(logEvent.getRequestMethod(), LogEvent.RequestMethod.POST);
5153
assertEquals(logEvent.getEndpointUrl(), EventFactory.EVENT_ENDPOINT);
5254
atomicBoolean.set(true);
53-
});
55+
}, notificationCenter);
5456
}
5557

5658
@Test
57-
public void testAddHandler() {
59+
public void testEventHandler() {
5860
UserEvent userEvent = buildConversionEvent(EVENT_NAME);
5961
eventProcessor.process(userEvent);
6062
assertTrue(atomicBoolean.get());
6163
}
6264

65+
@Test
66+
public void testNotifications() {
67+
AtomicBoolean notifcationTriggered = new AtomicBoolean();
68+
notificationCenter.addNotificationHandler(LogEvent.class, x -> notifcationTriggered.set(true));
69+
UserEvent userEvent = buildConversionEvent(EVENT_NAME);
70+
eventProcessor.process(userEvent);
71+
assertTrue(atomicBoolean.get());
72+
assertTrue(notifcationTriggered.get());
73+
}
74+
6375
private ConversionEvent buildConversionEvent(String eventName) {
6476
return UserEventFactory.createConversionEvent(projectConfig, USER_ID, EVENT_ID, eventName,
6577
Collections.emptyMap(), Collections.emptyMap());

0 commit comments

Comments
 (0)