views:

148

answers:

2

Hi,

I'm building a webapp that should run on both Tomcat and WebSphere and I've managed to make almost all the differences into properties with default values that I can override for deployment on the Tomcat server.

I need to do yet another override for the authentication provider bean...

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    if(isWebSphere()){
        LOG.warn("Running on WebSphere... not overriding default authentication mechanism.");
        return;
    }
    LOG.info("Running on Tomcat... overriding authentication provider bean ("+AUTHENTICATION_PROVIDER_BEAN+")");
    if (beanFactory.containsBean(AUTHENTICATOR_BEAN) && beanFactory.containsBean(POPULATOR_BEAN) && beanFactory.containsBean(USERDETAIL_PROVIDER_BEAN)){
        LdapAuthenticator authenticator = (LdapAuthenticator) beanFactory.getBean(AUTHENTICATOR_BEAN);
        LdapAuthoritiesPopulator populator = (LdapAuthoritiesPopulator) beanFactory.getBean(POPULATOR_BEAN);
        UserDetailProvider userDetailProvider = (UserDetailProvider) beanFactory.getBean(USERDETAIL_PROVIDER_BEAN);
        ExtendedLdapAuthenticationProvider override = new ExtendedLdapAuthenticationProvider(authenticator, populator);
        override.setUserDetailProvider(userDetailProvider);

        beanFactory.registerSingleton(AUTHENTICATION_PROVIDER_BEAN, override);
    } else {
        throw new BeanCreationException("Could not find required beans to assemble overriding object for authentication...");
    }
}

Now my problem is how to implement the isWebSphere() method. I was thinking Class.forName("someWebSphereSpecific"), but is there a better way?

+1  A: 

The ServletContext includes a method getServerInfo() which, for my tomcat, returns "Apache Tomcat/6.0.13". I assume that webSphere will return something equally distinguishable.

The only question you then have is how to get the ServletContext. If you look up the APIdoc index under getServletConfig(), you'll see that it's available from a whole lot of places. If your servlet is a bean that's created by your bean factory, then you can call servletBean.getServletConfig().getServerInfo().

If none of the beans you create give you access, you could create a dummy servlet that is purely for doing this detection - not the neatest, but it should work.

John
A: 

Here's my final solution based on John's recommendation:

public class ServerInfoBeanOverrider implements BeanFactoryPostProcessor, ServletContextAware {
    private static final Log LOG = LogFactory.getLog(ServerInfoBeanOverrider.class);

    private String test;
    private Object overrideBean;
    private String overrideName;

    private String serverInfo;

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        if(LOG.isDebugEnabled()){
            LOG.debug("Testing if overriding is needed for server '"+serverInfo+"' with test pattern: " + test);
        }
        if(Pattern.matches(test, serverInfo)){
            if(LOG.isDebugEnabled()){
                LOG.debug("Overriding matched... replacing bean with name: " + overrideName);
            }
            beanFactory.registerSingleton(overrideName, overrideBean);
            LOG.info("Replaced bean with name: "+ overrideName + " for server: " + serverInfo);
        }
    }

    public void setServletContext(ServletContext servletContext) {
        this.serverInfo = servletContext.getServerInfo();
    }

    public void setOverrideBean(Object overrideBean) {
        this.overrideBean = overrideBean;
    }

    public void setOverrideName(String overrideName) {
        this.overrideName = overrideName;
    }

    public void setTest(String test) {
        this.test = test;
    }
}

This will allow overriding a bean based on the server info string matching or not a regex.

It is used like this:

  <!-- Replace with Tomcat's version if not running on WebSphere -->
  <bean class="some.company.web.util.ServerInfoBeanOverrider">
    <property name="test" value="Apache Tomcat/.*" />
    <property name="overrideName" value="authenticationProvider" />
    <property name="overrideBean">
      <bean class="some.company.providers.ExtendedLdapAuthenticationProvider" lazy-init="true">
        <constructor-arg ref="ldapAuthenticator" />
        <constructor-arg ref="ldapAuthoritiesPopulator" />
        <property name="userDetailProvider" ref="someUserDetailProvider" />
      </bean>
    </property>
  </bean>
Pedro Guedes