Announcement Announcement Module
Collapse
No announcement yet.
Spring/JBoss/EJB3 -> Problems calling ejbs Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring/JBoss/EJB3 -> Problems calling ejbs

    Hello!

    I've put JBoss 4.2.2, EJB3.0 and Spring 2.5.1 together. However, I haven't succeeded to call the local EJBs yet.

    I've defined an EJB as follows:

    Code:
    @Stateless
    @Interceptors(SpringBeanAutowiringInterceptor.class)
    public class AccountServiceImpl implements AccountService, AccountServiceLocal {
    
    	@Autowired
    	private AccountDao accountDao;
    	private String tempFileName = "idsa2008file.dat";
    
    	@Override
    	public List<Account> getAllAccountsMNormal() {
    		return accountDao.getAccounts();
    	}
    The AccountService is used in JSF bean in the web container:
    Code:
    public class AccountAction {
    
    	private AccountService accountService;
    
    	/**
    	 * 
    	 * @return Action string.
    	 */
    	@SuppressWarnings("unchecked")
    	public String getAllAccounts() {
                List<Account> accounts = accountService.getAllAccounts();
                ....
    My application context, separated in 2 different files looks as follows:

    Code:
    	<!--  Repository configuration by annotations -->
         <context:annotation-config/>               
         <context:component-scan base-package="foo"/>
    
    	<!--  Configuration for defined persistence unit in persistence.xml -->
         <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
          <property name="persistenceUnitName" value="fooPersistenceUnit"/>
         </bean>
         
          <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
      		<property name="entityManagerFactory" ref="entityManagerFactory" />
          </bean>
          
          <!--  Transaction configuration by annotions -->
          <tx:annotation-driven transaction-manager="transactionManager"/>
    
    	<jee:jndi-lookup  id="accountServiceEjb" jndi-name="foo/AccountServiceImpl/local" lookup-on-startup="false" proxy-interface="foo.service.AccountService"/>
    
    	<bean id="accountAction"
            class="foo.web.jsf.AccountAction">
             <property name="accountService" ref="accountServiceEjb"/>
        </bean>
    Though, something is wrong. I can deploy the application without errors, but when I call a method on the ejb, the application throws following runtime error:

    Code:
    org.springframework.beans.factory.access.BootstrapException: Unable to return specified BeanFactory instance: factory key [null], from group with resource name [classpath*:beanRefContext.xml]; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [org.springframework.beans.factory.BeanFactory] is defined: expected single bean but found 0
    	org.springframework.beans.factory.access.SingletonBeanFactoryLocator.useBeanFactory(SingletonBeanFactoryLocator.java:410)
    	org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor.getBeanFactoryReference(SpringBeanAutowiringInterceptor.java:132)
    	org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor.getBeanFactory(SpringBeanAutowiringInterceptor.java:113)
    	org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor.autowireBean(SpringBeanAutowiringInterceptor.java:93)
    	sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    	sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    	java.lang.reflect.Method.invoke(Method.java:597)
    	org.jboss.ejb3.interceptor.LifecycleInvocationContextImpl.proceed(LifecycleInvocationContextImpl.java:131)
    	org.jboss.ejb3.interceptor.LifecycleInterceptorHandler.postConstruct(LifecycleInterceptorHandler.java:109)
    	org.jboss.ejb3.EJBContainer.invokePostConstruct(EJBContainer.java:619)
    	org.jboss.ejb3.AbstractPool.create(AbstractPool.java:131)
    	org.jboss.ejb3.InfinitePool.get(InfinitePool.java:49)
    	org.jboss.ejb3.ThreadlocalPool.create(ThreadlocalPool.java:50)
    	org.jboss.ejb3.ThreadlocalPool.get(ThreadlocalPool.java:90)
    	org.jboss.ejb3.stateless.StatelessInstanceInterceptor.invoke(StatelessInstanceInterceptor.java:54)
    	org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    	org.jboss.aspects.security.AuthenticationInterceptor.invoke(AuthenticationInterceptor.java:77)
    	org.jboss.ejb3.security.Ejb3AuthenticationInterceptor.invoke(Ejb3AuthenticationInterceptor.java:110)
    	org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    	org.jboss.ejb3.ENCPropagationInterceptor.invoke(ENCPropagationInterceptor.java:46)
    	org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    	org.jboss.ejb3.asynchronous.AsynchronousInterceptor.invoke(AsynchronousInterceptor.java:106)
    	org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    	org.jboss.ejb3.stateless.StatelessContainer.localInvoke(StatelessContainer.java:240)
    	org.jboss.ejb3.stateless.StatelessContainer.localInvoke(StatelessContainer.java:210)
    	org.jboss.ejb3.stateless.StatelessLocalProxy.invoke(StatelessLocalProxy.java:84)
    	$Proxy91.getAllAccounts(Unknown Source)
    	sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    	sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    	java.lang.reflect.Method.invoke(Method.java:597)
    	org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:301)
    	org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:198)
    	$Proxy82.getAllAccounts(Unknown Source)
    	foo.web.jsf.AccountAction.getAllAccounts(AccountAction.java:35)
    .....
    root cause
    
    org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [org.springframework.beans.factory.BeanFactory] is defined: expected single bean but found 0
    	org.springframework.beans.factory.BeanFactoryUtils.beanOfType(BeanFactoryUtils.java:379)
    	org.springframework.beans.factory.access.SingletonBeanFactoryLocator.useBeanFactory(SingletonBeanFactoryLocator.java:400)
    	org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor.getBeanFactoryReference(SpringBeanAutowiringInterceptor.java:132)
    	org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor.getBeanFactory(SpringBeanAutowiringInterceptor.java:113)
    	org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor.autowireBean(SpringBeanAutowiringInterceptor.java:93)
    	sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    	sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    	java.lang.reflect.Method.invoke(Method.java:597)
    	org.jboss.ejb3.interceptor.LifecycleInvocationContextImpl.proceed(LifecycleInvocationContextImpl.java:131)
    	org.jboss.ejb3.interceptor.LifecycleInterceptorHandler.postConstruct(LifecycleInterceptorHandler.java:109)
    	org.jboss.ejb3.EJBContainer.invokePostConstruct(EJBContainer.java:619)
    	org.jboss.ejb3.AbstractPool.create(AbstractPool.java:131)
    	org.jboss.ejb3.InfinitePool.get(InfinitePool.java:49)
    	org.jboss.ejb3.ThreadlocalPool.create(ThreadlocalPool.java:50)
    	org.jboss.ejb3.ThreadlocalPool.get(ThreadlocalPool.java:90)
    	org.jboss.ejb3.stateless.StatelessInstanceInterceptor.invoke(StatelessInstanceInterceptor.java:54)
    	org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    	org.jboss.aspects.security.AuthenticationInterceptor.invoke(AuthenticationInterceptor.java:77)
    	org.jboss.ejb3.security.Ejb3AuthenticationInterceptor.invoke(Ejb3AuthenticationInterceptor.java:110)
    	org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    	org.jboss.ejb3.ENCPropagationInterceptor.invoke(ENCPropagationInterceptor.java:46)
    	org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    	org.jboss.ejb3.asynchronous.AsynchronousInterceptor.invoke(AsynchronousInterceptor.java:106)
    	org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    	org.jboss.ejb3.stateless.StatelessContainer.localInvoke(StatelessContainer.java:240)
    	org.jboss.ejb3.stateless.StatelessContainer.localInvoke(StatelessContainer.java:210)
    	org.jboss.ejb3.stateless.StatelessLocalProxy.invoke(StatelessLocalProxy.java:84)
    	$Proxy91.getAllAccounts(Unknown Source)
    	sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    	sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    	java.lang.reflect.Method.invoke(Method.java:597)
    	org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:301)
    	org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:198)
    	$Proxy82.getAllAccounts(Unknown Source)
    	foo.web.jsf.AccountAction.getAllAccounts(AccountAction.java:35)
    	........
    I guess the injection is not working properly. There is a accountService instance, however, it can't use it.
    Can anybody help me?

    Thanks

    Kuno

  • #2
    It seems that you're not defining nested ApplicationContexts there in your beanRefContext.xml file... Check out the javadoc of "org.springframework.beans.factory.access.Singleto nBeanFactoryLocator" for examples.

    Essentially, your "beanRefContext.xml" file will typically define a ClassPathXmlApplicationContext which in turns loads your actual beans. The "beanRefContext.xml" mechanism allows multiple such shared ApplicationContexts to co-exist, differentiated by bean factory locators. In the default EJB3 case, simply define one such ApplicationContext which will be picked up automatically, regardless of name.

    A "beanRefContext.xml" example:

    Code:
    <beans>
    
      <bean id="myContext" class="org.springframework.context.support.ClassPathXmlApplicationContext">
        <constructor-arg value="myContextBeans.xml"/>
      </bean>
    
    </beans>
    Your actual application beans would then be defined in the specified "myContextBeans.xml" file.

    In a larger application, you could have multiple such shared contexts, using different ids. Different groups of EJBs could in turn talk to different shared ApplicationContexts. The specific context to be used can be identified through overriding SpringBeanAutowiringInterceptor's "getBeanFactoryLocatorKey" method.

    Juergen

    Comment


    • #3
      Originally posted by Juergen Hoeller View Post
      It seems that you're not defining nested ApplicationContexts there in your beanRefContext.xml file...

      Juergen
      Thanks for your reply. Actually, I tried to configure a beanRefContext.xml, however I'm not quite sure if I have done it right.

      My structure looks like this:

      Code:
      Archive:  app.jar
           META-INF/                
           META-INF/MANIFEST.MF     
           foo/            
           foo/dao/        
           foo/dao/AccountDao.class   
           foo/dao/AccountDaoMock.class   
           foo/dao/hibernate/   
           foo/dao/hibernate/AbstractTransactionalTestCase.class   
           foo/dao/hibernate/AccountDaoImpl.class   
           foo/dao/hibernate/AccountDaoImplTest.class   
           foo/dao/hibernate/AllTests.class   
           foo/domain/     
           foo/domain/Account.class   
           foo/service/    
           foo/service/AccountService.class   
           foo/service/AccountServiceImpl.class   
           foo/service/AccountServiceLocal.class   
           foo/service/AccountServiceTest.class   
           beanRefContext.xml       
           serviceContext.xml       
           META-INF/persistence.xml   
      
      Archive:  foo.ear
           META-INF/                
           META-INF/MANIFEST.MF     
           META-INF/application.xml   
           app.jar                  
           fooWeb.war              
           lib/                     
           lib/spring.jar           
           META-INF/jboss-app.xml
      My beanRefContext.xml

      Code:
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
      
          <bean id="ear.context" class="org.springframework.context.support.ClassPathXmlApplicationContext">
              <constructor-arg>
                  <list>
                      <value>serviceContext.xml</value>
                  </list>
              </constructor-arg>
          </bean>
      </beans>
      And then I've added following to my web.xml in fooWeb.war module:

      Code:
      ...
          <context-param>
              <param-name>parentContextKey</param-name>
              <param-value>ear.context</param-value>
          </context-param>
         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
      
      ...
      I'm not sure about the last step and it would be nice to have step by step example for integrating EJB3.0 into Spring. I've read the javadoc in org.springframework.beans.factory.access.Singleton BeanFactoryLocator. However, I'm more confused now as I was before ;-} More precisely, I'm not going to write "client code" like
      Code:
       BeanFactoryLocator bfl = SingletonBeanFactoryLocator.getInstance();
      ...
      Also, I had to put the spring library directly in foo.ear : lib/spring.jar. It seams that the SpringBeanAutowiringInterceptor called before the libs in fooWeb.war is actually loaded. Once more it looks like a classloading problem to me and I'm getting a bit frustrated about that.

      Thanks for your help.

      Kuno
      Last edited by qnob; Feb 1st, 2008, 01:34 AM.

      Comment


      • #4
        similar problem with glassfish/spring 2.5.1

        beanRefContext.xml:
        <beans>
        <bean id="myContext" class="org.springframework.context.support.ClassPa thXmlApplicationContext">
        <constructor-arg value="applicationContext.xml"/>
        </bean>
        </beans>

        applicationContext.xml:
        <beans>
        ...
        <context:annotation-config/>

        <bean id="beanName" class="java.lang.String">
        <constructor-arg value="Test Bean"/>
        </bean>
        </beans>


        bean class:
        Stateless(mappedName="ejb/TestBeanImpl")
        @Interceptors(SpringBeanAutowiringInterceptor.clas s)
        public class TestBeanImpl implements TestBean {
        @Autowired
        String beanName;

        ...
        }


        The error:
        Unable to return specified BeanFactory instance: factory key [null], from group with resource name [classpath*:beanRefContext.xml]; nested exception is org.springframework.beans.factory.NoSuchBeanDefini tionException: No unique bean of type [org.springframework.beans.factory.BeanFactory] is defined: expected single bean but found 0
        No unique bean of type [org.springframework.beans.factory.BeanFactory] is defined: expected single bean but found 0

        Comment


        • #5
          gave it up

          hello!

          sorry can't help. I gave it up after a couple of frustrating days. It seems that spring framework is developing to fast for my intellect or I'm drying to do things with this framework I shouldn't.
          I still stick on spring, though!

          I hope you'll succeed!

          Kuno

          Comment


          • #6
            I've gotten Spring 2.5.1 + EJB3 to work on both JBoss and Glassfish. Though, I've also at times run into issues similar to the above (see my thread on this).

            Like you, I also placed spring.jar into ${JBOSS_HOME}/server/default/lib.

            Here's my current (trivial) setup that works on JBoss 4.2.0.GA (minus the import statements).

            My bean interface:
            Code:
            package foo.ejb;
            
            public interface Service {
            
              public String getVersion();
            
            }
            My Bean implementation:
            Code:
            package foo.ejb;
            
            @Stateless(name = "service")
            public class ServiceBean implements Service {
            
              @Autowired
              private Delegate delegate;
            
              public String getVersion() {
                return delegate.getVersion();
              }
            
            }
            Delegate is a dependency of ServiceBean:
            Code:
            package foo.ejb;
            
            public class Delegate {
              public String getVersion() {
                return "1.0";
              }
            }
            My beanRefContext.xml:
            Code:
            <?xml version="1.0" encoding="UTF-8"?>
            <beans xmlns="http://www.springframework.org/schema/beans"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
            
              <bean class="org.springframework.context.support.ClassPathXmlApplicationContext">
                <constructor-arg type="java.lang.String" value="ejbApplicationContext.xml" />
              </bean>
              
            </beans>
            And my ejbApplicationContext.xml:
            Code:
            <?xml version="1.0" encoding="UTF-8"?>
            <beans xmlns="http://www.springframework.org/schema/beans"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
            
              <bean id="delegate" class="foo.ejb.Delegate" />
              
            </beans>
            And finally, to configure Spring to inject into my EJBs, I used Spring 2.5.1's SpringBeanAutowiringInterceptor. Here's my /META-INF/ejb-jar.xml:
            Code:
            <?xml version="1.0" encoding="UTF-8"?>
            <ejb-jar version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd">
              <interceptors>
                <interceptor>
                  <interceptor-class>org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor</interceptor-class>      
                </interceptor>    
              </interceptors>
              <assembly-descriptor>
                <interceptor-binding>
                  <ejb-name>*</ejb-name>
                  <interceptor-class>org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor</interceptor-class>
                </interceptor-binding>
              </assembly-descriptor>
            </ejb-jar>
            That all goes into foo-ejb.jar.

            Next the stuff that goes into foo-web.war, starting with my controller:
            Code:
            package foo.web;
            
            @Controller
            public class IndexController {
            
              /**
               * Or "service/remote" on JBoss. For Glassfish, remove the suffix.
               */
              @EJB(mappedName = "service/local")
              private Service service;
              
              @RequestMapping("/index.html")
              public void index(ModelMap model) {
                model.addAttribute("version", service.getVersion());
              }
            
            }
            The Freemarker template that comprises the view for the above:
            Code:
            <html>
            <body>
            <p>Version: ${version}</p>
            </body>
            </html>
            Now, an important point: I had problems on both Glassfish and JBoss getting the JNDI lookup correct because of prefixes and suffixes. The most relevant part of my foo-servlet.xml shows how I avoid the "java:comp/env" prefix:
            Code:
            <?xml version="1.0" encoding="UTF-8"?>
            <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-2.5.xsd
              http://www.springframework.org/schema/context
              http://www.springframework.org/schema/context/spring-context-2.5.xsd">
            
              <!--
                Use a custom JNDI bean factory configured not to prepend lookups with "java:comp/env"
              -->
              <bean id="jndiFactory"
                class="org.springframework.jndi.support.SimpleJndiBeanFactory">
                <property name="resourceRef" value="false" />
              </bean>
            
              <!--
                Configure the CommonAnnotationBeanPostProcessor to always use JNDI lookup (for EJBs)
                and use the custom JNDI bean factory above.
              -->
              <bean
                class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor">
                <property name="alwaysUseJndiLookup" value="true" />
                <property name="jndiFactory" ref="jndiFactory" />
              </bean>
            
              <!--
                Since we're turning off "annotation-config" in the context:component-scan below, we need
                to explicitly configure an AutowiredAnnotationBeanPostProcessor.
              -->
              <bean
                class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
            
              <!--
                Configure annotation-based component scanning, instantiation and dependency injection. 
              -->
              <context:component-scan base-package="com.talikos.ese.web.controllers" annotation-config="false" />
            
              <!--
                Rest of Spring MVC (view resolver, etc.) configuration goes here.
              -->
            
            </beans>
            Hope this (lengthy post) helps. I really should blog this.

            Comment


            • #7
              Thanks alistair for your great post. I've put Spring/EJB3 on ice for the moment - got transfered to another project...though, one day, I'll recall it

              Thanks again.

              K

              Comment

              Working...
              X