is it possible to @Autowired feature toggling?

1,073 views
Skip to first unread message

Eli Abramovitch

unread,
Mar 4, 2013, 10:33:56 AM3/4/13
to togglz...@googlegroups.com
Hi,
I've created a @configuration class for feature toggling and want to @Autowired it.
All i've managed to do is to inject it with the following code:
AnnotationConfigApplicationContext appContext = new AnnotationConfigApplicationContext(ServiceConfig.class);
GenericService service = (GenericService) appContext.getBean("getService");
 
System.out.println(service.whoAmI());
 
I want to prevent all of this code and just do:
@Autowired
GenericService service;
 
System.out.println(service.whoAmI());
 
but all i get is null pointer exception. any help will be appreciated.
 
application-context.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="
http://www.springframework.org/schema/context"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <context:annotation-config/>
    <context:component-scan base-package="com.hp.hpa.featuretoggling.spring"/>
</beans>
 
ServiceConfig:
@Configuration
public class ServiceConfig {
    @Bean
    public DefaultService getDefaultService() {
        return new DefaultService();
    }
    @Bean
    public HighPerformanceService getHighPerformanceService() {
        return new HighPerformanceService();
    }

    @Bean
    public GenericService getService() {
        FeatureProxyFactoryBean proxyFactoryBean = new FeatureProxyFactoryBean();
        proxyFactoryBean.setActive(getHighPerformanceService());
        proxyFactoryBean.setInactive(getDefaultService());
        proxyFactoryBean.setFeature(FeatureList.OPTIMIZED_SITE_FEATURE.name());
        proxyFactoryBean.setProxyType(GenericService.class);
        try {
            return (GenericService) proxyFactoryBean.getObject();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
 
DefaultService.java:
public class DefaultService implements GenericService{
    @Override
    public String whoAmI() {
        return "DefaultService";
    }
}
 
GenericService.java:
public interface GenericService {
    public String whoAmI();
}
 
HighPerformanceService.java:
public class HighPerformanceService implements GenericService{
    @Override
    public String whoAmI() {
        return "HighPerformanceService";
    }
}

Christian Kaltepoth

unread,
Mar 4, 2013, 11:48:13 AM3/4/13
to togglz...@googlegroups.com
Hey,

I'm not an expert on Spring's @Configuration config style, but it looks like your basic setup is correct, because it works when obtaining the proxy directly from the application context.

My guess is that your application context knows about three implementations of the GenericService interface (DefaultService, HighPerformanceService and the proxy) and therefore cannot decide which one to inject. You could try to remove the @Bean annotations from getDefaultService() and getHighPerformanceServer() methods because it looks like they are not really needed. 

But it would also be interesting to know which line of your code throws the NullPointerException.

Christian


2013/3/4 Eli Abramovitch <elim...@gmail.com>

--
 
---
You received this message because you are subscribed to the Google Groups "togglz-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to togglz-users...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Christian Kaltepoth

Eli Abramovitch

unread,
Mar 4, 2013, 12:55:06 PM3/4/13
to togglz...@googlegroups.com
Hi Christian,
My goal is to avoid any usage in xml.
The null pointer results from:
System.out.println(service.whoAmI());
since service is null.
there is an annotation of @primary in configuration, i'll try it out on the getServiceMethod.
I'm not so sure i need to remove the @Bean from the other methods but hey, it doesn't hurt to try:)
thanks 4 the quick response - i'll check it out and post my results

Christian Kaltepoth

unread,
Mar 5, 2013, 2:17:56 AM3/5/13
to togglz...@googlegroups.com
Hey Eli,

sure, give it a try. You could also (just for a test) try to directly inject one of the two implementations. Just to make sure the autowiring works at all.

Marcin Grzejszczak

unread,
Sep 25, 2013, 5:29:36 AM9/25/13
to togglz...@googlegroups.com
Hi! 

I had a very simillar issue...

When you have the FeatureProxyFactoryBean it will try to autowire immediately the proper implementation. What is probelmatic is that my TogglzConfig is a Spring bean and it's using some autowired fields to retrieve the feature states (from DB) and user permissions (also DB). The issue is that the SpringBeanFinder is trying to retrieve the current ApplicationContext which is somehow not loaded (I can't see any attempts to retrieve current ApplicationContext but only WebApplicationContext). So that's why my TogglzConfig never got found. First thing that I tried was to provide in the META-INF the path to my FeatureManager. Even though this FeatureManager got found it got instantiated using the new operator (that's why I had no dependencies injected) and nullpointers got thrown again.

The solution to this problem was to make the FeatureProxy annotated like this:

    @Bean
    @Scope(proxyMode = ScopedProxyMode.INTERFACES)
    public FactoryBean<SomeInterface> someInterface() {
       ....
    }

