Chapter 5. Invoking Session Beans
5.1. About EJB Client Contexts
JBoss EAP introduced the EJB client API for managing remote EJB invocations. The JBoss EJB client API uses the EJBClientContext, which may be associated with and be used by one or more threads concurrently. This means an EJBClientContext can potentially contain any number of EJB receivers. An EJB receiver is a component that knows how to communicate with a server that is capable of handling the EJB invocation. Typically, EJB remote applications can be classified into the following:
- A remote client, which runs as a standalone Java application.
- A remote client, which runs within another JBoss EAP instance.
Depending on the type of remote client, from an EJB client API point of view, there can potentially be more than one EJBClientContext within a JVM.
While standalone applications typically have a single EJBClientContext that may be backed by any number of EJB receivers, this isn’t mandatory. If a standalone application has more than one EJBClientContext, an EJB client context selector is responsible for returning the appropriate context.
In case of remote clients that run within another JBoss EAP instance, each deployed application will have a corresponding EJB client context. Whenever that application invokes another EJB, the corresponding EJB client context is used to find the correct EJB receiver, which then handles the invocation.
5.2. Using Remote EJB Clients
5.2.1. Initial Context Lookup
You can pass the remote server’s address using the PROVIDER_URL property when creating an initial context:
public class Client {
public static void main(String[] args)
throws NamingException, PrivilegedActionException, InterruptedException {
InitialContext ctx = new InitialContext(getCtxProperties());
String lookupName = "ejb:/server/HelloBean!ejb.HelloBeanRemote";
HelloBeanRemote bean = (HelloBeanRemote)ctx.lookup(lookupName);
System.out.println(bean.hello());
ctx.close();
}
public static Properties getCtxProperties() {
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, WildFlyInitialContextFactory.class.getName());
props.put(Context.PROVIDER_URL, "remote+http://127.0.0.1:8080");
props.put(Context.SECURITY_PRINCIPAL, "joe");
props.put(Context.SECURITY_CREDENTIALS, "joeIsAwesome2013!");
return props;
}
}
The Initial context factory to be used for the lookup is org.wildfly.naming.client.WildFlyInitialContextFactory.
5.2.2. Remote EJB Configuration File
JBoss EAP features the Elytron security framework. The wildfly-config.xml file, which is present in the META-INF/ directory of the client application’s class path, allows a wide range of authentication and authorization options for the Elytron security framework and EJB client configuration.
<configuration>
<authentication-client xmlns="urn:elytron:1.0.1">
<authentication-rules>
<rule use-configuration="default" />
</authentication-rules>
<authentication-configurations>
<configuration name="default">
<sasl-mechanism-selector selector="DIGEST-MD5" />
<set-user-name name="admin" />
<credentials>
<clear-password password="password123!" />
</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>
As an alternative to embedding the PROVIDER_URL, SECURITY_PRINCIPAL and SECURITY_CREDENTIALS parameters in the initial context, you can use the <connection-uri> and <authentication-client> elements in the wildfly-config.xml file to configure the connection URI and the security settings, respectively.
5.2.3. The ClientTransaction Annotation
The @org.jboss.ejb.client.annotation.ClientTransaction annotation handles transaction propagation from an EJB client. You can mandate the propagation to fail if the client has no transaction, or prevent the transaction propagation even if the client has one active. You can use the constants of the org.jboss.ejb.client.annotation.ClientTransactionPolicy interface to control the policy of the ClientTransaction annotation. The following are the constants of the org.jboss.ejb.client.annotation.ClientTransactionPolicy interface:
- MANDATORY: Fail with exception when there is no client-side transaction context; propagate the client-side transaction context when it is present.
- NEVER: Invoke without propagating any transaction context; if a client-side transaction context is present, an exception is thrown.
- NOT_SUPPORTED: Invoke without propagating any transaction context whether or not a client-side transaction context is present.
- SUPPORTS: Invoke without a transaction if there is no client-side transaction context; propagate the client-side transaction context if it is present.
If no annotation is present, the default policy is org.jboss.ejb.client.annotation.ClientTransactionPolicy#SUPPORTS, which means that the transaction is propagated if it is present, but the propagation does not fail, regardless of whether a transaction is present or not.
@ClientTransaction(ClientTransactionPolicy.MANDATORY)
@Remote
public interface RemoteCalculator {
public void callRemoteEjb() { }
}
@Stateless
@Remote(RemoteCalculator.class)
public class CalculatorBean implements RemoteCalculator {
@Override
public void callRemoteEjb() { }
}The annotation allows the remote interface provider to tell the remote interface consumer whether transactions are needed for a method.
5.3. Remote EJB Data Compression
Previous versions of JBoss EAP included a feature where the message stream that contained the EJB protocol message could be compressed. This feature has been included in JBoss EAP 6.3 and later.
Compression currently can only be specified by annotations on the EJB interface which should be on the client and server side. There is not currently an XML equivalent to specify compression hints.
Data compression hints can be specified via the JBoss annotation org.jboss.ejb.client.annotation.CompressionHint. The hint values specify whether to compress the request, response or request and response. Adding @CompressionHint defaults to compressResponse=true and compressRequest=true.
The annotation can be specified at the interface level to apply to all methods in the EJB’s interface such as:
import org.jboss.ejb.client.annotation.CompressionHint;
@CompressionHint(compressResponse = false)
public interface ClassLevelRequestCompressionRemoteView {
String echo(String msg);
}Or the annotation can be applied to specific methods in the EJB’s interface such as:
import org.jboss.ejb.client.annotation.CompressionHint;
public interface CompressableDataRemoteView {
@CompressionHint(compressResponse = false, compressionLevel = Deflater.BEST_COMPRESSION)
String echoWithRequestCompress(String msg);
@CompressionHint(compressRequest = false)
String echoWithResponseCompress(String msg);
@CompressionHint
String echoWithRequestAndResponseCompress(String msg);
String echoWithNoCompress(String msg);
}
The compressionLevel setting shown above can have the following values:
- BEST_COMPRESSION
- BEST_SPEED
- DEFAULT_COMPRESSION
- NO_COMPRESSION
The compressionLevel setting defaults to Deflater.DEFAULT_COMPRESSION.
Class level annotation with method level overrides:
@CompressionHint
public interface MethodOverrideDataCompressionRemoteView {
@CompressionHint(compressRequest = false)
String echoWithResponseCompress(final String msg);
@CompressionHint(compressResponse = false)
String echoWithRequestCompress(final String msg);
String echoWithNoExplicitDataCompressionHintOnMethod(String msg);
}
On the client side ensure the org.jboss.ejb.client.view.annotation.scan.enabled system property is set to true. This property tells JBoss EJB Client to scan for annotations.
5.4. EJB Client Remoting Interoperability
The default remote connection port is 8080. The jboss-ejb-client properties file looks like this:
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
Default Connector
The default connector is http-remoting.
-
If a client application uses the EJB client library from JBoss EAP 6 and wants to connect to a JBoss EAP 7 server, the server must be configured to expose a remoting connector on a port other than
8080. The client must then connect using that newly configured connector. A client application that uses the EJB client library from JBoss EAP 7 and wants to connect to a JBoss EAP 6 server must be aware that the server instance does not use the
http-remotingconnector and instead uses aremotingconnector. This is achieved by defining a new client-side connection property.remote.connection.default.protocol=remote
EJB remote calls are supported for JBoss EAP 7 with JBoss EAP 6 only.
Besides EJB client remoting interoperability, you can connect to legacy clients using the following options:
- Configure the ORB for JTS Transactions in the JBoss EAP Configuration Guide.
5.5. Configure IIOP for Remote EJB Calls
JBoss EAP supports CORBA/IIOP-based access to EJBs deployed on JBoss EAP.
The <iiop> element is used to enable IIOP, CORBA, invocation of EJBs. The presence of this element means that the iiop-openjdk subsystem is installed. The <iiop> element includes the following two attributes:
-
enable-by-default: If this istrue, then all the EJBs with EJB 2.x home interfaces are exposed through IIOP. Otherwise they must be explicitly enabled throughjboss-ejb3.xml. -
use-qualified-name: If this istrue, then the EJBs are bound to the CORBA naming context with a binding name that contains the application and modules name of the deployment, such asmyear/myejbjar/MyBean. If this isfalse, then the default binding name is simply the bean name.
IIOP calls can be done only with EJB 2 beans. EJB 3 beans are not supported by IIOP in JBoss EAP 7.1.
Enabling IIOP
To enable IIOP you must have the IIOP OpenJDK ORB subsystem installed, and the <iiop/> element present in the ejb3 subsystem configuration. The standalone-full.xml configuration that comes with the distribution has both of these enabled.
IIOP is configured in the iiop-openjdk subsystem of the server configuration file.
<subsystem xmlns="urn:jboss:domain:iiop-openjdk:1.0">
Use the following management CLI command to access and update the iiop-openjdk subsystem.
/subsystem=iiop-openjdk
The IIOP element takes two attributes that control the default behavior of the server.
<subsystem xmlns="urn:jboss:domain:ejb3:1.2"> ... <iiop enable-by-default="false" use-qualified-name="false"/> ... </subsystem>
The following management CLI command adds the <iiop> element under the ejb3 subsystem:
/subsystem=ejb3/service=iiop:add(enable-by-default=false, use-qualified-name=false)
Create an EJB That Communicates Using IIOP
The following example demonstrates how to make a remote IIOP call from the client:
Create an EJB 2 bean on the server:
@Remote(IIOPRemote.class) @RemoteHome(IIOPBeanHome.class) @Stateless public class IIOPBean { public String sayHello() throws RemoteException { return "hello"; } }Create a home implementation, which has a mandatory method
create(). This method is called by the client to obtain proxy of remote interface to invoke business methods:public interface IIOPBeanHome extends EJBHome { public IIOPRemote create() throws RemoteException; }Create a remote interface for remote connection to the EJB:
public interface IIOPRemote extends EJBObject { String sayHello() throws RemoteException; }Introduce the bean for remote call by creating a descriptor file
jboss-ejb3.xmlinMETA-INF:<?xml version="1.0" encoding="UTF-8"?> <jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:iiop="urn:iiop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd http://java.sun.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-spec-2_0.xsd urn:iiop jboss-ejb-iiop_1_0.xsd" version="3.1" impl-version="2.0"> <assembly-descriptor> <iiop:iiop> <ejb-name>*</ejb-name> </iiop:iiop> </assembly-descriptor> </jboss:ejb-jar>NoteThe packed beans along with the descriptor in the JAR file is now ready to be deployed to the JBoss EAP container.
Create a context at the client side:
System.setProperty("com.sun.CORBA.ORBUseDynamicStub", "true"); final Properties props = new Properties(); props.put(Context.PROVIDER_URL, "corbaloc::localhost:3528/JBoss/Naming/root"); props.setProperty(Context.URL_PKG_PREFIXES, "org.jboss.iiop.naming:org.jboss.naming.client"); props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.cosnaming.CNCtxFactory"); props.put(Context.OBJECT_FACTORIES, "org.jboss.tm.iiop.client.IIOPClientUserTransactionObjectFactory");NoteThe client will need to have the
wildfly iiop openjdklibrary added to its class path. The client might also need to add theorg.wildfly:wildfly-iiop-openjdkartifact as Maven dependency.Use the context lookup to narrow the reference to the
IIOPBeanHomehome interface. Then call the home interfacecreate()method to access the remote interface, which allows you to call its methods:try { Context context = new InitialContext(props); final Object iiopObj = context.lookup(IIOPBean.class.getSimpleName()); final IIOPBeanHome beanHome = (IIOPBeanHome) PortableRemoteObject.narrow(iiopObj, IIOPBeanHome.class); final IIOPRemote bean = beanHome.create(); System.out.println("Bean saying: " + bean.sayHello()); } catch (Exception e) { e.printStackTrace(); }
5.6. Configure the EJB Client Address
You can determine the EJB client address using the SessionContext interface, as shown in the example below.
public class HelloBean implements HelloBeanRemote {
@Resource
SessionContext ctx;
private Long counter;
public HelloBean() {
}
@PostConstruct
public void init() {
counter = 0L;
}
@Override
@RolesAllowed("users")
public String hello() {
final String message = "method hello() invoked by user " + ctx.getCallerPrincipal().getName()
+ ", source addr = " + ctx.getContextData().get("jboss.source-address").toString();
System.out.println(message);
return message;
}
}Standalone Client Configuration
You can configure the outbound-bind-addresses element within the worker element having namespace urn:xnio:3.5 in the wildfly-client.xml file. The bind-address sub-element takes the attributes match, bind-address, bind-port, as defined below.
The following is an example of the standalone client configuration using the wildfly-client.xml file.
<configuration>
<worker xmlns="urn:xnio:3.5">
<worker-name value="default"/>
<outbound-bind-addresses>
<bind-address bind-address=IP_ADDRESS_TO_BIND_TO bind-port=OPTIONAL_SOURCE_PORT_NUMBER match=CIDR_BLOCK />
</outbound-bind-addresses>
</worker>
</configuration>
The outbound-bind-address requires the following attributes:
-
matchis a Classless Inter-Domain Routing (CIDR) block, such as10.0.0.0/8,ff00::\8,0.0.0.0/0,::/0. -
bind-addressspecifies the IP address to bind to when the destination address matches the CIDR block specified in thematchparameter. It should be the same address family as the CIDR block. bind-portis an optional source port number that defaults to0.If no matching expression exists, then the outbound socket is not explicitly bound.
Container-based Configuration
Container-based configuration of the EJB client address is similar to the standalone client configuration defined in the wildfly-client.xml file.
The example below configures the outbound-bind-address on the default worker element of the io subsystem, which the ejb3 subsystem uses by default.
/subsystem=io/worker=default/outbound-bind-address=SPECIFY_OUTBOUND_BIND_ADDRESS:add(bind-address=IP_ADDRESS_TO_BIND_TO, bind-port=OPTIONAL_SOURCE_PORT_NUMBER, match=CIDR_BLOCK)
5.7. EJB Invocation Over HTTP
EJB invocation over HTTP is provided as Technology Preview only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs), might not be functionally complete, and Red Hat does not recommend to use them for production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.
See Technology Preview Features Support Scope on the Red Hat Customer Portal for information about the support scope for Technology Preview features.
EJB invocation over HTTP includes two distinct parts: the client-side and the server-side implementations.
5.7.1. Client-side Implementation
The client-side implementation consists of an EJBReceiver that uses the Undertow HTTP client to invoke the server. Connection management is handled automatically using a connection pool.
In order to configure an EJB client application to use HTTP transport, you must add the following dependency on the HTTP transport implementation:
<dependency>
<groupId>org.wildfly.wildfly-http-client</groupId>
<artifactId>wildfly-http-ejb-client</artifactId>
</dependency>
To perform the HTTP invocation, you must use the http URL scheme and include the context name of the HTTP invoker, wildfly-services. For example, if you are using remote+http://localhost:8080 as the target URL, in order to use the HTTP transport, you must update this to http://localhost:8080/wildfly-services.
5.7.2. Server-side Implementation
The server-side implementation consists of a service that handles the incoming HTTP requests, unmarshals them and passes the result to the internal EJB invocation code.
In order to configure the server, the http-invoker must be enabled on each of the virtual hosts that you wish to use in the undertow subsystem. This is enabled by default in the standard configurations. If it is disabled, it can be re-enabled using the following management CLI command:
/subsystem=undertow/server=default-server/host=default-host/setting=http-invoker:add(http-authentication-factory=myfactory, path='wildfly-services')
http-invoker has two attributes: a path that defaults to wildfly-services, and one of the following:
-
An
http-authentication-factorythat must be a reference to an Elytronhttp-authentication-factory, as shown in the above command. -
A legacy
security-realm.
Note that the above two attributes are mutually exclusive: you cannot specify both an http-authentication-factory and a security-realm at the same time.
Any deployment that aims to use the http-authentication-factory must use Elytron security with the same security domain corresponding to the specified HTTP authentication factory.

Where did the comment section go?
Red Hat's documentation publication system recently went through an upgrade to enable speedier, more mobile-friendly content. We decided to re-evaluate our commenting platform to ensure that it meets your expectations and serves as an optimal feedback mechanism. During this redesign, we invite your input on providing feedback on Red Hat documentation via the discussion platform.