State Repositories

State repositories are data stores which are responsible for persisting the state of a feature.

The persisted state consists of:

  • Is the feature enabled or disabled?
  • An optional activation strategy.
  • An optional list of configuration parameters for the selected strategy.

Users are able to choose the repository they want in their TogglzConfig implementation. Pleas see the Installation chapter for details.

This section will describe the repository implementations that are available in Togglz.

InMemoryStateRepository

This repository stores the feature state entirely in memory. As the repository isn't able to persist the feature state across JVM restarts it isn't typically used in production. Instead it may be useful during development time and in integration tests.

FileBasedStateRepository

The FileBasedStateRepository stores the state of features in a regular Java properties file. This repository is very easy to set up. The file based approach has some advantages compared to the other repository implementations. The most important advantage is that you are able to manually modify the properties file if you have direct access to the server running the application. This way you can very easily toggle features without the need to enable the embedded Togglz admin console.

The property files used by this repository have a very simple format:

# The feature 'FEATURE_ONE' is disabled
FEATURE_ONE=false

# The feature 'FEATURE_TWO' is enabled for the users 'chkal' and 'joe'
FEATURE_TWO=true
FEATURE_TWO.strategy = username
FEATURE_TWO.param.users = chkal, john

The following example shows a TogglzConfig that uses this repository:

public class FileBasedTogglzConfiguration implements TogglzConfig {

    /* ..... */ 

    @Override
    public StateRepository getStateRepository() {
        return new FileBasedStateRepository(new File("/tmp/features.properties"));
    }

}

JDBCStateRepository

This repository is able to store the feature state in regular SQL database. The implementation uses the standard Java JDBC API and just requires you to specify a DataSource.

It is very simple to setup this repository in a regular JEE environment. The following example shows how you can use the @Resource annotation to inject a JDBC datasource bound to JNDI into your CDI-managed configuration class.

@ApplicationScoped
public class DatabaseTogglzConfiguration implements TogglzConfig {

    @Resource(mappedName = "jboss/datasources/ExampleDS")
    private DataSource dataSource;

    /* ..... */ 

    @Override
    public StateRepository getStateRepository() {
        return new JDBCStateRepository(dataSource);
    }

}

Please note that you won't have to manually create any database tables for the repository to work correctly. JDBCStateRepository will automatically create the required table on the first connection to the database.

MongoStateRepository

This repository stores feature state in a MongoDB database.

At a minimum, you must provide a MongoClient instance and the name of the database. You can optionally override the name of the collection used to store feature state (defaults to 'togglz') and the default WriteConcern (ACKNOWLEDGED).

StateRepository stateRepository = MongoStateRepository.newBuilder(mongoClient, "myDatabase")
        .collection('myFeatureState')
        .writeConcern(WriteConcern.REPLICA_ACKNOWLEDGED)
        .build();

CachingStateRepository since 1.1.0

This repository can be used to add caching behavior to an existing repository. It wraps the underlying repository and caches state lookups for a predefined time.

public class CachingTogglzConfiguration implements TogglzConfig {

    /* ..... */ 

    @Override
    public StateRepository getStateRepository() {
        StateRepository someOtherRepository = ...;
        return new CachingStateRepository(someOtherRepository, 10000);
    }

}

This example shows how to use CachingStateRepository to act as a cache for another repository. In this configuration it will cache results for 10 seconds. If you omit the timeout, lookups will be cached until setFeatureState() is called for the specific feature. Using the cache without a timeout only makes sense if the repository state is never modified directly (by modifying the database table for example).