Announcement Announcement Module
Collapse
No announcement yet.
Using Bean Factory on 2nd attempt causes errors Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Using Bean Factory on 2nd attempt causes errors

    I have updated my project, which uses Spring to inject the managers and DAO, to get EJB3 working with the Springframework. Since introducing the EJBs i have been having some problems. My problems occur when calling the beanfactory more then once.

    org.springframework.beans.factory.BeanDefinitionSt oreException: Unexpected exception parsing XML document from class path resource [spring-config.xml]; nested exception is java.lang.IllegalArgumentException: Class [org.springframework.beans.factory.xml.SimpleProper tyNamespaceHandler] does not implement the NamespaceHandler interface

    When i called the bean factory initially to get the EJB (EJB3). There are no problems, everything works fine. But upon using the Bean factory again in order to get the manager beans used by the EJB layer the above error is thrown.

    The EJB is in a separate jar file, the web content is in a war file and the core of the code sits inside a 3rd jar file. All of which is within a EAR file.

    The bean factory code is

    beanFactory = new ClassPathXmlApplicationContext(new String[]{"spring-config.xml"}, false);

    Thanks in advance

  • #2
    Looks like you are loading your application context multiple times (hard to tell though from the limited example). You should try to bootstrap the application context using a ServletContextListener (or some other mechanism) so that the application context is only loaded once and held onto. Then you can just request your bean from the application context that is already loaded.

    Comment


    • #3
      Hi Caleb,
      The code

      beanFactory = new ClassPathXmlApplicationContext(new String[]{"spring-config.xml"}, false);

      is being used twice first time to get the service object with the EJB and then again inside the EJB to access the Manager bean. This is where it fails on the 2nd attempt. So i do believe that the ApplicationContext is being loaded twice

      With regards to using the using the ServletContextListener, could you give an example of how i would possibly use this.

      Thanks

      Comment


      • #4
        To bootstrap at the Web tier.

        Add the following to the web.xml

        Code:
        <context-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>/WEB-INF/spring-config.xml</param-value>
        </context-param>
        
        <listener>
         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
        Then to get access to the WebApplicationContext use the following.

        Code:
        ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(request.getSession().getServletContext())
        This will retrieve the bootstrapped application context from an Application scoped variable.

        To bootstrap the EJB container you can have your EJB Bean Class extend from Springs AbstractStatelessSessionBean. Then add an EJB Environment Variable with the name of "ejb/BeanFactoryPath" and value of "location of your application context file".

        Code:
        <env-entry>
          <env-entry-name>ejb/BeanFactoryPath</env-entry-name>
          <env-entry-type>java.lang.String</env-entry-type>
          <env-entry-value>classpath:applicationContext.xml</env-entry-value>
        </env-entry>
        Then in your EJB you can use the getBeanFactory() method to get the bootstrapped application context from the EJB container.

        Note: now that I re-read your problem this might be because your classpath is not the same for both the Web container and EJB container. Need to verify that you have all the jar files added to Java jar dependecies of both the Web and EJB components.

        Comment


        • #5
          Thanks for the example.

          I am currently using EJB3 so dont have an ejb-jar fille. How would i specify the env entry for the bean factory in my EJB bean class

          <env-entry>
          <env-entry-name>ejb/BeanFactoryPath</env-entry-name>
          <env-entry-type>java.lang.String</env-entry-type>
          <env-entry-value>classpath:applicationContext.xml</env-entry-value>
          </env-entry>

          Comment


          • #6
            Looks like in order to have env-entry values you still need an ejb-jar.xml file. Here's a doc that talks about Spring and EJB 3.0

            http://www.oracle.com/technology/tec...ring.html#slsb

            Comment


            • #7
              Thanks for that example.

              There is a new error now

              java.lang.NullPointerException
              at org.springframework.ejb.support.AbstractEnterprise Bean.getBeanFactory(AbstractEnterpriseBean.java:15 4)


              Unfortuantly it doesnt give to much info about what is missing

              My code is as follows

              In my myapp.jar(which resides in a ear file)

              ejb-jar.xml

              <session>
              <ejb-name>ExpensesEJBBean</ejb-name>
              <env-entry>
              <env-entry-name>ejb/BeanFactoryPath</env-entry-name>
              <env-entry-type>java.lang.String</env-entry-type>
              <env-entry-value>/applicationContext.xml</env-entry-value>
              </env-entry>
              </session>


              ExpensesEJBBean class file

              @Stateless(name = "ExpensesEJBBean", mappedName = "ExpensesEJBBean")
              public class ExpensesEJBBean extends AbstractStatelessSessionBean implements ExpensesEJBLocal, ExpensesEJB {

              protected void onEjbCreate() throws CreateException {
              System.out.println("READY");
              expensesManager = (ExpensesManager) getBeanFactory().getBean("expensesManager");
              }

              public List getAllRecords(String month) throws EJBException {
              System.out.println("getAllRecords");
              Object o = super.getBeanFactory().getBean("expensesManager");
              return expensesManager.getAllRecords();
              }
              }


              applicationContext.xml

              <bean id="expensesService" class="uk.co.aztekSolutions.expensesApp.services.c ore.expenses.ExpensesServiceImpl">
              <property name="expensesEJB" ref="expensesEJB"/>
              </bean>

              <bean id="expensesEJB" class="org.springframework.jndi.JndiObjectFactoryB ean">
              <property name="jndiEnvironment">
              <props>
              <prop key="java.naming.factory.initial">org.jnp.interfac es.NamingContextFactory</prop>
              <prop key="java.naming.factory.url.pkgs">org.jboss.namin g:org.jnp.interfaces</prop>
              <prop key="java.naming.provider.url">jnp://localhost:1099</prop>
              </props>
              </property>
              <property name="jndiName" value="AztekApplication/ExpensesEJBBean/local"/>
              <property name="resourceRef">
              <value>true</value>
              </property>
              </bean>

              <bean id="expensesManager" class="uk.co.aztekSolutions.server.domain.expenses .ExpensesManagerImpl">
              </bean>

              <bean id="bankManager" class="uk.co.aztekSolutions.server.domain.bank.Ban kManagerImpl">
              </bean>


              The code appears to be failing on

              Object o = super.getBeanFactory().getBean("expensesManager");

              Comment


              • #8
                Looks like the result of getBeanFactory() is null. This usually happens when the file you specify cannot be found.

                Where do you have your applicationContext.xml file placed? If you have it in the root of the classpath. Try...

                Code:
                         <env-entry-value>classpath:applicationContext.xml</env-entry-value>
                Try turning on DEBUG level messages (with Log4j or your logging implementation) to have more insight into what is going on.

                Comment


                • #9
                  The applicationContext.xml recides in the root of the ejb jar file. But the same nullpointer exception is still occuring. I have switched on the logging but nothing useful is being displayed. Not sure if it cant see the env entry in the ejb-jar.xml file.

                  Is it possible to enter this value programmatically.

                  For example i have seen the method setBeanFactoryLocatorKey(). I have tried entering "ejb/BeanFactoryPath" and /applicationContext.xml with no luck

                  would appreciate any further assitance you could provde. woah 2.06am time for bed i think. Given enough time to this problem today.

                  Comment


                  • #10
                    In the constructor of your bean you can do the following.

                    Code:
                    setBeanFactoryLocator(SingletonBeanFactoryLocator.getInstance("classpath:applicationContext.xml"));
                    This will override the default behavior of looking for the applicationContext file locations in the ejb environment variable entry.

                    Comment


                    • #11
                      Thanks for your help. I am at the stage of giving up. Dont seem to be making much progress. I have tried different combinations but the same null pointer exception is being thrown.

                      Using the classloader (looking at the javadoc getInstance() uses this to look for the xml file) i have looked at what resources it is able to see and it does find the xml file.

                      "jar:file:/C:/Program Files/jboss-4.0.5.GA/server/default/tmp/deploy/tmp32554AztekApplication.ear!/applicationContext.xml"

                      I even passed this into the constructor of

                      setBeanFactoryLocator(SingletonBeanFactoryLocator. getInstance(loader.getResource("applicationContext .xml").toString()));

                      If you have any other ideas please let me know as i am out of them right now. The only work around is to pass the manager in via the service layer. Something which i would like to avoid as it couples the business code into the service layer rather then into the EJB layer

                      Comment


                      • #12
                        Originally posted by akhtara7 View Post
                        "jar:file:/C:/Program Files/jboss-4.0.5.GA/server/default/tmp/deploy/tmp32554AztekApplication.ear!/applicationContext.xml"
                        Looks like the file you are pointing at is in the root of your deployed EAR. This would not be on the classpath by default. Try placing this in the root of a jar file (your ejb jar file). As this should get the xml file on the classpath of your session bean so that you can load an application context from this .xml file.

                        I don't believe the syntax you have above is valid for Spring as it expects a valid URL when loading resources. You can always start simple by dropping this file in the root of your c: drive - "file:/C:/applicationContext.xml" to see if you can get that working and then work towards a file that is included with your EAR/Jar(s).

                        Comment


                        • #13
                          The xml file was initially under the ejb jar file but resulted in the same error. So i moved it into the ear file to see if that helped.

                          I have already tried moving the file to my c:\ to see if i can get it working that way but the same error is still being thrown.

                          Below is the class and full error trace.

                          java.lang.NullPointerException
                          at org.springframework.ejb.support.AbstractEnterprise Bean.getBeanFactory(AbstractEnterpriseBean.java:15 4)
                          at uk.co.aztekSolutions.server.ejb.expenses.ExpensesE JBBean.init(ExpensesEJBBean.java:47)
                          at uk.co.aztekSolutions.server.ejb.expenses.ExpensesE JBBean.getExpensesManager(ExpensesEJBBean.java:78)
                          at uk.co.aztekSolutions.server.ejb.expenses.ExpensesE JBBean.getAllRecords(ExpensesEJBBean.java:93)
                          at sun.reflect.NativeMethodAccessorImpl.invoke0(Nativ e Method)
                          at sun.reflect.NativeMethodAccessorImpl.invoke(Native MethodAccessorImpl.java:39)
                          at sun.reflect.DelegatingMethodAccessorImpl.invoke(De legatingMethodAccessorImpl.java:25)
                          at java.lang.reflect.Method.invoke(Method.java:585)
                          at org.jboss.aop.joinpoint.MethodInvocation.invokeNex t(MethodInvocation.java:112)
                          at org.jboss.ejb3.interceptor.InvocationContextImpl.p roceed(InvocationContextImpl.java:166)
                          at org.jboss.ejb3.interceptor.EJB3InterceptorsInterce ptor.invoke(EJB3InterceptorsInterceptor.java:63)
                          at org.jboss.aop.joinpoint.MethodInvocation.invokeNex t(MethodInvocation.java:101)
                          at org.jboss.ejb3.entity.TransactionScopedEntityManag erInterceptor.invoke(TransactionScopedEntityManage rInterceptor.java:54)
                          at org.jboss.aop.joinpoint.MethodInvocation.invokeNex t(MethodInvocation.java:101)
                          at org.jboss.ejb3.AllowedOperationsInterceptor.invoke (AllowedOperationsInterceptor.java:46)
                          at org.jboss.aop.joinpoint.MethodInvocation.invokeNex t(MethodInvocation.java:101)
                          at org.jboss.aspects.tx.TxPolicy.invokeInOurTx(TxPoli cy.java:79)
                          at org.jboss.aspects.tx.TxInterceptor$Required.invoke (TxInterceptor.java:191)
                          at org.jboss.aop.joinpoint.MethodInvocation.invokeNex t(MethodInvocation.java:101)
                          at org.jboss.aspects.tx.TxPropagationInterceptor.invo ke(TxPropagationInterceptor.java:76)
                          at org.jboss.aop.joinpoint.MethodInvocation.invokeNex t(MethodInvocation.java:101)
                          at org.jboss.ejb3.stateless.StatelessInstanceIntercep tor.invoke(StatelessInstanceInterceptor.java:62)
                          at org.jboss.aop.joinpoint.MethodInvocation.invokeNex t(MethodInvocation.java:101)
                          at org.jboss.aspects.security.AuthenticationIntercept or.invoke(AuthenticationInterceptor.java:77)
                          at org.jboss.ejb3.security.Ejb3AuthenticationIntercep tor.invoke(Ejb3AuthenticationInterceptor.java:102)
                          at org.jboss.aop.joinpoint.MethodInvocation.invokeNex t(MethodInvocation.java:101)
                          at org.jboss.ejb3.ENCPropagationInterceptor.invoke(EN CPropagationInterceptor.java:47)
                          at org.jboss.aop.joinpoint.MethodInvocation.invokeNex t(MethodInvocation.java:101)
                          at org.jboss.ejb3.asynchronous.AsynchronousIntercepto r.invoke(AsynchronousInterceptor.java:106)
                          at org.jboss.aop.joinpoint.MethodInvocation.invokeNex t(MethodInvocation.java:101)
                          at org.jboss.ejb3.stateless.StatelessContainer.localI nvoke(StatelessContainer.java:211)
                          at org.jboss.ejb3.stateless.StatelessLocalProxy.invok e(StatelessLocalProxy.java:79)
                          at $Proxy87.getAllRecords(Unknown Source)


                          The EJBBean

                          public class ExpensesEJBBean extends AbstractStatelessSessionBean implements ExpensesEJBLocal, ExpensesEJB {
                          private ExpensesManager expensesManager = null;
                          private Object manualExpensesManager = null;

                          public ExpensesEJBBean() {
                          super();
                          init();
                          }


                          private void init() {
                          try {
                          BeanFactory factory = null;
                          System.out.println("####SETTING LOCATOR");
                          setBeanFactoryLocator(SingletonBeanFactoryLocator. getInstance("file:/C:/applicationContext.xml"));

                          factory = getBeanFactory();

                          System.out.println("FACTORY IS = " + factory);
                          expensesManager = (ExpensesManager) factory.getBean("expensesManager");
                          } catch (Exception e) {
                          System.out.println("Spring Expenses Manager load ERROR - " + e.getMessage());
                          e.printStackTrace();
                          } finally {
                          System.out.println("OBJECT IS = " + expensesManager);
                          }
                          }

                          protected void onEjbCreate() throws CreateException {
                          }

                          public ExpensesManager getExpensesManager() throws DomainLayerException {
                          if (expensesManager == null) {
                          init();
                          }

                          if (expensesManager == null)
                          System.out.println("expensesManager NULL");
                          else
                          System.out.println("expensesManager VALID");
                          return expensesManager;
                          }

                          public List getAllRecords(String month) throws EJBException {
                          System.out.println("getAllRecords");
                          try {
                          System.out.println("expensesManager= " + expensesManager);

                          return getExpensesManager().getAllRecords(month).getList( );
                          } catch (DomainLayerException e) {
                          e.printStackTrace();
                          throw new EJBException(e);
                          }
                          }
                          }


                          Not sure if the error is being caused because it cant find the xml file or if i have missed something else out.

                          Comment


                          • #14
                            I see the problem. You need to move your call to the init() method that you have created to the onEjbCreate() method. The problem is Spring does not create the application Context until after the ejb create method runs. Therefore, calling it in the constructor is why you are getting a null pointer exception.

                            Code:
                            public class ExpensesEJBBean extends AbstractStatelessSessionBean implements ExpensesEJBLocal, ExpensesEJB {
                                private ExpensesManager expensesManager = null;
                                private Object manualExpensesManager = null;
                            
                                public ExpensesEJBBean() {
                                    super();
                            //remove call to init()
                                }
                            
                            
                                private void init() {
                                    try {
                                        BeanFactory factory = null;
                                        System.out.println("####SETTING LOCATOR");
                                        setBeanFactoryLocator(SingletonBeanFactoryLocator.  getInstance("file:/C:/applicationContext.xml"));
                                        
                                        factory = getBeanFactory();
                            
                                        System.out.println("FACTORY IS = " + factory);
                                        expensesManager = (ExpensesManager) factory.getBean("expensesManager");
                                    } catch (Exception e) {
                                        System.out.println("Spring Expenses Manager load ERROR - " + e.getMessage());
                                         e.printStackTrace();
                                    } finally {
                                        System.out.println("OBJECT IS = " + expensesManager);
                                    }
                                }
                            
                                protected void onEjbCreate() throws CreateException {
                            init();
                                }
                            
                                public ExpensesManager getExpensesManager() throws DomainLayerException {
                            //don't need all the checks for the expenseManager == null
                            return expensesManager;
                                }
                            
                                public List getAllRecords(String month) throws EJBException {
                                    System.out.println("getAllRecords");
                                    try {
                                        System.out.println("expensesManager= " + expensesManager);
                            
                                        return getExpensesManager().getAllRecords(month).getList(  );
                                    } catch (DomainLayerException e) {
                                        e.printStackTrace();
                                        throw new EJBException(e);
                                    }
                                }
                            }
                            That should get you past the null pointer exception that you are seeing.

                            Comment


                            • #15
                              Just given that a try i moved the init call into onEjbCreate, got a nullpointer exception but this time on

                              return getExpensesManager().getAllRecords(month).getList( );

                              The object returned by getExpensesManager() is null, this should have been set by the call to init.

                              I put some debug statements into create method but nothing is getting displayed. Thinking back to the whole EJB lifecyle the onEJBCreate call is done after the container calls ejbCreate. So i dont think this call is being made

                              I am starting to think whether the container is interpreting the bean as an EJB (oh just remebered on the jboss startup does actually say the bean has been deployed).

                              Coud be a Spring thing???

                              The EJB is being called via service object using

                              org.springframework.jndi.JndiObjectFactoryBean

                              From what i have read of the docs this should return an EJB Bean

                              Comment

                              Working...
                              X