JBoss EAP / Wildfly – Three ways to invoke remote EJBs

The JBoss EAP / Wildfly application server provides as primary API the EJB client library to invoke remote EJB components. This client library is the implementation of the WildFly application server to invoke EJB components. The lookup of an object, such as a JMS connection factory, from the naming service is with the EJB client library not possible. For this purpose the remote naming implementation can be used. It can handle lookups of objects from the naming service. Both libraries can be used through the InitialContext of the JNDI API.

This post introduces three ways to configure the InitialContext to lookup and invoke EJB components, describes the pro and cons of each approach and introduces a combination of both libraries.

Portable JNDI names

Before we start, we give a brief introduction of the portable JNDI names. Since Java EE 6 the JNDI name syntax of an EJB component has the following structure:

[/<application-name>]/<module-name>/<bean-name>[!<full-qualified-interface-name>]

By default, the application name is the filename of the enterprise archive. Therefore, it is recommended to configure the application name in the application.xml deployment descriptor of the enterprise archive, as shown below.

<application xmlns="http://xmlns.jcp.org/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee  http://xmlns.jcp.org/xml/ns/javaee/application_7.xsd"
        version="7">
    <application-name>myapp</application-name>
    ...
</application>

It is also recommended to configure the module name of the ejb module. Otherwise, the module name is by default the filename of the ejb archive. The module name can be configured with the ejb-jar.xml deployment descriptor.

<ejb-jar xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/ejb-jar_3_2.xsd"
    version="3.2">
    <module-name>remote</module-name>
</ejb-jar>

An EJB component will be registered, according to the spec, within the namespaces java:global, java:app, and java:module. In the log file of the Wildfly application server you will find the following log message with the JNDI names for each deployed EJB component:

java:global/myapp/remote/calculator!de.akquinet.jbosscc.ejb.Calculator
java:app/myapp/remote/calculator!de.akquinet.jbosscc.ejb.Calculator
java:module/myapp/calculator!de.akquinet.jbosscc.ejb.Calculator
java:jboss/exported/app/remote/calculator!de.akquinet.jbosscc.ejb.Calculator
java:global/myapp/remote/calculator
java:app/myapp/remote/calculator
java:module/myapp/calculator

The scope of the standardized java:global, java:app, and java:module namespaces are restricted to the container and the application client container (acc). Therefore, all components that are accessible outside the container via the naming service will be registered in addition within the JBoss-specific namespace java:jboss/exported/. Only components that are registered within the java:jboss/exported/ namespace are remote accessible via the naming service.

The last three JNDI Names from the above shown log message are short forms. This JNDI names are available, if the EJB component only exposes one applicable interface.

1. EJB client library

The EJB client library is the primary library to invoke remote EJB components. This library can be used through the InitialContext. To invoke EJB components the library creates an EJB client context via a URL context factory. The only necessary configuration is to parse the value org.jboss.ejb.client.naming for the java.naming.factory.url.pkgs property to instantiate an InitialContext.

Properties prop = new Properties();
prop.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
Context context = new InitialContext(prop);

With this environment property the IntitalContext knows the URL context factory implementation of the EJB client library to handle the JBoss-specific ejb: namespace.
All the other configurations needs to be configured in a property file named jboss-ejb-client.properties. This file must be added to the classpath. Below is a simple example:

remote.connections=default
remote.connection.default.host=127.0.0.1
remote.connection.default.port=8080
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT=false
remote.connection.default.connect.options.org.xnio.Options.SASL_DISALLOWED_MECHANISMS=${host.auth:JBOSS-LOCAL-USER}
 
remote.connection.default.username=${username}
remote.connection.default.password=${password}

With these configurations EJB components can be lookuped, as shown below.

context.lookup("ejb:/myapp/remote/calculator!de.akquinet.jbosscc.ejb.Calculator");

The benefit is, that the created EJB client context needs no server connection for the lookup. Via the ejb: namespace of the JNDI name the library knows that the component is a stateless session bean and creates a proxy on the client side without any server connection to avoid network round-trips and serialization overhead. The first server connection occurs when a business method of the EJB component is invoked.

This optimization can be applied for stateless session beans. For stateful session bean the library needs to initiate a session on the server side. A lookup of a stateful session bean requires that the JNDI name have the extension ?stateful

In addition to the optimized lookup the EJB client library supports load blancing and failover. These features are described in this post.

