Togglz defines the concept of activation strategies. They are responsible for deciding whether an enabled feature is active or not. Activation strategies can, for example, be used to activate features only for specific users, for specific client IPs or at a specified time.
Togglz ships with the following default strategies:
The following sections will describe each strategy in detail. The last section custom strategies describes how to build your own strategies.
Enabling features for specific users was already supported in very early versions of Togglz, even before the activation strategy concept was introduced in Togglz 2.0.0.
If you select this strategy for a feature, you can specify a comma-separated list of
users for which the feature should be active. Togglz will use the UserProvider
you configured for the FeatureManager to determine the current user and compare it to
that list.
Please note that Togglz is case-sensitive when comparing the usernames. So the
users admin
and Admin
are NOT the same.
This strategy is very useful if you want to allow a specific list of users to test a certain feature in production.
The gradual rollout strategy allows you to activate a feature to a certain percentage of users. This allows you to test a feature with a very small number of users and increase the number over time until the feature is active for everyone.
If you select this strategy, you will be asked to enter a percentage value. If you for example
enter 25
, Togglz will activate the feature for every fourth user.
The users are selected by calculating a hash value from the username which is then normalized to a value between 0 and 100. The feature will be active for a user if the hash value is smaller or equal to the percentage you configured. This algorithm ensures that the feature will be active for a user even after you increased the percentage. Have a look at the source code of the strategy for more details.
The release date strategy can be used to automatically activate a feature at a certain
point in time. If you select this strategy, you must enter the date and (optionally) the
time when the feature should become active. If you omit the time, the feature will be activated
at midnight. The date must be specified in the format 2012-12-31
and the
time in the format 14:15:00
The client IP strategy allows you to restrict a feature to clients connecting from a specific
IP address. The strategy uses HttpServletRequest.getRemoteAddr()
to obtain the IP
address of the client. The strategy is therefore restricted to web applications running in a
Servlet environment.
Please note that the strategy requires you to enter a full IP address. Specifying subnets is currently not supported (patches are welcome). But you can enter multiple IP addresses separated by comma.
The Server IP strategy is similar to the Client IP strategy. The only difference is that not the client IP but the server IP address is used. This strategy is very useful for canary testing where you activate a feature only on a subset of your cluster nodes to test for things like performance issues.
The strategy uses NetworkInterface.getNetworkInterfaces() to obtain the IP addresses of the server. All IP addresses returned by this method are compared against the IP addresses configured for the strategy. The feature will be active if there is at least one match.
The ScriptEngine strategy is the most flexible activation strategy. It allows you to use a
JSR223 scripting language to implement the test that decides whether the feature is active or not.
You can use any language supported by the
ScriptEngine
of your JVM. The Oracle JVM ships with an ECMAScript
engine that allows you
to write JavaScript for your check out of the box.
The activation strategy has two parameters. The first one is used to specify the language to use for the
script (for example ECMAScript
). The second parameters is the script itself. The script must
evaluate to a boolean result. The script context is populated with a few variables that may
be useful for you:
user
: The FeatureUser
representing the current user.
date
: The current time as a java.util.Date
This example shows a script written in JavaScript that enables the feature
for a user named john
on Sundays.
ECMAScript
user.name == 'john' && date.day == 0
Please double check your script before using it for a feature. If the script evaluation fails due to some error, the feature will be inactive.
The System Properties Activation Strategy allows you to define a strategy that enables or disables a flag based on a system property being set.
The activation strategy has two parameters. The first one is used to specify the property name to use
(e.g. togglz.FEATURE_ONE
). The second parameter is the value to compare against. If the property
value matches the expected value, the feature will be on, otherwise it will be off.
The great thing about activation strategies is that it is very easy to add your own strategies. Togglz offers an extension point that allows you to implement a new strategy with only a single class.
All activation strategies have to implement the interface ActivationStrategy. Togglz looks up the implementations using the standard Java ServiceLoader mechanism.
To register a custom activation strategy implementation, you must create a file called
META-INF/services/org.togglz.core.spi.ActivationStrategy
on your classpath
and add single line containing the fully-qualified class name of your implementation class.
The ActivationStrategy
interface defines the following methods:
This method has to return a unique id for the strategy. This id is used to identify the strategy
when the feature state is persisted by a StateRepository
.
This method returns the human readable name of the activation strategy. This name will for example be displayed in the Togglz Admin Console.
The getParameters()
method can be used by the activation strategy to tell Togglz about
the strategy parameters it supports. The method returns an array of
Parameter
instances. Each element in this array represents a specification for a single parameter.
The simplest way to create Parameter
instances is to use
ParameterBuilder.
The builder offers a fluent API for defining a parameter. However you can also create your own
Parameter
implementation. This can be useful especially if you need to implement custom
validation for a parameter.
This method is responsible for the evaluation of the strategy. It is called every time a feature
state is checked for a feature which uses the strategy. The method has two arguments, the
current user as a FeatureUser
and the FeatureState
representing
the configuration of the feature. The implementation of the method can obtain the values of the
strategy parameters by calling FeatureState.getParameter()
.
Enough theory for now. The easiest way to understand how to build a custom strategy is to see an example.
The following strategy allows you to activate a feature only for specific days of the week.
So it can for example be configured so that the feature is only active on Mondays.
The strategy defines a single parameter identified by the id day
. This value of
this parameter is then compared against the current weekday.
public class WeekdayActivationStrategy implements ActivationStrategy { private static final String[] SHORT_WEEKDAYS = DateFormatSymbols.getInstance().getShortWeekdays(); @Override public String getId() { return "weekday"; } @Override public String getName() { return "Weekday strategy"; } @Override public Parameter[] getParameters() { return new Parameter[] { ParameterBuilder.create("day").label("Day of week") }; } @Override public boolean isActive(FeatureState featureState, FeatureUser user) { // the weekday name configured for the strategy String selectedWeekday = featureState.getParameter("day"); // get the weekday name for today Calendar now = GregorianCalendar.getInstance(); int currentWeekday = now.get(Calendar.DAY_OF_WEEK); String currentWeekdayName = SHORT_WEEKDAYS[currentWeekday]; // the feature is active if the weekday matches return selectedWeekday.equals(currentWeekdayName); } }
Easy, isn't it? :)