How to pass extra parameters when EJB client invokes EJB in JBoss EAP 6

Solution Verified - Updated

Environment

  • JBoss Enterprise Application Platform (EAP)
    • 6.0

Issue

  • We need to be able to pass few extra parameters when invoking EJBs (local and remote). These parameters can not be a part of method signature. We tried ejbContext, TransactionSynchronizationRegistry and those do not work. We also tried https://issues.jboss.org/browse/AS7-5021 but it does not work in JBoss EAP 6.0.0

Resolution

Update to JBoss EAP 6.0.1 or later.

Create an EJBClientInterceptor that adds custom data to the context data, see the example below. Note the EJB 3.1 specification does not define client side EJB interceptors which is why the client interceptor is implementing the JBoss class EJBClientInterceptor.

import org.jboss.ejb.client.EJBClientInterceptor;
import org.jboss.ejb.client.EJBClientInvocationContext;

public class HelloClientInterceptor implements EJBClientInterceptor
{
    @Override
    public void handleInvocation(EJBClientInvocationContext context)throws Exception {
        context.getContextData().put("test_data", "it_works");
        // Must make this call
        context.sendRequest();
    }
    @Override
    public Object handleInvocationResult(EJBClientInvocationContext context)
            throws Exception {
        // Must make this call
        return context.getResult();
    }
}

Create a EJB Server Interceptor that pulls the data out, see the example below. Note this is an EJB 3.1 interceptor as which is defined in the EJB specification.

import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
import javax.annotation.Resource;
import javax.ejb.SessionContext;
import java.security.Principal;

public class HelloServerInterceptor
{
   @Resource
   private SessionContext context;

  @AroundInvoke
  public Object log(InvocationContext invocationContext) throws Exception {
    String test_data = (String) invocationContext.getContextData().get("test_data");
    System.out.println("test_data:" + test_data);
    return invocationContext.proceed();
  }
}

Add the client interceptor in your client when setting up the EJB call, for example:

import java.util.Hashtable;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.Context;
import javax.naming.NamingException;

import javax.security.auth.login.LoginContext;
import javax.security.auth.callback.CallbackHandler;
import org.jboss.security.auth.callback.SecurityAssociationHandler;
import org.jboss.security.SimplePrincipal;
import org.jboss.ejb.client.EJBClientConfiguration;
import org.jboss.ejb.client.ContextSelector;
import org.jboss.ejb.client.PropertiesBasedEJBClientConfiguration;
import org.jboss.ejb.client.EJBClientContext;
import org.jboss.ejb.client.remoting.ConfigBasedEJBClientContextSelector;

// This is setting up the connection properties to call the remote ejb 
Properties p = new Properties();
p.put("remote.connections", "default");
p.put("remote.connection.default.host", "localhost");
p.put("remote.connection.default.port", "4447");
p.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false");
p.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS", "false");
// The following setting is required when deferring to JAAS
p.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT", "false");
p.put("remote.connection.default.username", "admin");
p.put("remote.connection.default.password", "redhat");

EJBClientConfiguration cc = new PropertiesBasedEJBClientConfiguration(p);
ContextSelector<EJBClientContext> selector = new ConfigBasedEJBClientContextSelector(cc);
EJBClientContext.setSelector(selector);

// registering the client interceptor (JBoss specific since the EJB 3.1 spec does not cover client side interceptors)
EJBClientContext.getCurrent().registerInterceptor(0, new HelloClientInterceptor());

// Create the initial context to look up the ejb
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
Context ctx = new InitialContext(env);

// look up and invoke the ejb
Hello ejbObject = (Hello) ctx.lookup("ejb:/example-ejb//Hello!jboss.example.ejb.Hello");
System.out.println(ejbObject.sayHello());

Note the JBoss private private attachments are stored under the key: org.jboss.ejb.client.EJBClientInvocationContext.PRIVATE_ATTACHMENTS_KEY key

Content from issues.jboss.org is not included.[1] Client EJB Interceptor context data serialized into privateData map on server side https://issues.jboss.org/browse/AS7-5021

Components
Category

This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.