-
Notifications
You must be signed in to change notification settings - Fork 32
Refact: Added builder pattern in decision listener #275
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0b51b15
a28e17c
03b7589
0972ac3
ef3bdbe
f0016a9
db4cb66
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
/**************************************************************************** | ||
* Copyright 2019, Optimizely, Inc. and contributors * | ||
* * | ||
* Licensed under the Apache License, Version 2.0 (the "License"); * | ||
* you may not use this file except in compliance with the License. * | ||
* You may obtain a copy of the License at * | ||
* * | ||
* http://www.apache.org/licenses/LICENSE-2.0 * | ||
* * | ||
* Unless required by applicable law or agreed to in writing, software * | ||
* distributed under the License is distributed on an "AS IS" BASIS, * | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | ||
* See the License for the specific language governing permissions and * | ||
* limitations under the License. * | ||
***************************************************************************/ | ||
|
||
package com.optimizely.ab.notification; | ||
|
||
|
||
import com.optimizely.ab.bucketing.FeatureDecision; | ||
import com.optimizely.ab.config.FeatureVariable; | ||
|
||
import javax.annotation.Nonnull; | ||
import javax.annotation.Nullable; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
public class DecisionNotification { | ||
protected String type; | ||
protected String userId; | ||
protected Map<String, ?> attributes; | ||
protected Map<String, ?> decisionInfo; | ||
|
||
protected DecisionNotification() { | ||
} | ||
|
||
protected DecisionNotification(@Nonnull String type, | ||
@Nonnull String userId, | ||
@Nullable Map<String, ?> attributes, | ||
@Nonnull Map<String, ?> decisionInfo) { | ||
this.type = type; | ||
this.userId = userId; | ||
if (attributes == null) { | ||
attributes = new HashMap<>(); | ||
} | ||
this.attributes = attributes; | ||
this.decisionInfo = decisionInfo; | ||
} | ||
|
||
public String getType() { | ||
return type; | ||
} | ||
|
||
public String getUserId() { | ||
return userId; | ||
} | ||
|
||
public Map<String, ?> getAttributes() { | ||
return attributes; | ||
} | ||
|
||
public Map<String, ?> getDecisionInfo() { | ||
return decisionInfo; | ||
} | ||
|
||
public static FeatureVariableDecisionNotificationBuilder newFeatureVariableBuilder() { | ||
return new FeatureVariableDecisionNotificationBuilder(); | ||
} | ||
|
||
public static class FeatureVariableDecisionNotificationBuilder { | ||
|
||
public static final String FEATURE_KEY = "feature_key"; | ||
public static final String FEATURE_ENABLED = "feature_enabled"; | ||
public static final String SOURCE = "source"; | ||
public static final String SOURCE_EXPERIMENT_KEY = "source_experiment_key"; | ||
public static final String SOURCE_VARIATION_KEY = "source_variation_key"; | ||
public static final String VARIABLE_KEY = "variable_key"; | ||
public static final String VARIABLE_TYPE = "variable_type"; | ||
public static final String VARIABLE_VALUE = "variable_value"; | ||
|
||
private String featureKey; | ||
private Boolean featureEnabled; | ||
private FeatureDecision featureDecision; | ||
private String variableKey; | ||
private FeatureVariable.VariableType variableType; | ||
private Object variableValue; | ||
private String userId; | ||
private Map<String, ?> attributes; | ||
private Map<String, Object> decisionInfo; | ||
|
||
protected FeatureVariableDecisionNotificationBuilder() { | ||
} | ||
|
||
public FeatureVariableDecisionNotificationBuilder withUserId(String userId) { | ||
this.userId = userId; | ||
return this; | ||
} | ||
|
||
public FeatureVariableDecisionNotificationBuilder withAttributes(Map<String, ?> attributes) { | ||
this.attributes = attributes; | ||
return this; | ||
} | ||
|
||
public FeatureVariableDecisionNotificationBuilder withFeatureKey(String featureKey) { | ||
this.featureKey = featureKey; | ||
return this; | ||
} | ||
|
||
public FeatureVariableDecisionNotificationBuilder withFeatureEnabled(boolean featureEnabled) { | ||
this.featureEnabled = featureEnabled; | ||
return this; | ||
} | ||
|
||
public FeatureVariableDecisionNotificationBuilder withFeatureDecision(FeatureDecision featureDecision) { | ||
this.featureDecision = featureDecision; | ||
return this; | ||
} | ||
|
||
public FeatureVariableDecisionNotificationBuilder withVariableKey(String variableKey) { | ||
this.variableKey = variableKey; | ||
return this; | ||
} | ||
|
||
public FeatureVariableDecisionNotificationBuilder withVariableType(FeatureVariable.VariableType variableType) { | ||
this.variableType = variableType; | ||
return this; | ||
} | ||
|
||
public FeatureVariableDecisionNotificationBuilder withVariableValue(Object variableValue) { | ||
this.variableValue = variableValue; | ||
return this; | ||
} | ||
|
||
public DecisionNotification build() { | ||
decisionInfo = new HashMap<>(); | ||
decisionInfo.put(FEATURE_KEY, featureKey); | ||
decisionInfo.put(FEATURE_ENABLED, featureEnabled); | ||
decisionInfo.put(VARIABLE_KEY, variableKey); | ||
decisionInfo.put(VARIABLE_TYPE, variableType); | ||
decisionInfo.put(VARIABLE_VALUE, variableValue); | ||
if (featureDecision != null && featureDecision.decisionSource != null && FeatureDecision.DecisionSource.EXPERIMENT.equals(featureDecision.decisionSource)) { | ||
decisionInfo.put(SOURCE_EXPERIMENT_KEY, featureDecision.experiment.getKey()); | ||
decisionInfo.put(SOURCE_VARIATION_KEY, featureDecision.variation.getKey()); | ||
decisionInfo.put(SOURCE, featureDecision.decisionSource); | ||
} else { | ||
decisionInfo.put(SOURCE_EXPERIMENT_KEY, null); | ||
decisionInfo.put(SOURCE_VARIATION_KEY, null); | ||
decisionInfo.put(SOURCE, FeatureDecision.DecisionSource.ROLLOUT); | ||
} | ||
|
||
return new DecisionNotification( | ||
NotificationCenter.DecisionNotificationType.FEATURE_VARIABLE.toString(), | ||
userId, | ||
attributes, | ||
decisionInfo); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,37 +17,17 @@ | |
package com.optimizely.ab.notification; | ||
|
||
import javax.annotation.Nonnull; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
public abstract class DecisionNotificationListener implements NotificationListener, DecisionNotificationListenerInterface { | ||
public interface DecisionNotificationListener { | ||
|
||
/** | ||
* Base notify called with var args. This method parses the parameters and calls the abstract method. | ||
* onDecision called when an activate was triggered | ||
* | ||
* @param args - variable argument list based on the type of notification. | ||
* @param decisionNotification - The decision notification object containing: | ||
* type - The notification type. | ||
* userId - The userId passed to the API. | ||
* attributes - The attribute map passed to the API. | ||
* decisionInfo - The decision information containing all parameters passed in API. | ||
*/ | ||
@Override | ||
public final void notify(Object... args) { | ||
assert (args[0] instanceof String); | ||
String type = (String) args[0]; | ||
assert (args[1] instanceof String); | ||
String userId = (String) args[1]; | ||
Map<String, ?> attributes = null; | ||
if (args[2] != null) { | ||
assert (args[2] instanceof java.util.Map); | ||
attributes = (Map<String, ?>) args[2]; | ||
} else { | ||
attributes = new HashMap<>(); | ||
} | ||
assert (args[3] instanceof java.util.Map); | ||
Map<String, ?> decisionInfo = (Map<String, ?>) args[3]; | ||
onDecision(type, userId, attributes, decisionInfo); | ||
} | ||
|
||
@Override | ||
public abstract void onDecision(@Nonnull String type, | ||
@Nonnull String userId, | ||
@Nonnull Map<String, ?> attributes, | ||
@Nonnull Map<String, ?> decisionInfo); | ||
void onDecision(@Nonnull DecisionNotification decisionNotification); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've been trying to see if we can use generics to maintain some higher order generality. Ideally NotificationLister originally would have been defined like:
but since it wasn't trying to think the best way forward. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, you are right we can use generics but I think than we have to refactor Track and Activate listeners as well. If I am understanding this correctly? |
||
} |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are all of these fields allowed to be null? I see in
BaseDecisionNotificationBuilder
, that we defaultattributes
to empty map -- that should be moved here (otherwise assert non-null in constructor) to make it consistent, otherwise nulls can slip in.