I reverted the changes related to META-INF and ServiceLoader and had again @Component annotated TogglzConfig. By using the ScopedProxyMode.INTERFACES what got injected was the Proxy and not the real implementation. Afterwards after adding the TogglzFilter to web.xml when the Web Context actually got initialized it got bound to Togglz and eventually when the autowired field was used for the first time the real implementation was chosen basing on the TogglzConfig bean.

It seems that either I made some mistakes in the configuration or something's wrong with Spring integration cause it's a little bit tricky (add TogglzFilter to bind current context to FeatureManagerProviders, add Proxy scope so that we postpone searching for the real implementation until the context is up and running...).

BR,
Marcin

Christian Kaltepoth

unread,
Sep 25, 2013, 12:25:23 PM9/25/13
to togglz...@googlegroups.com
Hey Marcin,

I think there are different issues you are talking about. So I'll try to comment on them individually.

It's really weird that SpringBeanFinder doesn't find your WebApplicationContext. Actually Spring's ContextLoaderListener should store it in the ServletContext where the bean finder should be able to find it. Or isn't your application a webapp at all?

It's correct that FeatureProxyFactoryBean requires to resolve the wrapped services immediately. And I don't see any workaround for this from Togglz' side. However, I'm a bit surprised that this leads to problems. Actually the dependent services (for the active and non active case) are resolved immediately. But the feature state is only checked when the feature proxy created by the factory is accessed. So there should be no problem at creation time of the proxy. At least I don't see any reason for a problem. :)

It would be really interesting to see a full stack trace of the original exception your got.

For web application I always recommend to use togglz-servlet because it really simplifies the setup process. In Servlet 3.0 containers it is actually just a matter of adding the togglz-servlet dependency. The filter will be registered automatically.

Christian 



2013/9/25 Marcin Grzejszczak <marcin.gr...@gmail.com>

Marcin Grzejszczak

unread,
Sep 26, 2013, 4:12:15 AM9/26/13
to togglz...@googlegroups.com
Hi!

Thanks for the reply - let me go through step by step.
  1. We have a Spring WebApplication running in servlet 2.5 env. 
  2. Initially I did as you presented on the website so I annotated implementation of TogglzConfig as @Component
  3. We had the FeatureProxyFactoryBean that was supposed to switch between two implementations - that's why on the level of bean autowiring we already had Togglz context setup called
  4. Unfortunately TogglzConfig never got found by the SpringBeanFinder - we got the 

    IllegalStateExceotion: Could not find the FeatureManager. For web applications please verify that the TogglzFilter starts up correctly. In other deployment scenarios you will typically have to implement a FeatureManagerProvider as described in the 'Advanced Configuration' chapter of the documentation.

    Thrown from FeatureContext.getFeatureManager()

  5. The SpringBeanFinder always returned null for application context - it never got found (which is hillarious since the whole process got executed from the application context)
  6. My first workaround to retrieve the Toggle configuration involved manual FeatureProvider creation and I added it to the META-INF folder - it worked the FeatureProvider was found
  7. Unfortunately it got instantiated by the new operator so it was not part of the ApplcationContext so all of the fields where not autowired (NPE were thrown)
  8. I removed mine FeatureProvider, added the TogglzFilter to web.xml and removed the FeatureProxy - everything started to work! SpringBeanFinder (when in the code a feature was checked for being active) found the @Component annotated TogglzConfig
  9. In order to postpone the autowiring process untill the implementation is actually used I annotated the FeatureProxyFactoryBean by @Scope(proxyMode = ScopedProxyMode.INTERFACES) - this way the TogglzFilter's logic is activated before the feature resolution takes place
Hope that this time I managed to clarify it a bit :)

BR,
Marcin

Christian Kaltepoth

unread,
Sep 27, 2013, 12:39:19 AM9/27/13
to togglz...@googlegroups.com
Hey,

thanks a lot for your detailed explanation. Let me respond to some points:

3. This is the thing that is really strange. I don't see a reason why the Togglz FeatureManager lookup is performed when creating the proxy. IMHO this should not happen at creation time of the proxy. If the lookup is done so early during startup, then it makes sense that the bootstrapping of Togglz fails, because it happens during Spring startup and not after it.

4. Could you perhaps show more of the stack trace. I would like to know why FeatureContext.getFeatureManager() is called.

6. Do you mean FeatureProvider or FeatureManagerProvider? I think you tried to implement the latter one, right? And yes, if you implement the SPI this way, injection of Spring beans won't work.

9. Yeah, this should definitely be a way to work around this problem. However, I'm still not sure why the creation of the proxy triggers a call to FeatureContext.getFeatureManager() which is the root problem.

Best regards

Christian
  


2013/9/26 Marcin Grzejszczak <marcin.gr...@gmail.com>
Reply all
Reply to author
Forward
0 new messages