package org.togglz.core.bootstrap;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.ServiceLoader;
import java.util.Set;
import org.togglz.core.manager.FeatureManager;
import org.togglz.core.manager.FeatureManagerBuilder;
import org.togglz.core.manager.TogglzConfig;
import org.togglz.core.spi.BeanFinder;
import org.togglz.core.util.Strings;
import org.togglz.core.util.Validate;
/**
*
* <p>
* This class is used to automatically bootstrap a {@link FeatureManager} for Togglz which is the default behavior for simple
* web applications. The bootstrap process heavily relies on the {@link BeanFinder} SPI.
* </p>
*
* <p>
* The bootstrapping process consists of the following steps:
* </p>
*
* <ol>
* <li>First try to locate an implementation of the {@link TogglzBootstrap} interface. If this lookup is successful, a
* {@link FeatureManager} is created from it and returned.</li>
* <li>If the first step fails, the class will try to locate an implementation of the {@link TogglzConfig} interface. If an
* implementation is found, it is used to build a {@link FeatureManager} using
* {@link FeatureManagerBuilder#togglzConfig(TogglzConfig)} which will be returned to the caller.</li>
* </ol>
*
* @author Christian Kaltepoth
*
*/
public class FeatureManagerBootstrapper {
/**
* Tries to automatically build and configure a {@link FeatureManager} like described above.
*
* @param context An optional context object which is provided to the {@link BeanFinder} implementations. This parameter is
* for example used in web application to supply the ServletContext.
* @return A newly created {@link FeatureManager}
* @throws IllegalStateException if the bootstrapping process failed
*/
public FeatureManager createFeatureManager(Object context) {
/*
* Step 1: Try to find TogglzBootstrap implementation
*/
TogglzBootstrap togglzBootstrap = lookupBean(TogglzBootstrap.class, context);
if (togglzBootstrap != null) {
FeatureManager manager = togglzBootstrap.createFeatureManager();
Validate.notNull(manager, togglzBootstrap.getClass().getName() + " returned null");
return manager;
}
/*
* Steps 2: Fallback to use TogglzConfig implementation for FeatureManager configuration
*/
TogglzConfig togglzConfig = lookupBean(TogglzConfig.class, context);
if (togglzConfig != null) {
return new FeatureManagerBuilder()
.togglzConfig(togglzConfig)
.build();
}
// fail with a descriptive error message
throw new IllegalStateException("Could not find any implementation of TogglzConfig or TogglzBootstrap. " +
"Please make sure that you have added the required integration modules to your project " +
"or register the implementation in your web.xml as described in the 'Configuration' chapter of the documentation.");
}
private <T> T lookupBean(Class<T> clazz, Object context) {
Set<T> impls = new HashSet<T>();
for (BeanFinder beanFinder : ServiceLoader.load(BeanFinder.class)) {
Collection<T> result = beanFinder.find(clazz, context);
if (result != null) {
impls.addAll(result);
}
}
if (impls.size() > 1) {
throw new IllegalStateException("Found more than one implementation of the " +
clazz.getSimpleName() + " interface: " + Strings.joinClassNames(impls));
}
if (!impls.isEmpty()) {
return impls.iterator().next();
}
return null;
}
}