2 Replies Latest reply on Jun 4, 2009 2:25 AM by pawel.wyrwinski

    HA-JNDI lookup of SLSB depending on HASingletonDeployer Barr

    pawel.wyrwinski

      Hello.
      My app is EAR running on JBoss 4.2.2 containing:
      - Stateless Session Bean
      - JSF-based web-app

      SLSB is able to create/start/stop ejb.Timer, and has method annotated with @Timeout as well.
      Web-app is makes JNDI lookup to acquire bean's stub and perform it's start() and stop() methods.

      Now, my goal is to move this EAR to cluster and assure that only one instance of "timed" SLSB is active.
      So I've established two-node cluster on single machine using ServiceBindingManager in jboss-service.xml and replaced HSQL with PostgreSQL.
      I'm pretty sure my cluster partition is working properly.
      Then I modified my app by adding @Clusterd and @Depends("jboss.ha:service=HASingletonDeployer,type=Barrier") annotations on ejb and switching from local JDNI to HA-JNDI lookup in my web-app, which now looks like this:

      ...
      import pw.test.interfaces.ITimer;
      public class TestTimerManagedBean {
      
       private ITimer timer;
      
       private void lookup() {
       Properties jndiProperties = new Properties();
       jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
       jndiProperties.put(Context.URL_PKG_PREFIXES, "jboss.naming:org.jnp.interfaces");
       jndiProperties.setProperty("jnp.partitionName", "pw_partition"); // partition's name
      
       Context context;
       try {
       context = new InitialContext(jndiProperties);
       this.timer = (ITimer)context.lookup("testEar/TestTimerBean/remote");
       } catch (NamingException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
       }
       }
      
       public void start() {
       this.lookup();
      
       if (this.timer != null) {
       this.timer.start();
       }
       }
      
       public void stop() {
       this.lookup();
      
       if (this.timer != null) {
       this.timer.stop();
       }
       }
      }
      


      Problem description.
      ====================

      Use case:
      1. start cluster.
      Partition consists of:
      - node1 (ports: web=8180, JNDI=1199, HA-JNDI=1200) <-- master node
      - node2 (ports: web=8280, JNDI=1299, HA-JNDI=1300)

      2. place ear in /all/farm of node1.
      Node1 deploys and starts SLSB, Node2 deploys SLSB but doesn't start it.
      As far as I can tell, it's correct behaviour (effect of using @Depends annotation). Here is what JNDIView shows on node1 (there are no such entries on node2's JNDIView, it's ok i suppose):

      +- testEar (class: org.jnp.interfaces.NamingContext)
       | +- TestTimerBean (class: org.jnp.interfaces.NamingContext)
       | | +- local (proxy: $Proxy84 implements interface pw.test.interfaces.ITestTimerLocal,interface org.jboss.ejb3.JBossProxy,interface javax.ejb.EJBLocalObject)
       | | +- remote (proxy: $Proxy83 implements interface pw.test.interfaces.ITestTimerRemote,interface org.jboss.ejb3.JBossProxy,interface javax.ejb.EJBObject)
      


      3. In web-browser i go to web-app on node1: http://localhost:8180/TestTimerWeb, and successfully lookup SLSB and start/stop timer on node1. When i kill node1, SLSB instance on node2 is started and continues tasks (failover).
      4. In web-browser i go to web-app on node2: http://localhost:8280/TestTimerWeb, and here my problem is. Some SLSB is looked-up, but when i try to invoke some methods on it, i get exception:
      2009-05-29 13:24:26,778 ERROR [javax.enterprise.resource.webcontainer.jsf.application] java.lang.NullPointerException
      javax.faces.el.EvaluationException: java.lang.NullPointerException
       at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:102)
       at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
       at javax.faces.component.UICommand.broadcast(UICommand.java:387)
       at org.ajax4jsf.component.AjaxViewRoot.processEvents(AjaxViewRoot.java:321)
       at org.ajax4jsf.component.AjaxViewRoot.broadcastEvents(AjaxViewRoot.java:296)
       at org.ajax4jsf.component.AjaxViewRoot.processPhase(AjaxViewRoot.java:253)
       at org.ajax4jsf.component.AjaxViewRoot.processApplication(AjaxViewRoot.java:466)
       at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:82)
       at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100)
       at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
       at javax.faces.webapp.FacesServlet.service(FacesServlet.java:265)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
       at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
       at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
       at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:173)
       at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:182)
       at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
       at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
       at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)
       at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157)
       at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
       at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:241)
       at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
       at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
       at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
       at java.lang.Thread.run(Thread.java:619)
      Caused by: java.lang.NullPointerException
       at org.jboss.ejb3.stateless.StatelessInstanceInterceptor.invoke(StatelessInstanceInterceptor.java:62)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       at org.jboss.aspects.remoting.ReplicantsManagerInterceptor.invoke(ReplicantsManagerInterceptor.java:51)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       at org.jboss.aspects.security.AuthenticationInterceptor.invoke(AuthenticationInterceptor.java:77)
       at org.jboss.ejb3.security.Ejb3AuthenticationInterceptor.invoke(Ejb3AuthenticationInterceptor.java:108)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       at org.jboss.ejb3.ENCPropagationInterceptor.invoke(ENCPropagationInterceptor.java:46)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       at org.jboss.ejb3.asynchronous.AsynchronousInterceptor.invoke(AsynchronousInterceptor.java:106)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       at org.jboss.ejb3.stateless.StatelessContainer.dynamicInvoke(StatelessContainer.java:280)
       at org.jboss.ejb3.remoting.IsLocalInterceptor.invokeLocal(IsLocalInterceptor.java:81)
       at org.jboss.ejb3.remoting.ClusteredIsLocalInterceptor.invoke(ClusteredIsLocalInterceptor.java:53)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       at org.jboss.ejb3.stateless.StatelessClusteredProxy.invoke(StatelessClusteredProxy.java:113)
       at $Proxy83.start(Unknown Source)
       at pw.test.TestTimerManagedBean.start(TestTimerManagedBean.java:40)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:597)
       at org.apache.el.parser.AstValue.invoke(AstValue.java:131)
       at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:276)
       at com.sun.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:68)
       at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:88)
       ... 28 more
      


      For some reason, HA-JNDI lookup performed by web-app on node2 is optimized to local JNDI lookup even when SLSB on this node is not started.

      The only solution i've found is to edit /all/deploy/ejb3-interceptors-aop.xml and get rid of interceptors: IsLocalInterceptor and ClusteredIsLocalInterceptor.
      This soulution is too intrusive, and i'm affraid there can be some negative consequences in future.

      My question: is it possible to bypass this behaviour? I'd like to achieve this scenario:
      1. There is only one active(started) SLSB that manages my ejb.timer in entire cluster. Let's say it would be node1 in partition.
      2. Web-app controlling SLSB is present on all nodes, and regardles from which node i'll run it, it will always find started SLSB on master node.