diff --git a/src/main/java/com/gremlin/failureflags/Behavior.java b/src/main/java/com/gremlin/failureflags/Behavior.java index 6987c9c..ed0b6f9 100644 --- a/src/main/java/com/gremlin/failureflags/Behavior.java +++ b/src/main/java/com/gremlin/failureflags/Behavior.java @@ -1,6 +1,20 @@ package com.gremlin.failureflags; +/** + * Behaviors implement specific effects or symptoms of failures that an application will experience in calls to + * FailureFlags.invoke(...). When processing multiple experiments, delays should be applied before other failure types + * and those failure types that can be processed without changing flow should be applied first. If multiple experiments + * result in changing control flow (like exceptions, shutdowns, panics, etc.) then the behavior chain may not realize + * some effects. + * + * This is a functional interface. An adopter might use Lambdas to provide behavior inline. + * */ @FunctionalInterface public interface Behavior { + /** + * applyBehavior applies any behavior described by the effect statements in each experiment in the provided array. + * + * @param experiments an ordered array of active Experiments to apply + * */ void applyBehavior(Experiment[] experiments); } diff --git a/src/main/java/com/gremlin/failureflags/Experiment.java b/src/main/java/com/gremlin/failureflags/Experiment.java index b8a43bf..d7e9a09 100644 --- a/src/main/java/com/gremlin/failureflags/Experiment.java +++ b/src/main/java/com/gremlin/failureflags/Experiment.java @@ -4,42 +4,70 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import java.util.Map; +/** + * Experiment describes an active experiment defined by a Gremlin user. + * */ @JsonIgnoreProperties(ignoreUnknown = true) public class Experiment { String name; String guid; float rate; Map effect; - + /** + * getName() returns the name of the experiment. + * @return the name of the experiment + * */ public String getName() { return name; } + /** + * setName() sets the name of the experiment. + * @param name the name of the experiment + * */ public void setName(String name) { this.name = name; } + /** + * getGuid() returns the GUID of the experiment. + * @return the GUID of the experiment + * */ public String getGuid() { return guid; } - + /** + * setGuid() sets the GUID of the experiment. + * @param guid the guid of the experiment + * */ public void setGuid(String guid) { this.guid = guid; } - + /** + * getRate() returns the rate of the experiment. + * @return the rate of the experiment + * */ public float getRate() { return rate; } - + /** + * setRate() sets the rate of the experiment. + * @param rate the rate of the experiment + * */ public void setRate(float rate) { this.rate = rate; } - + /** + * getEffect() returns the effect of the experiment. + * @return the effect of the experiment + * */ public Map getEffect() { return effect; } - + /** + * setEffect() sets the effect of the experiment. + * @param effect the effect of the experiment + * */ public void setEffect(Map effect) { this.effect = effect; } - } diff --git a/src/main/java/com/gremlin/failureflags/FailureFlag.java b/src/main/java/com/gremlin/failureflags/FailureFlag.java index 0febf4b..b41fcec 100644 --- a/src/main/java/com/gremlin/failureflags/FailureFlag.java +++ b/src/main/java/com/gremlin/failureflags/FailureFlag.java @@ -14,30 +14,60 @@ public class FailureFlag { @JsonIgnore boolean debug; + /** + * Construct a new FailureFlag and set all options. + * + * @param name the name of the FailureFlag + * @param labels the labels of the FailureFlag + * @param debug the debug state of the FailureFlag + * */ public FailureFlag(String name, Map labels, boolean debug) { this.name = name; this.labels = labels; this.debug = debug; } + /** + * getName() returns the name of the FailureFlag. + * @return the name of the FailureFlag + * */ public String getName() { return name; } + /** + * setName() sets the name of the FailureFlag. + * @param name the name of the FailureFlag + * */ public void setName(String name) { this.name = name; } + /** + * getLabels() returns the labels of the FailureFlag. + * @return the labels of the FailureFlag + * */ public Map getLabels() { return labels; } + /** + * setLabels() sets the labels of the FailureFlag. + * @param labels the labels of the FailureFlag + * */ public void setLabels(Map labels) { this.labels = labels; } + /** + * getDebug() returns true if the FailureFlag is configured for debugging. + * @return the debug state of the FailureFlag + * */ public boolean getDebug() { return debug; } - public void setDebug(boolean debug) { this.debug = debug; } - + /** + * setDebug() sets the debug state of the FailureFlag. + * @param debug the debug state of the FailureFlag + * */ + public void setDebug(boolean debug) { this.debug = debug; } } diff --git a/src/main/java/com/gremlin/failureflags/FailureFlagException.java b/src/main/java/com/gremlin/failureflags/FailureFlagException.java index f8c76e9..1604d11 100644 --- a/src/main/java/com/gremlin/failureflags/FailureFlagException.java +++ b/src/main/java/com/gremlin/failureflags/FailureFlagException.java @@ -2,9 +2,16 @@ import java.util.Map; +/** + * FailureFlagException is an unchecked exception thrown by the Exception behavior while processing an Experiment with + * an exception property on its effect statement. + * */ public class FailureFlagException extends RuntimeException { + /** + * Construct a new FailureFlagException. + * @param message the message to attach to this exception. + * */ public FailureFlagException(final String message) { super(message); } - } \ No newline at end of file diff --git a/src/main/java/com/gremlin/failureflags/FailureFlags.java b/src/main/java/com/gremlin/failureflags/FailureFlags.java index 4a4ed8c..55af7d4 100644 --- a/src/main/java/com/gremlin/failureflags/FailureFlags.java +++ b/src/main/java/com/gremlin/failureflags/FailureFlags.java @@ -1,18 +1,27 @@ package com.gremlin.failureflags; +/** + * FailureFlags is an interface exposing the core functionality of the FailureFlags system. Code to this interface to + * improve testability of your code. GremlinFailureFlags is the default implementation. + * */ public interface FailureFlags { /** * invoke will fetch and apply the provided behaviors for any experiments targeting the provided Failure Flag. + * @param flag the FailureFlag to invoke + * @param behavior the specific or inline behavior to use for any active experiments + * @return an array of active Experiments. null if there are no active experiments targeting the provided Failure Flag. * */ Experiment[] invoke(FailureFlag flag, Behavior behavior); /** * invoke will fetch and apply default behaviors for any experiments targeting the provided Failure Flag. + * @param flag the FailureFlag to invoke + * @return an array of active Experiments. null if there are no active experiments targeting the provided Failure Flag. * */ Experiment[] invoke(FailureFlag flag); /** * fetchExperiment retrieves the list of active experiments targeting the provided Failure Flag. - * - * @return null if there are no active experiments targeting the provided Failure Flag. + * @param flag the FailureFlag to invoke + * @return an array of active Experiments. null if there are no active experiments targeting the provided Failure Flag. * */ Experiment[] fetch(FailureFlag flag); } diff --git a/src/main/java/com/gremlin/failureflags/GremlinFailureFlags.java b/src/main/java/com/gremlin/failureflags/GremlinFailureFlags.java index 9ed4be9..8fc6c0a 100644 --- a/src/main/java/com/gremlin/failureflags/GremlinFailureFlags.java +++ b/src/main/java/com/gremlin/failureflags/GremlinFailureFlags.java @@ -20,6 +20,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * GremlinFailureFlags is a full implementation of FailureFlags that integrates with the Gremlin sidecars and API. + * */ public class GremlinFailureFlags implements FailureFlags { private static final String VERSION = FailureFlags.class.getPackage().getImplementationVersion(); @@ -27,9 +30,15 @@ public class GremlinFailureFlags implements FailureFlags { private static final String IOEXCEPTION_MESSAGE = "IOException during HTTP call to Gremlin co-process"; private static final ObjectMapper MAPPER = new ObjectMapper(); + /** + * FAILURE_FLAGS_ENABLED contains the name of the environment variable to use to control the enabled status of this SDK. + * */ public static final String FAILURE_FLAGS_ENABLED = "FAILURE_FLAGS_ENABLED"; private final Behavior defaultBehavior; + /** + * enabled overrides any environment configuration to enable or disable this SDK. Setting to true will enable this SDK. + * */ protected boolean enabled; // for testing purposes /** @@ -41,6 +50,8 @@ public GremlinFailureFlags() { /** * Construct a new FailureFlags instance with a different default behavior chain. + * @param defaultBehavior the default behavior to use in all calls to invoke unless overridden by + * parameter on that specific invocation. * */ public GremlinFailureFlags(Behavior defaultBehavior) { if (defaultBehavior == null) { @@ -49,6 +60,10 @@ public GremlinFailureFlags(Behavior defaultBehavior) { this.defaultBehavior = defaultBehavior; } + /** + * getDefaultBehavior returns the current Behavior to be used in default invocations. + * @return the default behavior + * */ public Behavior getDefaultBehavior() { return this.defaultBehavior; } @@ -56,6 +71,7 @@ public Behavior getDefaultBehavior() { /** * {@inheritDoc} * */ + @Override public Experiment[] invoke(FailureFlag flag) { return invoke(flag, null); } @@ -63,6 +79,7 @@ public Experiment[] invoke(FailureFlag flag) { /** * {@inheritDoc} * */ + @Override public Experiment[] invoke(FailureFlag flag, Behavior behavior) { if (!System.getenv().containsKey(FAILURE_FLAGS_ENABLED) && !this.enabled) { return null; @@ -119,6 +136,7 @@ public Experiment[] invoke(FailureFlag flag, Behavior behavior) { /** * {@inheritDoc} * */ + @Override public Experiment[] fetch(FailureFlag flag) { if (flag == null) { return null; diff --git a/src/main/java/com/gremlin/failureflags/NoopFailureFlags.java b/src/main/java/com/gremlin/failureflags/NoopFailureFlags.java new file mode 100644 index 0000000..27a3eed --- /dev/null +++ b/src/main/java/com/gremlin/failureflags/NoopFailureFlags.java @@ -0,0 +1,21 @@ +package com.gremlin.failureflags; + +/** + * NoopFailureFlags is a stub implementation of FailureFlags. It does nothing and its methods always return null. + * */ +public class NoopFailureFlags implements FailureFlags { + @Override + public Experiment[] invoke(FailureFlag flag, Behavior behavior) { + return null; + } + + @Override + public Experiment[] invoke(FailureFlag flag) { + return null; + } + + @Override + public Experiment[] fetch(FailureFlag flag) { + return null; + } +} diff --git a/src/main/java/com/gremlin/failureflags/behaviors/DelayedException.java b/src/main/java/com/gremlin/failureflags/behaviors/DelayedException.java index 4e0fc1b..1b63f51 100644 --- a/src/main/java/com/gremlin/failureflags/behaviors/DelayedException.java +++ b/src/main/java/com/gremlin/failureflags/behaviors/DelayedException.java @@ -3,6 +3,16 @@ import com.gremlin.failureflags.Behavior; import com.gremlin.failureflags.Experiment; +/** + * DelayedException processes latency and exception properties in experiment effects. All + * latency effects will be applied before any exceptions are thrown. + * + * Behaviors implement specific effects or symptoms of failures that an application will experience in calls to + * FailureFlags.invoke(...). When processing multiple experiments, delays should be applied before other failure types + * and those failure types that can be processed without changing flow should be applied first. If multiple experiments + * result in changing control flow (like exceptions, shutdowns, panics, etc.) then the behavior chain may not realize + * some effects. + * */ public class DelayedException implements Behavior { public void applyBehavior(Experiment[] experiments) { new Latency().applyBehavior(experiments); diff --git a/src/main/java/com/gremlin/failureflags/behaviors/Exception.java b/src/main/java/com/gremlin/failureflags/behaviors/Exception.java index 662f63d..a3e27f9 100644 --- a/src/main/java/com/gremlin/failureflags/behaviors/Exception.java +++ b/src/main/java/com/gremlin/failureflags/behaviors/Exception.java @@ -3,8 +3,17 @@ import com.gremlin.failureflags.Behavior; import com.gremlin.failureflags.FailureFlagException; import com.gremlin.failureflags.Experiment; - +/** + * Exception processes exception properties in experiment effects. + * + * Behaviors implement specific effects or symptoms of failures that an application will experience in calls to + * FailureFlags.invoke(...). When processing multiple experiments, delays should be applied before other failure types + * and those failure types that can be processed without changing flow should be applied first. If multiple experiments + * result in changing control flow (like exceptions, shutdowns, panics, etc.) then the behavior chain may not realize + * some effects. + * */ public class Exception implements Behavior { + /**{@inheritDoc}*/ public void applyBehavior(Experiment[] experiments) { for (Experiment e: experiments) { if (!e.getEffect().containsKey("exception")) { diff --git a/src/main/java/com/gremlin/failureflags/behaviors/Latency.java b/src/main/java/com/gremlin/failureflags/behaviors/Latency.java index 0541a84..663ddf2 100644 --- a/src/main/java/com/gremlin/failureflags/behaviors/Latency.java +++ b/src/main/java/com/gremlin/failureflags/behaviors/Latency.java @@ -41,6 +41,7 @@ * */ public class Latency implements Behavior { + /**{@inheritDoc}*/ public void applyBehavior(Experiment[] experiments) { for (Experiment e: experiments) { if (!e.getEffect().containsKey("latency")) { continue; }