2. Remote Naming Project

The remote naming project implements a factory class that will create an initial context. The following code shows the necessary environment properties to setup the initial context instance.

Properties prop = new Properties();
 
prop.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
prop.put(Context.PROVIDER_URL, "http-remoting://127.0.0.1:8080");
prop.put(Context.SECURITY_PRINCIPAL, "username");
prop.put(Context.SECURITY_CREDENTIALS, "password");
         
prop.put("jboss.naming.client.ejb.context", true);
 
Context context = new InitialContext(prop);

The environment property jboss.naming.client.ejb.context indicates that the InitialContext implementation of the remote naming project will also create an internal EJB client context via the EJB client library. This allows the invocation of EJB components with the remote naming project.

context.lookup("/app/remote/calculator!de.akquinet.jbosscc.ejb.Calculator");

Unlike to EJB client library the remote naming project has no idea that the object is a EJB proxy and needs to lookup the EJB proxy on the server-side in the namesapce java:jboss/exported/.

The benefit of this approch is that the same InitialContext can handle the lookup of EJB proxies and other objects from the naming service.

The disadvantages of this approach are, that the remote naming implementation can not create an EJB proxy on the client-side and fine-grained configuration of the EJB client context is not supported. This includes configuration for load balacing and session failover. Therefore, this approach is not recommended for EJB invocations.

3. Combination of Remote Naming Project and EJB client library

To get the benefits of both approaches it is possible to combine the EJB client library and the remote naming implementation without any restrictions. This approach requires that the environment property jboss.naming.client.ejb.context is set to false. Than, the remote naming project creates no internal EJB client context.

To invoke remote EJB components, this approch requires in additon to add the URL package prefix org.jboss.ejb.client.naming. With this environment property, the InitialContext creates the necessary EJB client context to handle the ejb: namespace via the URL context factory implementation of the EJB client library. The EJB client context can now be configured separately with the jboss-ejb-client.properties file.

Properties prop = new Properties();
 
prop.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
 
prop.put(Context.PROVIDER_URL, "http-remoting://127.0.0.1:8080");
prop.put(Context.SECURITY_PRINCIPAL, "username");
prop.put(Context.SECURITY_CREDENTIALS, "password");
         
prop.put("jboss.naming.client.ejb.context", false);
prop.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
 
Context context = new InitialContext(prop);

The only disadvantage is that this approach requires a configuration of the EJB client context and the remote naming project. The benefit is that only one InitialContext are required to invoke EJB components with all optimizations and configuration capabilities of the EJB client library, and the possibility to lookup other objects with the same InitialContext.

A complete example with each approach can be found on github, in the ejb-remote-example directory.

Feel free to contact us for any questions or feedback.
heinz.wilming (at) akquinet.de


Comments

8 responses to “JBoss EAP / Wildfly – Three ways to invoke remote EJBs”

  1. Richard Oates

    is it possible to specify the ejb-jar.xml entry remote as an annotation on the bean itself?

  2. Shouldn’t this be “ejb:myapp/…” instead of “ejb:/myapp/…” ?

  3. how to create this EJB Client as a bundle for deployed at jboss fuse (karaf)? i already try 2 way, first way, make jboss-client.jar (API) as a OSGi bundle and the second way is embed jboss-client.jar on my OSGi bundle application. Either failed!

  4. Thank you for this interesting article.

    Do you know if the http-remoting using port 8080 (3rd method) is available under EAP 6.3 ?

    After a quick test on EAP 6.3, I get the error : No connection provider for URI scheme “http-remoting” is installed

    It seems this method is only for WildFly 8 Alpha 3 according to the release notes.

  5. Reblogged this on java web development and commented:
    JBoss EAP / Wildfly – Three ways to invoke remote EJBs

  6. Thats an excellent article. Just one addition to “1. EJB client library”. For this to work you should have WILDFLY_HOME/bin/client/jboss-client.jar on your classpath.

    1. Steve Cohen

      do you mean jboss-ejb-client.jar?

  7. I notice that your examples always use the local host IP (127.0.0.1) . Will the examples you have also work to invoke an EJB on another server also running jboss? We are currently using JBOSS 5 and we have beans that invoke EJBs on different servers based on the content of the data received.

Discover more from akquinet - Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading

WordPress Cookie Notice by Real Cookie Banner