Skip to content

Instantly share code, notes, and snippets.

@Synesso
Created February 28, 2013 06:43
Show Gist options
  • Select an option

  • Save Synesso/5054751 to your computer and use it in GitHub Desktop.

Select an option

Save Synesso/5054751 to your computer and use it in GitHub Desktop.
package ari.dnrs.registry.configuration;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import java.util.Set;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.togglz.core.Feature;
import org.togglz.core.annotation.Label;
import org.togglz.core.context.FeatureContext;
import org.togglz.core.context.ThreadLocalFeatureManagerProvider;
import org.togglz.core.manager.FeatureManagerBuilder;
import org.togglz.core.repository.FeatureState;
import org.togglz.core.repository.mem.InMemoryStateRepository;
import org.togglz.core.user.NoOpUserProvider;
import org.togglz.spring.proxy.FeatureProxyFactoryBean;
import com.google.common.collect.Sets;
public class FeaturesTest {
private static InMemoryStateRepository inMemoryStateRepository;
private Fruit fruit;
private ApplicationContext context;
@Before
public void setUp() throws Exception {
inMemoryStateRepository = new InMemoryStateRepository();
ThreadLocalFeatureManagerProvider.release();
ThreadLocalFeatureManagerProvider.bind(new FeatureManagerBuilder()
.featureClass(Features.class)
.stateRepository(inMemoryStateRepository)
.userProvider(new NoOpUserProvider())
.build());
context = new AnnotationConfigApplicationContext(FeaturesTestConfiguration.class);
fruit = context.getBean(Fruit.class);
}
@Test
public void shouldProxyToTheOldInstanceWhenInactive() {
inMemoryStateRepository.setFeatureState(new FeatureState(Features.FANCY_FRUIT, false));
assertThat(fruit.toString(), is("mango"));
}
@Test
public void shouldProxyToTheNewInstanceWhenActive() {
inMemoryStateRepository.setFeatureState(new FeatureState(Features.FANCY_FRUIT, true));
fruit = context.getBean(Fruit.class);
assertThat(fruit.toString(), is("apple"));
}
@Test
public void shouldSwitchDelegatesAtRuntime() {
inMemoryStateRepository.setFeatureState(new FeatureState(Features.FANCY_FRUIT, false));
assertThat(fruit.toString(), is("mango"));
inMemoryStateRepository.setFeatureState(new FeatureState(Features.FANCY_FRUIT, true));
assertThat(fruit.toString(), is("apple"));
inMemoryStateRepository.setFeatureState(new FeatureState(Features.FANCY_FRUIT, false));
assertThat(fruit.toString(), is("mango"));
}
public enum Features implements Feature {
@Label("Fancy Fruit")
FANCY_FRUIT;
@Override
public boolean isActive() {
return FeatureContext.getFeatureManager().isActive(this);
}
@SuppressWarnings("unchecked")
public <T, U extends T, V extends T> T toggle(U activeInstance, V inactiveInstance) {
T proxy = null;
final FeatureProxyFactoryBean proxyFactoryBean = new FeatureProxyFactoryBean();
proxyFactoryBean.setActive(activeInstance);
proxyFactoryBean.setInactive(inactiveInstance);
proxyFactoryBean.setFeature(this.name());
Set<Class<?>> commonInterfaces = Sets.intersection(
Sets.newHashSet(activeInstance.getClass().getInterfaces()),
Sets.newHashSet(inactiveInstance.getClass().getInterfaces())
);
for (Class<?> commonInterface : commonInterfaces) {
if (proxy == null) {
try {
proxy = (T) commonInterface.cast(proxyFactoryBean.getObject());
proxyFactoryBean.setProxyType(commonInterface);
break;
} catch (ClassCastException e) {
// continue
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
// by now proxy will not be null, because the compiler ensures U and V have a common interface
// TODO - is this true for super types (non interface)?
return proxy;
}
}
@Configuration
public static class FeaturesTestConfiguration {
@Bean
public Fruit fancyFruit() {
return Features.FANCY_FRUIT.toggle(new Apple(), new Mango());
}
}
private static interface Fruit {
}
private static interface Tropical {
}
private static interface Round {
}
private static class Apple implements Round, Fruit {
@Override
public String toString() {
return "apple";
}
}
private static class Mango implements Tropical, Fruit {
@Override
public String toString() {
return "mango";
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment