package org.jboss.seam.ioc.spring; import org.jboss.seam.ScopeType; import org.jboss.seam.contexts.Contexts; import org.jboss.seam.contexts.Lifecycle; import org.jboss.seam.core.Init; import org.jboss.seam.log.LogProvider; import org.jboss.seam.log.Logging; import org.springframework.beans.BeansException; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; /** * Post processor that makes all of the seam scopes available in * spring and takes all of the beans with those scopes and creates * Seam Components out of them. <p/> To use simply define the * namespace handler in in your ApplicationContext. * <seam:configure-scopes/> * * @author youngm */ public class SeamScopePostProcessor implements BeanFactoryPostProcessor, InitializingBean { private static final LogProvider log = Logging.getLogProvider(SeamScopePostProcessor.class); /** * Default seam scope prefix. */ public static final String DEFAULT_SCOPE_PREFIX = "seam."; private String prefix; private boolean defaultAutoCreate = false; /** * Null is not a valid prefix so make it the default is used if null or empty. * * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() */ public void afterPropertiesSet() throws Exception { if (prefix == null || "".equals(prefix)) { prefix = DEFAULT_SCOPE_PREFIX; } } /** * Add all of the seam scopes to this beanFactory. * * @see org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory) */ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { for (ScopeType scope : ScopeType.values()) { // Don't create a scope for Unspecified if (scope != ScopeType.UNSPECIFIED) { beanFactory.registerScope(prefix + scope.name(), new SeamScope(scope)); beanFactory.registerScope(prefix + scope.name().toLowerCase(), new SeamScope(scope)); } } // Create a mock application context if not available. // TODO Reuse boolean unmockApplication = false; if (!Contexts.isApplicationContextActive()) { Lifecycle.setupApplication(); unmockApplication = true; } try { // Iterate through all the beans in the factory for (String beanName : beanFactory.getBeanDefinitionNames()) { BeanDefinition definition = beanFactory.getBeanDefinition(beanName); ScopeType scope; if (definition.getScope().startsWith(prefix)) { // Will throw an error if the scope is not found. scope = ScopeType.valueOf(definition.getScope().replaceFirst(prefix, "").toUpperCase()); } else { if (log.isDebugEnabled()) { log.debug("No scope could be derived for bean with name: " + beanName); } continue; } if (scope == ScopeType.UNSPECIFIED) { if (log.isDebugEnabled()) { log.debug("Discarding bean with scope UNSPECIFIED. Spring will throw an error later: " + beanName); } continue; } // Cannot be a seam component without a specified class seam:component will need to be used for this // bean. if (definition.getBeanClassName() == null) { if (log.isDebugEnabled()) { log.debug("Unable to create component for bean: " + beanName + ". No class defined try seam:component instead."); } continue; } SpringComponent.addSpringComponent(beanName, beanName, definition.getBeanClassName(), scope, beanFactory, null); if (defaultAutoCreate) { Init.instance().addAutocreateVariable(beanName); } } } finally { if (unmockApplication) { Lifecycle.cleanupApplication(); } } } /** * @param prefix case sensitive the prefix to use to identify seam scopes for spring beans. Default is "seam." */ public void setPrefix(String prefix) { this.prefix = prefix; } /** * @param defaultAutoCreate whether or not context variables should be set to auto-create. Default is false. */ public void setDefaultAutoCreate(boolean defaultAutoCreate) { this.defaultAutoCreate = defaultAutoCreate; } }