2 Replies Latest reply on May 16, 2012 7:25 AM by arnoldjohansson

    selectNode() of a ClusterNodeSelector isn't executed

    arnoldjohansson

      Hi Jaikiran and community!

       

      This is in continued reference to my late question in

      https://community.jboss.org/message/734538

      Problem

      The selectNode() method of an implemented ClusterNodeSelector isn't called despite its constructor being found and executed.

      Platform

      JBoss AS 7.1.2.Final

      Setup

      • An EAR (sample-jee.ear) deployed on two separate AS instances. This EAR contains clustered EJB:s (by anotation).
      • An EAR (sample-jee-client.ear) deployed on a separate AS instance. This EAR contains a Servlet that calls an EJB in the cluster.

      Reproduce problem

      To reproduce the behavior perform the following steps...

       

      1. Download the sample project from

      https://github.com/swesource/sample-jee

       

      2. Run 'mvn install' to build the project (from its root directory)

       

      3. Create a user 'admin' with password 'admin2'.

      For this example it's been created both for Management and Application realms.

       

      4. Copy the attached standalone-xml to JBOSS_HOME/standalone/configuration/

      It is a standard standalone-xml equiped with the needed server-klient--to--server communication setup.

       

      5. Start the following three AS 7.1.2.Final servers as instructed

       

      node1

      {code}$JBOSS_HOME/bin/standalone.sh -Djboss.socket.binding.port-offset=0 --server-config standalone-ha.xml -Djboss.node.name=node1{code}

       

      node2

      {code}$JBOSS_HOME/bin/standalone.sh -Djboss.socket.binding.port-offset=500 --server-config standalone-ha.xml -Djboss.node.name=node2{code}

       

      client1

      {code}$JBOSS_HOME/bin/standalone.sh -Djboss.socket.binding.port-offset=1000 --server-config standalone.xml -Djboss.node.name=client1{code}

       

      6. Deploy the EAR of the sample-jee-server-ear project (sample-jee/sample-jee-server-ear/target/sample-jee-server.ear) in node1 and node2

      This will create a set of clustered EJB:s

       

      7. Deploy the EAR of the sample-jee-client-project (sample-jee/sample-jee-client-ear/target/sample-jee-client.ear) in client1

       

      8. From a browser use the URL:

      http://localhost:9080/sample-jee-client/SlsbClientServlet

       

      9. Look at the console output of client1.

      I get an output saying that the constructor is executed...

       

      {code}***** RoundRobinClusterNodeSelector created{code}

       

      ...but no more messages are displayed from the selector as (successful) calls are being made.

       

      It should show lines starting with:

       

      {code}***** RoundRobinClusterNodeSelector::selectNode{code}

       

      Additional information

      All things work fine (clustering, communication, failover etc) except for the invocation of my implemented ClusterNodeSelector.selectNode()-method.

      But the strange thing is that the constructor of my ClusterNodeSelector is called but not the selectNode()-method!

      -So the class is (probably?) configured and instantiated correctly?


      The selector class is located in

       

      {code}sample-jee/sample-jee-client-util/src/main/java/com/swesource/sample/jee/jbossas7/clustering/RoundRobinClusterNodeSelector.java{code}

       

      and it is configured in

       

      {code}sample-jee/sample-jee-client-ear/src/main/application/META-INF/jboss-ejb-client.xml{code}

       

       

      Kind Regards

      /Arnold

        • 1. Re: selectNode() of a ClusterNodeSelector isn't executed
          jaikiran

          I had a look at your code and your web client servlet looks up the bean proxy on each invocation https://github.com/swesource/sample-jee/blob/master/sample-jee-client-web/src/main/java/com/swesource/sample/jee/web/SlsbClientServlet.java#L48 which means that any cluster topology information affinity for that proxy is lost during the next invocation. So I changed the servlet code to do the lookup only once in the init() of the servlet:

           

           

          @WebServlet(value = "/SlsbClientServlet")
          public class SlsbClientServlet extends HttpServlet {
              
              private ServerSlsbRemote beanProxy;
              
              @Override
              public void init() throws javax.servlet.ServletException {
                  try {
                      final Hashtable props = new Hashtable();
                      // setup the ejb: namespace URL factory
                      props.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
                      // create the InitialContext
                      final Context context = new javax.naming.InitialContext(props);
          
                      // Lookup the SlsbOne bean using the ejb: namespace syntax which is explained here
                      // https://docs.jboss.org/author/display/AS71/EJB+invocations+from+a+remote+client+using+JNDI
                      
                      // For remote ejbs (other container)
                      String path = "ejb:sample-jee-server/sample-jee-server-ejb-1.0-SNAPSHOT//ServerSlsbBean!com.swesource.sample.jee.ServerSlsbRemote";
                      this.beanProxy = (ServerSlsbRemote) context.lookup(path);
          
                  } catch (Exception e) {
                      throw new RuntimeException(e);
                  }
              }
              
              protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                  invokeOnBean();
              }
          
              protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                  String greeting = invokeOnBean();
                  PrintWriter pw = response.getWriter();
                  pw.write("SlsbClientServlet -> ServerSlsbBean.sayHello (in remote EAR) -> SlsbClientServlet -> [" + greeting + "]\n");
                  //String callResponse = invokeOnRelayBean();
                  //pw.write("SlsbClientServlet -> SlsbRelayBean.called (in remote EAR) -> SlsbOneBean.sayHello (in remote EAR) -> SlsbClientServlet -> [" + callResponse + "]\n");
                  pw.flush();
                  pw.close();
              }
          
              private String invokeOnBean() {
                  try {
                      // invoke on the bean
                      final String greeting = this.beanProxy.sayHello();
                      System.out.println("SlsbClientServlet: Received greeting: " + greeting);
                      return greeting;
          
                  } catch (Exception e) {
                      throw new RuntimeException(e);
                  }
              }
          

           

          That'll allow the proxy to hold on to the cluster weak affinity associated with the bean and that should let the EJB client API know that it has to allow the cluster node selector to select a node from the cluster.

          • 2. Re: selectNode() of a ClusterNodeSelector isn't executed
            arnoldjohansson

            Brilliant! Now I (finally) understand better how affinity is tied in.

            The solution has been verified. I will update my sample project on github asap.

            Many thanks!