Advanced Configuration

One of the mission statements of Togglz is that it should be easy to integrate into applications. As described in the Configuration chapter, this is especially easy for web applications. If you want to integrate Togglz into other environments, you will typically have to do some manual steps.

This chapter will cover how to bootstrap and use Togglz in the following environments:

Basic concept

Most of the strategies described in this chapter are based on the idea of implementing a custom FeatureManagerProvider. This SPI is used by Togglz to find the FeatureManager for the application. You can think of the FeatureManager as a central service that manages the features of your application.

If you are using Togglz in a web application, the FeatureManager will be created automatically during application startup. During this process Togglz will try to automatically find your implementation of the TogglzConfig interface, which acts as the configuration for the FeatureManager.

Depending on the environment you want to integrate Togglz into, you may have to build the FeatureManager yourself. Fortunately Togglz provides a class called FeatureManagerBuilder which simplifies this process. To build a FeatureManager that is configured using a TogglzConfig instance, you can use this code:

FeatureManager manager = new FeatureManagerBuilder()
        .togglzConfig(new MyTogglzConfig())
        .build();

This is basically what Togglz does when starting up in a web application.

If you are using FeatureManagerBuilder to create your FeatureManager, you don't even have to implement TogglzConfig at all. You can also simply configure all the aspects of Togglz by calling the corresponding methods on the builder:

FeatureManager manager = new FeatureManagerBuilder()
        .featureClass(MyFeaturess.class)
        .stateRepository(new InMemoryStateRepository())
        .userProvider(new NoOpUserProvider())
        .build();

Togglz uses an service provider interfaces called FeatureManagerProvider to find the FeatureManager to use in the current execution context. Implementing this interface is very easy. The only thing you have to think about is how to maintain (or obtain) the single FeatureManager instance for your application. The following sections will describe best practices for doing this in different environments and advanced packaging scenarios.

Environment Scenarios

Standalone Applications

Using Togglz in standalone applications requires some more work compared to applications which are deployed to an application server.

In most cases standalone applications don't have such complex classloading configurations as application servers. Therefore you can typically use a simple singleton approach to manage the FeatureManager.

The following example shows an implementation of the FeatureManagerProvider that uses this approach:

public class SingletonFeatureManagerProvider implements FeatureManagerProvider {

    private static FeatureManager featureManager;

    @Override
    public int priority() {
        return 30;
    }

    @Override
    public synchronized FeatureManager getFeatureManager() {

        if (featureManager == null) {
            featureManager = new FeatureManagerBuilder()
                    .featureClass(MyFeaturess.class)
                    .stateRepository(new InMemoryStateRepository())
                    .userProvider(new NoOpUserProvider())
                    .build();
        }

        return featureManager;

    }

}

To register the provider, take the fully qualified name of your implementation class and save it in a file called META-INF/services/org.togglz.core.spi.FeatureManagerProvider on your classpath. See the docs of the ServiceLoader class for a full description of the underlying mechanism.

EJBs and EAR packaging (JEE6)

If you want to use Togglz in an environment with EJB and/or EAR packaging and your application server supports EJB 3.1, you can use an EJB singleton to manage the FeatureManager. To do so, create an EJB singleton that builds the FeatureManager in the @PostConstruct method:

@Singleton
public class FeatureManagerSingleton {

    private FeatureManager featureManager;

    @PostConstruct
    public void init() {
        featureManager = new FeatureManagerBuilder()
            .featureClass(MyFeaturess.class)
            .stateRepository(new InMemoryStateRepository())
            .userProvider(new NoOpUserProvider())
            .build();
    }

    public FeatureManager getFeatureManager() {
        return featureManager;
    }

}

Now you have to create an implementation of FeatureManagerProvider that uses the EJB singleton to obtain the FeatureManager:

public class EJBSingletonFeatureManagerProvider implements FeatureManagerProvider {

    @Override
    public int priority() {
        return 30;
    }

    @Override
    public FeatureManager getFeatureManager() {

        try {

            InitialContext context = new InitialContext();
            FeatureManagerSingleton singleton = (FeatureManagerSingleton)
                context.lookup("java:module/FeatureManagerSingleton");
            return singleton.getFeatureManager();

        } catch (NamingException e) {
            return null;
        }

    }

}

To register the provider, take the fully qualified name of your implementation class and save it in a file called META-INF/services/org.togglz.core.spi.FeatureManagerProvider on your classpath. See the docs of the ServiceLoader class for a full description of the underlying mechanism.

This will work fine for the EJB module itself, because the JNDI name used to lookup the singleton is relative to that module. If you want a shared FeatureManager for all modules in your EAR, you will have to change the JNDI name to something like this:

java:app/MyModule/FeatureManagerSingleton

If your EAR file also contains web applications and you want to use one shared FeatureManager for the complete EAR, you have to perform one additional step. In the default setup Togglz automatically creates a local FeatureManager for a web application. To prevent this, add the following configuration to your web.xml:

<context-param>
  <param-name>org.togglz.FEATURE_MANAGER_PROVIDED</param-name>
  <param-value>true</param-value>
</context-param>

If you add this configuration and your custom FeatureManagerProvider is visible for your web application, Togglz will automatically use the shared FeatureManager maintained by the EJB singleton.