2
votes

Here's an example of what I need to accomplish. There is a remote EJB interface with a dummy method. The interface is implemented by two stateful EJBs, and the first one needs to perform a lookup of the second:

@Stateful
@Remote(BeanI.class)
public class Bean1 implements BeanI {
  @Override
  public void doSomething() {
    try {
      System.out.println("Bean1");
      JndiManager.lookup(Bean2.class).doSomething();
    } catch (Exception ex) { ... }
  }
}

@Stateful
@Remote(BeanI.class)
public class Bean2 implements BeanI {
  @Override
  public void doSomething() {
    System.out.println("Bean2");
  }
}

The helper class JndiManager is as follows:

public class JndiManager {
  private static Hashtable<String, Object> jndiProps;
  static {
    jndiProps = new Hashtable<>();
    jndiProps.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
  }

  public static BeanI lookup(Class<?> cls) throws NamingException {
    final String name = "ejb:/TestServer//" + cls.getSimpleName() + "!" + 
      BeanI.class.getName() + "?stateful";
    Context ctx = new InitialContext(jndiProps);
    return (BeanI) ctx.lookup(name);
  }
}

The client application performs a lookup of Bean1 and invokes its method. Here's the jboss-ejb-client.properties file:

remote.clusters=ejb
remote.cluster.ejb.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.cluster.ejb.connect.options.org.xnio.Options.SSL_ENABLED=false
remote.cluster.ejb.username=someuser
remote.cluster.ejb.password=somepass1~

endpoint.name=client-endpoint
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
remote.connections=default
remote.connection.default.host=localhost
remote.connection.default.port=8080
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.connection.default.username=someuser
remote.connection.default.password=somepass1~

Bean1 is invoked successfully, but its lookup of Bean2 fails. The error is:

java.lang.IllegalStateException: EJBCLIENT000029: No cluster context available for cluster named ejb
line -> JndiManager.lookup(Bean2.class).doSomething();

It works fine in standalone mode, but fails in domain mode (running a single, master node). Also, everything works great in JBoss EAP 6.1.

Any help would be appreciated.

1

1 Answers

1
votes

This seems to be a bug in WildFly.

WildFly expects the Local EJB client to be initialized for clustering, see org.jboss.ejb.client.EJBClientContext, line 989

But the initialization doesn't happen due to missing dependency to service EJBRemoteConnectorService, see org.jboss.as.ejb3.remote.LocalEjbReceiver, line 449.

The dependency to EJBRemoteConnectorService is defined as optional in org.jboss.as.ejb3.subsystem.EJB3SubsystemAdd, lines 416 and 426. The problem is that EJBRemoteConnectorService gets always initialized after the LocalEjbReceiver service and is therefore always null in the LocalEjbReceiver. This causes the cluster initialization to be skipped.

The issue can be patched by changing DependencyType.OPTIONAL to DependencyType.REQUIRED on lines 416 and 426 in org.jboss.as.ejb3.subsystem.EJB3SubsystemAdd.

You can download a patched file (for WildFly 8.0.Final) and overwrite the existing file in wildfly/modules/system/layers/base/org/jboss/as/ejb3/main/wildfly-ejb3-8.0.0.Final.jar. Applying this patch will solve your issue.