Created
February 28, 2013 06:43
-
-
Save Synesso/5054751 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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