EJB client with scoped-context problem with transaction in JBoss EAP 6

Solution Verified - Updated -

Issue

  • There is a problem if a EJB client with scoped-context is used inside EAP6. I have a setup consisting of two application servers (A and B) where a EJB at serverA invokes a remote EJB (stateless) at serverB. Both servers are configured to use JTS and the transaction contexts are propagated from A to B during the remote EJB method invocation. The EJB at A creates the scoped EJB client context and closes it as soon as it has made completed the remote method invocation at B. This closing of the scoped EJB client context is done inside the transaction scope which causes a transaction failure :
INFO [MyBean] (http-/0.0.0.0:8080-1) Creating contexts
INFO  [org.jboss.ejb.client.remoting] (Remoting "test" task-1) EJBCLIENT000017: Received server version 2 and marshalling strategies [river]
INFO  [org.jboss.ejb.client.remoting] (http-/0.0.0.0:8080-1) EJBCLIENT000013: Successful version handshake completed for receiver context EJBReceiverContext{clientContext=org.jboss.ejb.client.EJBClientContext@23fd686, receiver=Remoting connection EJB receiver [connection=org.jboss.ejb.client.remoting.ConnectionPool$PooledConnection@499ed933,channel=jboss.ejb,nodename=node2]} on channel Channel ID d4b2fa6d (outbound) of Remoting connection 3ea82444 to linux.example/192.168.1.101:14947
INFO  [MyBean] (http-/0.0.0.0:8080-1) Closing contexts
WARN  [com.arjuna.ats.jtax] (RequestProcessor-5) ARJUNA024004: Caught the following error while trying to single phase complete resource: java.lang.IllegalStateException: EJBCLIENT000027: No EJBReceiver available for node name node2
    at org.jboss.ejb.client.EJBClientContext.requireNodeEJBReceiver(EJBClientContext.java:824)
    at org.jboss.ejb.client.EJBClientContext.requireNodeEJBReceiverContext(EJBClientContext.java:865)
    at org.jboss.ejb.client.EJBClientManagedTransactionContext$mit(EJBClientManagedTransactionContext.java:237)
    at mit_one_phase(XAResourceRecord.java:739) [jbossjts-jacorb-4.17.7.Final-redhat-4.jar:4.17.7.Final-redhat-4]
    at com.arjuna.ArjunaOTS.OTSAbstractRecordPOA._invoke(OTSAbstractRecordPOA.java:61) [jbossjts-jacorb-4.17.7.Final-redhat-4.jar:4.17.7.Final-redhat-4]
    at org.jacorb.poa.RequestProcessor.invokeOperation(RequestProcessor.java:306) [jacorb-2.3.2-redhat-4.jar:2.3.2-redhat-4]
    at org.jacorb.poa.RequestProcessor.process(RequestProcessor.java:626) [jacorb-2.3.2-redhat-4.jar:2.3.2-redhat-4]
    at org.jacorb.poa.RequestProcessor.run(RequestProcessor.java:769) [jacorb-2.3.2-redhat-4.jar:2.3.2-redhat-4]

The code of the StatelessBean invoking the EJB at serverB:

@Stateless
public class MyBean {
    private static final Logger logger = LoggerFactory.getLogger(MyBean.class);
    private static final String JNDI_PATH = "test2/ejb/RemoteBean!com.redhat.examples.Remote";

    private Context ejbRootNamingContext = null;
    private Context ctx = null;

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void test() {
        logger.debug("Test invoked");

        try {
            createContext();
            Remote bean = (Remote) ejbRootNamingContext.lookup(JNDI_PATH);
            SampleResult result = bean.generate(10);
            logger.debug("Result : {}", result);
        } catch (NamingException e) {
            throw new RuntimeException(JNDI_PATH, e);
        } finally {
            destroyContext();
        }
    }

    protected void createContext() {
        logger.info("Creating contexts");
        try {
            ctx = new InitialContext(generateJNDIProperties());
            ejbRootNamingContext = (Context) ctx.lookup("ejb:");
        } catch (NamingException e) {
            throw new RmiCommunicationException(generateJNDIProperties(), e);
        }
    }

    protected void destroyContext() {
        logger.info("Closing contexts");
        if (ejbRootNamingContext != null) {
            try {
                ejbRootNamingContext.close();
                ejbRootNamingContext = null;
            } catch (NamingException e) {
                logger.error("Could not close jndi context", e);
            }
        }
        if (ctx != null) {
            try {
                ctx.close();
                ctx = null;
            } catch (NamingException e) {
                logger.error("Could not close jndi context", e);
            }
        }
    }

    protected Properties generateJNDIProperties() {
        final Properties ejbClientContextProps = new Properties();
        ejbClientContextProps.put("org.jboss.ejb.client.scoped.context", true);
        ejbClientContextProps.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");

        final String connectionName = "mytest";
        ejbClientContextProps.put("remote.connections", connectionName);
        ejbClientContextProps.put("remote.connection." + connectionName + ".host", "myhost");
        ejbClientContextProps.put("remote.connection." + connectionName + ".port", "4447");
        // add some more properties
        return ejbClientContextProps;
    }
}

In case of change the transaction attribute of MyBean to Not_supported instead of Requires_new everything works.
If I don’t close ejbRootNamingContext, I will soon get into a situation where there are too many open channels and I will get an error.

Environment

  • Red Hat JBoss Enterprise Application Platform (EAP)
    • 6.1.x and further

Subscriber exclusive content

A Red Hat subscription provides unlimited access to our knowledgebase of over 48,000 articles and solutions.

Current Customers and Partners

Log in for full access

Log In
Close

Welcome! Check out the Getting Started with Red Hat page for quick tours and guides for common tasks.