11 Replies Latest reply on Mar 12, 2008 12:34 PM by alesj

    Accessing app_1's spring beans in app_2's config file

    mr_belowski2

      Hi folks,

      I've got a 'server' application which has a set of beans defined in its config xml. I've got a client webapp which uses these (they're injected in Tapestry pages). The structure looks a bit like this:

      server_app.spring
      ->someClasses
      ->META-INF
      ->jboss-spring.xml

      client_app.ear
      ->webapp.war
      ->WEB-INF
      ->applicationContext.xml

      jboss-spring.xml defines some beans, and I'm trying to access these in the webapp.

      jboss-spring.xml contains
      BeanFactory=(server_app)
      then the bean definitions

      webapp's applicationContext.xml contains
      BeanFactory=(webapp) ParentBeanFactory=(server_app)
      the some webapp specific bean definitions.

      Some of the webapp bean definitions reference beans defined in the server app - e.g.





      I name the apps so the server one gets deployed first. When the client app is deployed it can't create this someWebAppBean, saying "No bean named 'someServerBean' is defined. So the deployment fails.


      Is there a configuration step I'm missing? Have I done something silly?

        • 1. Re: Accessing app_1's spring beans in app_2's config file
          mr_belowski2

          Oops, I'll try the code stuff again...

          server_app.spring
          ->someClasses
          ->META-INF
          - ->jboss-spring.xml

          client_app.ear
          ->webapp.war
          ->WEB-INF
          - ->applicationContext.xml

          jboss-spring.xml defines some beans, and I'm trying to access these in the webapp.

          jboss-spring.xml contains

          <description>BeanFactory=(server_app)</description>

          then the beans

          webapp's applicationContext.xml contains
          <description>BeanFactory=(webapp) ParentBeanFactory=(server_app)</description>

          the some webapp specific bean definitions.

          Some of the webapp bean definitions reference beans defined in the server app - e.g.
          <bean id="someWebAppBean" class="..." >
          <property name="someServerBean"><ref bean="someServerBean"/></property>




          ...

          • 2. Re: Accessing app_1's spring beans in app_2's config file
            alesj

            Only BeanFactories that are constructed by SpringDeployer can reference beans from parent BeanFactories.
            In your case parent BF is constructed by SpringDeployer, but your child BF is constructed by regular Spring ContextLoader.
            And only SpringDeployer knows about parent=(<some_parent>) notion.

            You can use something like this:

            public abstract class AbstractJndiContextLoader extends ContextLoader {
            
             protected String getJndiName(ServletContext servletContext) {
             String jndiName = DEFAULT_ROOT_APP_CONTEXT_JNDI_NAME;
             if (servletContext.getInitParameter(ROOT_JNDI_APP_CONTEXT_KEY) != null) {
             jndiName = servletContext.getInitParameter(ROOT_JNDI_APP_CONTEXT_KEY);
             }
             return jndiName;
             }
            
             protected Context createContext() throws BeansException {
             try {
             return new InitialContext();
             } catch (Exception e) {
             throw new ApplicationContextException("Cannot create naming context!", e);
             }
             }
            
            }
            
            public abstract class JndiContextSaver extends AbstractJndiContextLoader {
            
             @Override
             protected WebApplicationContext createWebApplicationContext(ServletContext servletContext, ApplicationContext parent) throws BeansException {
             try {
             WebApplicationContext wac = super.createWebApplicationContext(servletContext, parent);
             bindApplicationContext(getJndiName(servletContext), wac);
             return wac;
             } catch (Exception e) {
             throw new ApplicationContextException("Cannot bind application context.", e);
             }
             }
            
             protected abstract void bindApplicationContext(String jndiName, ApplicationContext applicationContext) throws Exception;
            
             @Override
             public void closeWebApplicationContext(ServletContext servletContext) {
             unbindApplicationContext(getJndiName(servletContext));
             super.closeWebApplicationContext(servletContext);
             }
            
             protected abstract void unbindApplicationContext(String jndiName);
            
            }
            
            public class JBossJndiContextSaver extends JndiContextSaver {
            
             protected void bindApplicationContext(String jndiName, ApplicationContext applicationContext) throws Exception {
             NonSerializableFactory.bind(createContext(), jndiName, applicationContext);
             }
            
             protected void unbindApplicationContext(String jndiName) {
             try {
             NonSerializableFactory.unbind(createContext(), jndiName);
             } catch (NamingException e) {
             LogFactory.getLog(getClass()).warn("Exception unbinding application context.", e);
             }
             }
            
            }
            
            public class JndiContextSaverListener extends InitializerContextLoaderListener {
            
             @Override
             protected ContextLoader createContextLoader() {
             return new JBossJndiContextSaver();
             }
            
            }
            
             <listener>
             <listener-class>com.alesj.acme.webcommon.context.JndiContextSaverListener</listener-class>
             </listener>
            
            


            HTH,
            Ales

            • 3. Re: Accessing app_1's spring beans in app_2's config file
              mr_belowski2

              Ahhhhhh, now it makes sense. I guess i was trying something a little silly :)

              Thanks for the info and the code - it's really helped to clarify things

              • 4. Re: Accessing app_1's spring beans in app_2's config file
                gumnaam

                Where can I find the class InitializerContextLoaderListener ?

                I tried to follow the above code, but I couldn't find InitializerContextLoaderListener anywhere, so I assumed that you were refering to ContextLoaderListener , and substituting InitializerContextLoaderListener with ContextLoaderListener made the code compile, but it doesn't run.

                The problem is as per the code for JndiContextSaver, the WebApplicationContext is created by calling super method. And here if the web context's applicationContext.xml has any bean definitions, that refer to a parent bean defi. (in bean factory in the ejb context), then they don't get deployed.

                I get bean ref. error, and as a result the WebApplication context creation throws an error.


                If the WebApplicationContext is created by a super call, how will the spring deployer make it aware of the parent application context in the ejb container.

                • 5. Re: Accessing app_1's spring beans in app_2's config file
                  alesj

                  The missing code:

                  public class InitializerContextLoaderListener extends ContextLoaderListener {
                  
                   @Override
                   public void contextInitialized(ServletContextEvent event) {
                   JndiRootApplicationContextLookup.initialize(event.getServletContext());
                   super.contextInitialized(event);
                   }
                  
                  }
                  
                  public class JndiRootApplicationContextLookup {
                  
                   private static final Log log = LogFactory.getLog(JndiRootApplicationContextLookup.class);
                   public static final String ROOT_JNDI_APP_CONTEXT_KEY = "RootJndiApplicationContextKey";
                   public static final String DEFAULT_ROOT_APP_CONTEXT_JNDI_NAME = "RootJndiApplicationContextName";
                  
                   private static String JNDI_NAME;
                  
                   public static String jndiName() {
                   return JNDI_NAME;
                   }
                  
                   public static void initialize(ServletContext servletContext) {
                   String jndiName = DEFAULT_ROOT_APP_CONTEXT_JNDI_NAME;
                   if (servletContext.getInitParameter(ROOT_JNDI_APP_CONTEXT_KEY) != null) {
                   jndiName = servletContext.getInitParameter(ROOT_JNDI_APP_CONTEXT_KEY);
                   }
                   if (JNDI_NAME != null && !JNDI_NAME.equals(jndiName)) {
                   log.warn("Jndi name already initialized with different name: " + JNDI_NAME + " / " + jndiName);
                   }
                   JNDI_NAME = jndiName;
                   }
                  
                   public static Object lookup(String beanName) throws Exception {
                   JndiTemplate jndiTemplate = new JndiTemplate();
                   ApplicationContext ac = (ApplicationContext) jndiTemplate.lookup(JNDI_NAME, ApplicationContext.class);
                   return ac.getBean(beanName);
                   }
                  
                  }
                  


                  Try it now, and let me know.

                  • 6. Re: Accessing app_1's spring beans in app_2's config file
                    gumnaam

                    The RootJndiApplicationContextName, should that be the context name of the bean Factory in the ejb Context (i.e. parent) or the web Context (i.e. child ) ?

                    • 7. Re: Accessing app_1's spring beans in app_2's config file
                      gumnaam

                      Still the same error. btw, I set the DEFAULT_ROOT_APP_CONTEXT_JNDI_NAME to the parent cotext name. ( I hope that the right thing to do), in both JndiRootApplicationContextLookup and AbstractJndiContextLoader .

                      Who calls the static lookup method of JndiRootApplicationContextLookup class ? I think the initialize method of JndiRootApplicationContextLookup is missing something. from what I can see, it only sets the value of JNDI_NAME variable . Should it not call the lookup after that ?

                      • 8. Re: Accessing app_1's spring beans in app_2's config file
                        alesj

                        The idea there is such:
                        You declare a root context, which is deployed by JBoss SpringDeployer.
                        Then you might have a child context also deployed by SpringDeployer.
                        But you also want to have a web context that is also a child of that root context.
                        e.g. having some common beans declared in the root

                        So, by that RootJndiApplicationContextName should be the name of the root context.

                        But it's been a while since I did this, so don't pull my leg if I got it wrong. :-)

                        • 9. Re: Accessing app_1's spring beans in app_2's config file
                          gumnaam

                          OK so I am on the correct path, I have decared the root context correctly, but I still can't get access to the beans defined in the root context.

                          As I said in my previous email, the "initialize" method of JndiRootApplicationContextLookup , should probably call the lookup method or something. As it is right now, it's doing nothing but initializing a string. and no one is calling the lookup method.

                          • 10. Re: Accessing app_1's spring beans in app_2's config file
                            gumnaam

                            OK here's an alternate approach that worked for me.

                            Simply extend the ContextLoader and override the loadParentContext method.
                            In the load parentContext method, look up the root context from JNDI and retrun it.

                            No need to have any more classes, no need to add description elements to any spring xml file.

                            • 11. Re: Accessing app_1's spring beans in app_2's config file
                              alesj

                               

                              "gumnaam" wrote:

                              No need to have any more classes, no need to add description elements to any spring xml file.

                              I know I had reasons why I hacked all those classes, just can't remember them now.
                              I'll try an dig that code up ... it's been a while like I said ... :-)