0 Replies Latest reply on Jan 12, 2010 1:08 PM by gonzalad

    SpringBeanAutowiringSupport

    gonzalad

      Hello,


      The current version of Seam Spring Integration doesn't support the use of  SpringBeanAutowiringSupport.


      When a Seam application containing in it's components.xml :


           <spring:context-loader>
                <spring:config-locations>
                     <value>classpath:applicationContext.xml</value>
                </spring:config-locations>
           </spring:context-loader>
      



      It starts the Spring Application Context and registers it in the servletContext.
      But, contrary to Spring WebApplicationContextUtils class, it doesn't registers it in a static Map of ContextLoader.


      If you use SpringBeanAutowiringSupport, you need the ContextLoader static field initialized.


      To do it, we just implemented this hackish class.
      You just need to add it to your application :




      package com.mycompany.jsf.web;
      
      import java.lang.reflect.Field;
      import java.util.Map;
      
      import javax.annotation.PostConstruct;
      import javax.annotation.PreDestroy;
      import javax.servlet.ServletContext;
      
      import org.apache.commons.logging.Log;
      import org.apache.commons.logging.LogFactory;
      import org.jboss.seam.ScopeType;
      import org.jboss.seam.annotations.Install;
      import org.jboss.seam.annotations.Name;
      import org.jboss.seam.annotations.Scope;
      import org.jboss.seam.annotations.Startup;
      import org.jboss.seam.annotations.intercept.BypassInterceptors;
      import org.jboss.seam.contexts.ServletLifecycle;
      import org.springframework.web.context.WebApplicationContext;
      
      /**
       * <p>
       * Ce composant effectuer le reste du travail de
       * <code>org.jboss.seam.ioc.spring.ContextLoader</code> :
       * <ul>
       * <li> le ContextLoader de Seam enregistre le contexte Spring dans le
       * ServletContext. Il est donc disponible via un appel à
       * <code>WebApplicationContextUtils.getWebApplicationContext(ServletContext)</code>/</li>
       * <li> cette classe enregistre le contexte Spring dans les variables
       * threadLocal de ContextLoader de Spring. Il est donc aussi disponible via
       * ContextLoader.getCurrentWebApplicationContext().</li>
       * </ul>
       * </p>
       */
      @Scope(ScopeType.APPLICATION)
      @BypassInterceptors
      @Startup(depends = "org.jboss.seam.ioc.spring.contextLoader")
      @Name("com.mycompany.jsf.web.contextLoader")
      @Install(precedence = Install.FRAMEWORK)
      public class SpringContextLoader {
      
           private static final Log logger = LogFactory.getLog(SpringContextLoader.class);
           private boolean hasRegisteredInThreadLocal;
      
           @PostConstruct
           public void initialize() {
                registerInThreadLocal();
           }
      
           @PreDestroy
           public void destroy() {
                unregisterFromThreadLocal();
           }
      
           private WebApplicationContext getCurrentWebApplicationContext(ServletContext aServletContext) {
                WebApplicationContext lWebApplicationContextInServletContext = (WebApplicationContext) aServletContext
                          .getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
                return lWebApplicationContextInServletContext;
           }
      
           @SuppressWarnings("unchecked")
           private void registerInThreadLocal() {
                WebApplicationContext lWebApplicationContextInServletContext = 
                     getCurrentWebApplicationContext(ServletLifecycle.getServletContext());
                if (lWebApplicationContextInServletContext == null) {
                     logger.warn("Le webApplication Context de Spring n'a pas été enregistré. Ce n'est pas normal."
                               +" Enregistrement de l'applicationContext Spring dans threadLocal annulé.");
                     return;
                }
                WebApplicationContext lWebApplicationContextInThreadLocal = 
                          org.springframework.web.context.ContextLoader.getCurrentWebApplicationContext();
                if (lWebApplicationContextInThreadLocal != null) {
                     logger.debug("Le webApplication Context de Spring est déjà enregistré dans le threadLocal.");
                     return;
                }
                Field lField = getCurrentContextPerThreadField();
                if (lField == null) {
                     logger.error("Erreur interne : SpringContextLoaderListener se base sur l'existence de l'attribut"
                               + " currentContextPerThread de org.springframework.web.context.ContextLoader."
                               + " L'applicationContext de Spring ne peut pas être enregistré auprès du ContextLoader."
                               + " Erreur ignorée.");
                     return;
                }
                lField.setAccessible(true);
                Map lCurrentContextPerThread;
                try {
                     lCurrentContextPerThread = (Map) lField.get(null);
                } catch (IllegalArgumentException e) {
                     throw new IllegalStateException("Erreur lors de l'accès au champs " + lField + " : " + e.toString(), e);
                } catch (IllegalAccessException e) {
                     throw new IllegalStateException("Erreur lors de l'accès au champs " + lField + " : " + e.toString(), e);
                }
                lCurrentContextPerThread.put(Thread.currentThread().getContextClassLoader(), 
                          lWebApplicationContextInServletContext);
           }
      
           @SuppressWarnings("unchecked")
           private void unregisterFromThreadLocal() {
                if (hasRegisteredInThreadLocal) {
                     Field lField = getCurrentContextPerThreadField();
                     if (lField == null) {
                          return;
                     }
                     lField.setAccessible(true);
                     Map lCurrentContextPerThread;
                     try {
                          lCurrentContextPerThread = (Map) lField.get(null);
                     } catch (IllegalArgumentException e) {
                          throw new IllegalStateException("Erreur lors de l'accès au champs " + lField + " : " + e.toString(), e);
                     } catch (IllegalAccessException e) {
                          throw new IllegalStateException("Erreur lors de l'accès au champs " + lField + " : " + e.toString(), e);
                     }
                     lCurrentContextPerThread.remove(Thread.currentThread().getContextClassLoader());
                }
           }
      
           private Field getCurrentContextPerThreadField() {
                Field lField = null;
                try {
                     lField = org.springframework.web.context.ContextLoader.class.getDeclaredField("currentContextPerThread");
                } catch (SecurityException e) {
                     logger.error("Erreur interne : erreur lors de la récupération de l'attribut currentContextPerThread"
                               +" de la classe org.springframework.web.context.ContextLoader "+e.toString(), e);
                } catch (NoSuchFieldException e) {
                     logger.error("Erreur interne : erreur lors de la récupération de l'attribut currentContextPerThread"
                               +" de la classe org.springframework.web.context.ContextLoader "+e.toString(), e);
                }
                if (lField != null) {
                     lField.setAccessible(true);
                }
                return lField;
           }
      }
      



      Sample usage :



      @javax.jws.WebService (endpointInterface="com.mycompany.wsdl.aws.charge_1.ChargeService1", 
                targetNamespace="http://www.mycompany.com/wsdl/aws/charge-1", 
                serviceName="ChargeService1", 
                portName="ChargeService1SOAP", 
                wsdlLocation="WEB-INF/wsdl/ChargeService-1.wsdl")
      @HandlerChain(file="handler-chain.xml")
      public class ChargeService1SOAPImpl extends SpringBeanAutowiringSupport {
      
           @Autowired
           private IChargeClienteleFacade facade;
           
          public ChargeClienteleType findChargeById(ChargeClientelePkType aChargePk, int aIndexClient, int aNbClients) 
                    throws ChargeClienteleInexistantFault {
              return facade.findChargeById(aChargePk, aIndexClient, aNbClients);
          }
      



      Hope this helps someone...