How configure an EJB client in EAP 7.1+ / 8.0+
Environment
- Red Hat JBoss Enterprise Application Platform (EAP)
- 8
- 7.1+
Issue
- How to configure remote EJB client in EAP 8.0 + ?
- How to do server-to-server EJB in EAP 7.4+?
- How to do server-to-server EJB in EAP 7.3+?
- How to do server-to-server EJB in EAP 7.2+?
- How configure an EJB client in EAP 7.2
- How configure an EJB client in EAP 7.1
Resolution
Table of contents
- Client application configuration
- Client application code
- JBoss Profile standalone/domain configuration
- Elytron Example Configuration (EAP 8 / EAP 7.1+)
- This content is not included.Picketbox Example Configuration (EAP 7 / EAP 6) (deprecated)
Note
If the EJB is in the same JVM as the Client that is calling it, then the Client should follow the JavaEE spec and defined Portable JNDI Naming Syntax such as java:global/, java:app/, java:module as described in What are the allowed JNDI name formats for EJBs in EAP 7 / 6 according to EE6+
For example:
public void callEjbRemoteInterfaceInVM() {
HelloRemote ejbRemote = new InitialContext().lookup("java:global/helloWorld/helloWorld-ejb/HelloWorldSLSB!org.jboss.examples.ejb.HelloRemote");
ejbRemote.helloWorld();
}
public void callEjbLocalInterfaceInVM() {
HelloRemote ejbLocal = new InitialContext().lookup("java:global/helloWorld/helloWorld-ejb/HelloWorldSLSB!org.jboss.examples.ejb.HelloLocal");
ejbLocal.helloWorld();
}
If the Client is not in the same JVM as the EJB, then the 'ejb:' / ejb-client methods below would be used or the EJB over IIOP spec method as described in: How to expose an EJB via IIOP and call it in JBoss EAP 7 / 6
Using the WildFlyInitialContextFactory
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import org.jboss.ejb.client.EJBClient;
public void callRemoteEjb() {
HelloRemote remote = getInitialContext(host, port, user, pass).lookup("ejb:helloWorld/helloWorld-ejb/HelloWorldSLSB!org.jboss.examples.ejb.HelloRemote");
remote.helloWorld();
}
public static Context getInitialContext(String host, Integer port, String username, String password)
throws NamingException {
Hashtable<String, Object> env = new Hashtable<>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.wildfly.naming.client.WildFlyInitialContextFactory");
env.put(Context.PROVIDER_URL, String.format("remote+http://%s:%d", host, port));
if (username != null && password != null) {
env.put(Context.SECURITY_PRINCIPAL, username);
env.put(Context.SECURITY_CREDENTIALS, password);
}
return new InitialContext(env);
}
Lookup Failover
In order to manage Lookup High Availability, you can provide a list of remote servers that will be checked for the Initial Lookup of the remote+http call. Here is the updated getInitialContext() method, supposing you were to contact two servers located at localhost:8080 and localhost:8180:
public static Context getInitialContext(String host, Integer port, String username, String password)
throws NamingException {
Hashtable<String, Object> env = new Hashtable<>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.wildfly.naming.client.WildFlyInitialContextFactory");
env.put(Context.PROVIDER_URL, String.format("remote+http://%s:%d", host, port));
if (username != null && password != null) {
env.put(Context.SECURITY_PRINCIPAL, username);
env.put(Context.SECURITY_CREDENTIALS, password);
}
return new InitialContext(env);
}
Using the wildfly-config.xml and WildFlyInitialContextFactory (standalone client only)
The wildfly-config.xml can be used to specify a static configuration for a standalone client to use. Below is a simple example specifying plaintext username / password and the remote server connection (host/port). The wildfly-config.xml goes in the META-INF directory.
<configuration>
<authentication-client xmlns="urn:elytron:1.0.1">
<authentication-rules>
<rule use-configuration="default"/>
</authentication-rules>
<authentication-configurations>
<configuration name="default">
<set-user-name name="ejbuser"/>
<credentials>
<clear-password password="redhat1!"/>
</credentials>
</configuration>
</authentication-configurations>
</authentication-client>
<jboss-ejb-client xmlns="urn:jboss:wildfly-client-ejb:3.0">
<connections>
<connection uri="remote+http://127.0.0.1:8080" />
</connections>
</jboss-ejb-client>
</configuration>
Using the wildfly-config.xml, the InitialContext creation does not specify the host/port/user/pass since it is already defined in the wildfly-config.xml. The EJB lookup
public static Context getInitialContext(String host, Integer port, String username, String password) throws NamingException {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.wildfly.naming.client.WildFlyInitialContextFactory");
return new InitialContext(env);
}
public void callRemoteEjb() {
HelloRemote remote = getInitialContext(host, port, user, pass).lookup("ejb:helloWorld/helloWorld-ejb/HelloWorldSLSB!org.jboss.examples.ejb.HelloRemote");
remote.helloWorld();
}
Configuring server to server in the JBoss profile
All of the following pieces are required to correctly configure EJB clients from within the JBoss container.
Client application code
// create the InitialContext
final Context context = new javax.naming.InitialContext();
final Greeter bean = (Greeter) context.lookup("ejb:myapp/myejb/GreeterBean!" + org.myapp.ejb.Greeter.class.getName());
JBoss Profile configuration: This is configuration that goes in your standalone.xml or domain.xml.
Elytron Example Configuration (EAP 8 / EAP 7.1+)
Client application configuration
jboss-ejb-client.xmlgoes in theWEB-INFif the top level deployment is a war or in the top level deployment'sMETA-INFif not a war
<jboss-ejb-client xmlns:xsi="urn:jboss:ejb-client:1.4" xsi:noNamespaceSchemaLocation="jboss-ejb-client_1_4.xsd">
<client-context>
<profile name="remote-ejb-profile" />
</client-context>
</jboss-ejb-client>
EJB-client-server configuration
- Add an Elytron Authentication Configuration for the credentials to connect to the remote EAP instance
Standalone Mode
/subsystem=elytron/authentication-configuration=ejbauth:add(authentication-name=server, security-domain=ApplicationDomain, forwarding-mode=authorization, realm=ApplicationRealm, credential-reference={clear-text=redhat1!})
Domain Mode (host-master used in this example)
/profile=default/subsystem=elytron/authentication-configuration=ejbauth:add(authentication-name=server, security-domain=ApplicationDomain, forwarding-mode=authorization, realm=ApplicationRealm, credential-reference={clear-text=redhat1!})
- Add an Elytron Authentication Context
Standalone Mode
/subsystem=elytron/authentication-context=ejbauthctx:add(match-rules=[{match-no-user=true,authentication-configuration=ejbauth}])
Domain Mode (host-master used in this example)
/profile=default/subsystem=elytron/authentication-context=ejbauthctx:add(match-rules=[{match-no-user=true,authentication-configuration=ejbauth}])
The resulting xml added looks like:
<subsystem xmlns="urn:wildfly:elytron:13.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
<authentication-client>
<authentication-configuration name="ejbauth" authentication-name="server" realm="ApplicationRealm" security-domain="ApplicationDomain" forwarding-mode="authorization">
<credential-reference clear-text="redhat1!"/>
</authentication-configuration>
<authentication-context name="ejbauthctx">
<match-rule match-no-user="true" authentication-configuration="ejbauth"/>
</authentication-context>
</authentication-client>
- Create an outbound-socket-binding on the "Client Server"
Standalone Mode
/socket-binding-group=standard-sockets/remote-destination-outbound-socket-binding=remote-socket-ejb:add(host=localhost, port=8080)
Domain Mode
/socket-binding-group=standard-sockets/remote-destination-outbound-socket-binding=remote-socket-ejb:add(host=server, port=8080)
The xml added looks like:
<socket-binding-group name="standard-sockets"
default-interface="public"
port-offset="${jboss.socket.binding.port-offset:0}">
...
<outbound-socket-binding name="remote-socket-ejb">
<remote-destination host="localhost" port="8080"/>
</outbound-socket-binding>
</socket-binding-group>
- Create the remoting profile with the connections
Standalone Mode
/subsystem=ejb3/remoting-profile=remote-ejb-profile:add()
/subsystem=ejb3/remoting-profile=remote-ejb-profile/remote-http-connection=server1:add(uri=remote+https://localhost:8080)
Domain Mode (default profile used in this example, see in server-groups the exact profile to modify):
/subsystem=ejb3/remoting-profile=remote-ejb-profile:add()
/profile=default/subsystem=ejb3/remoting-profile=remote-ejb-profile/remote-http-connection=server1:add(uri=remote+https://localhost:8080)
The xml added looks like:
<subsystem xmlns="urn:jboss:domain:ejb3:9.0">
...
<remote cluster="ejb" connectors="http-remoting-connector" thread-pool-name="default">
<channel-creation-options>
<option name="MAX_OUTBOUND_MESSAGES" value="1234" type="remoting"/>
</channel-creation-options>
<profiles>
<profile name="remote-ejb-profile">
<remote-http-connection name="server1" uri="remote+https://localhost:8080"/>
</profile>
</profiles>
</remote>
...
</subsystem>
EJB-server configuration
Add an application user:
Standalone Mode
./add-user.sh -a -u ejbuser -p redhat1!
Domain Mode
./add-user.sh -a -u ejbuser -p redhat1!
Picketbox Example Configuration (EAP 7 / EAP 6) (deprecated)
Client application configuration
jboss-ejb-client.xmlgoes in theWEB-INFif the top level deployment is a war or in the top level deployment'sMETA-INFif not a war
<jboss-ejb-client xmlns="urn:jboss:ejb-client:1.4">
<client-context>
<ejb-receivers>
<remoting-ejb-receiver outbound-connection-ref="remote-ejb-connection"/>
</ejb-receivers>
</client-context>
</jboss-ejb-client>
- Create a security realm on the client server (when adding the EJB user on EJB server side EAP with
./add-user.sh -a -u ejbuser -p redhat1! -dswe can get a base64 encoded passwordcmVkaGF0MSE=, use this same password value for the secret value inside<server-identities>section)
Standalone Mode
/core-service=management/security-realm=ejb-security-realm:add()
/core-service=management/security-realm=ejb-security-realm/server-identity=secret:add(value="cmVkaGF0MSE=")
Domain Mode (host-master used in this example)
/host=master/core-service=management/security-realm=ejb-security-realm:add()
/host=master/core-service=management/security-realm=ejb-security-realm/server-identity=secret:add(value="cmVkaGF0MSE=")
The xml added looks like:
<management>
<security-realms>
...
<security-realm name="ejb-security-realm">
<server-identities>
<secret value="cmVkaGF0MSE="/>
</server-identities>
</security-realm>
...
</security-realms>
...
</management>
2.Create an outbound-socket-binding on the "Client Server"
Standalone Mode
/socket-binding-group=standard-sockets/remote-destination-outbound-socket-binding=remote-socket-ejb:add(host=localhost, port=8080)
Domain Mode
/socket-binding-group=standard-sockets/remote-destination-outbound-socket-binding=remote-socket-ejb:add(host=server, port=8080)
The xml added looks like:
<socket-binding-group name="standard-sockets"
default-interface="public"
port-offset="${jboss.socket.binding.port-offset:0}">
...
<outbound-socket-binding name="remote-socket-ejb">
<remote-destination host="localhost" port="8080"/>
</outbound-socket-binding>
</socket-binding-group>
3.Create a "remote-outbound-connection" which uses this newly created "outbound-socket-binding"
Standalone Mode
/subsystem=remoting/remote-outbound-connection=remote-ejb-connection:add(outbound-socket-binding-ref=remote-socket-ejb,security-realm=ejb-security-realm,username=ejb)
/subsystem=remoting/remote-outbound-connection=remote-ejb-connection/property=SASL_POLICY_NOANONYMOUS:add(value=false)
/subsystem=remoting/remote-outbound-connection=remote-ejb-connection/property=SSL_ENABLED:add(value=false)
Domain Mode (default profile used in this example, see in server-groups the exact profile to modify):
/profile=default/subsystem=remoting/remote-outbound-connection=remote-ejb-connection:add(outbound-socket-binding-ref=remote-socket-ejb,security-realm=ejb-security-realm,username=ejbuser)
/profile=default/subsystem=remoting/remote-outbound-connection=remote-ejb-connection/property=SASL_POLICY_NOANONYMOUS:add(value=false)
/profile=default/subsystem=remoting/remote-outbound-connection=remote-ejb-connection/property=SSL_ENABLED:add(value=false)
/profile=default/subsystem=remoting/remote-outbound-connection=remote-ejb-connection/property=org.jboss.remoting3.RemotingOptions.HEARTBEAT_INTERVAL:add(value=50000)
/profile=default/subsystem=remoting/remote-outbound-connection=remote-ejb-connection/property=KEEP_ALIVE:add(value=true)
/profile=default/subsystem=remoting/remote-outbound-connection=remote-ejb-connection/property=READ_TIMEOUT:add(value=60000)
The xml added looks like:
<subsystem xmlns="urn:jboss:domain:remoting:1.1">
....
<outbound-connections>
<remote-outbound-connection name="remote-ejb-connection"
outbound-socket-binding-ref="remote-socket-ejb"
security-realm="ejb-security-realm"
username="ejbuser">
<properties>
<property name="SASL_POLICY_NOANONYMOUS" value="false"/>
<property name="SSL_ENABLED" value="false"/>
<property name="org.jboss.remoting3.RemotingOptions.HEARTBEAT_INTERVAL" value="50000"/>
<property name="KEEP_ALIVE" value="true"/>
<property name="READ_TIMEOUT" value="60000"/>
</properties>
</remote-outbound-connection>
</outbound-connections>
</subsystem>
Notes
Clustering
If the remote EAP instances are clustered, once an EJB client connects to one of these clustered instances, the client will receive a cluster view for the cluster and will then connect to those nodes for load balancing and failover. It is recommended to list two nodes in the InitialContext or remote-outbound-connections for HA in the event the first clustered node is down, it will try the second node and then the full cluster view will be received.
If the host specified is in a cluster, it will have affinity to that cluster. If the same EJB is deployed on two different clusters, and the provider url contains a host in cluster1 and host in cluster2, it will connect to host1 / cluster1 and have cluster1 affinity, unless host1 is unavailable and then it will failover to host2 / cluster2 and have affinity to cluster2. To load balance across more than one cluster, see: EJB Load Balancing across multiple clusters in JBoss EAP 7.1
FAQ
- JBoss EAP 8 server Interoperability with JBoss EAP 7 and JBoss EAP 6 servers
- How to connect to JBoss EAP 7 using JBoss EAP 6 EJB / JMS / JNDI client
- How to convert a jboss-ejb-client.properties to wildfly-config in JBoss EAP 7.1 for a standalone ejb client application
- How to use the legacy EJB client with EAP 7.1 if applications from EAP 6 or 7 are migrated
- How to change my standalone client's remote ejb configuration to not reference org.jboss.ejb.client in JBoss EAP 7.1
- How to configure server to server EJB security propagation in EAP 7.1
- How to enable EJB IIOP in JBoss EAP 7 / 6
- How to expose an EJB via IIOP and call it in JBoss EAP 7 / 6
- How to set EJB client side invocation timeout in JBoss EAP 7.1
- How to get Remote EJB UserTransaction in JBoss EAP 7.1
- How to configure EJB Client side Interceptors in EAP 7.1
- How to get the an EJB client's IP / Address when it invokes an EJB in EAP 7.1
- How to configure EJB standalone client application security in EAP 7.1
- How to configure XNIO/Remoting options for an EJB client in EAP 7.1
- Invoking EJBs / JNDI / JMS over HTTP in JBoss EAP 7.2+ with or without a Load Balancer
- How to configure EJB Client Address in JBoss EAP 7.1
- How to control an EJB Transaction from the Client in EAP 7.1
- How to enable and view ejb invocation & pool statistics in JBoss EAP 7 / 6
- How to test host / port / user / pass for remote JNDI authenticates and is correct in JBoss EAP 7.1
- Sticky transactions in JBoss EAP 7.1
- How to enable EJB forwards compatibility in EAP 7.1
- How can I configure JBoss EAP 7.1 so that EJB connections use 1-way SSL with Picketlink legacy security
- How can I configure JBoss EAP 7.1 so that EJB connections use 2-way SSL with Picketlink legacy security
- How to return EJB context data back to client in JBoss EAP 7.1
- How to set the cluster name in JBoss EAP 7.1
- How to configure EJB Cluster Node Selector / Deployment Node Selector in EAP 7.1
- Is it possible to use the remoting protocol instead of the http-remoting with http upgrade in EAP 7?
- EJB Load Balancing across multiple clusters in JBoss EAP 7.1
- How to invoke an EJB running on a current JBoss EAP / JDK from a legacy application running on an old JDK
- How to enable heartbeat on EJB connections in JBoss EAP 7.1
- How to disable security on the EJB remoting interface in JBoss EAP 7
- How can I enable unsecured and secured EJB access on JBoss EAP 7
- For remote EJBs in EAP 7 what are the differences between HTTP-REMOTING , HTTPS-REMOTING and REMOTE
- What is the ejb: JNDI binding in JBoss EAP 7.2 that is logged at deployment time with WFLYEJB0473: JNDI bindings...
- How to disable Stateful Session EJB (SFSB) clustering while leaving Stateless EJB (SLSB) clustering enabled in JBoss EAP 7
- How to disable Session EJB (SLSB/SFSB) clustering while leaving web session replication enabled in JBoss EAP 7
- How to enable EJB pass-by-reference in JBoss EAP 7 / 6
- How to configure EJB Async and EJB Timers to use a separate thread pool in JBoss EAP 7 / 6
- How to set an EJB's Instance Pool class via annotation and xml in JBoss EAP 7 / 6
- How to set EJB transaction timeout in JBoss EAP 7 / 6
- Transaction timeout precedence in JBoss EAP
- Using a Load balancer for remote EJB invocations in EAP 7 / EAP 6
- Handling of EJB business interface which is inherited in EAP
- How to compress remote EJB communication in JBoss EAP 7 / 6
- Configuring multiple EJB Connectors in JBoss EAP 7.4 / 8.0+
- How to create global ejb server side / client side interceptors in JBoss EAP
- How to set Discovery timeout in EJB client in JBoss EAP 7?
Troubleshooting
- Enabling EJB Debug/Trace logging in JBoss EAP 7 / 6
- Troubleshooting remote EJB client Exceptions in JBoss EAP 7.1
- EJBCLIENT000064 / WFNAM00049 / WFNAM00025 ... is deprecated in JBoss EAP 7.1
Common Issues
-
Client hangs on remote EJB calls during network / power outage in EAP 7 / 6
-
JBREM000308: Authentication failed (no mechanisms left), tried: (none) in EAP 7
-
Unable to use EJB over HTTP through Apache httpd connected to JBoss EAP via AJP
-
EJB invocation from standalone java fail with NullPointerException in EAP 7.1
-
Why EJB invocations are loadbalanced even if it is deployed in the same instance for EAP 7.2
-
For EAP 6.x, EAP 7.0 see How to configure an EJB client in JBoss EAP 6 / 7.0
Diagnostic Steps
Files to collect when an issue occurs:
- logs from both the client and server side when the issue occurs
- the client code showing how it sets up the InitialContext , any ejb client related configuration files such as jboss-ejb-client.xml, jboss-ejb-client.properties, wildfly-config.xml, etc.
- the server side: the EAP configuration, EJB annotations, ejb-jar.xml, jboss-ejb3.xml, etc anything that might be relevant
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.