This task describes how to add support to a remote client for the invocation of session beans using JNDI. The task assumes that the project is being built using Maven.
The ejb-remote quickstart contains working Maven projects that demonstrate this functionality. The quickstart contains projects for both the session beans to deploy and the remote client. The code samples below are taken from the remote client project.
This task assumes that the session beans do not require authentication.
You must already have a Maven project created ready to use.
Configuration for the JBoss EAP Maven repository has already been added.
The session beans that you want to invoke are already deployed.
The deployed session beans implement remote business interfaces.
You need to know the host name and JNDI port of the server hosting the session beans.
To invoke a session bean from a remote client you must first configure the project correctly.
Add the required project dependencies.
The pom.xml for the project must be updated to include the necessary dependencies.
The JBoss EJB client API expects to find a file in the root of the project named jboss-ejb-client.properties that contains the connection information for the JNDI service. Add this file to the src/main/resources/ directory of your project with the following content.
Change the host name and port to match your server. The default port number is 8080. For a secure connection, set the SSL_ENABLED line to true and uncomment the SSL_STARTTLS line. The Remoting interface in the container supports secured and unsecured connections using the same port.
Add dependencies on the remote business interfaces.
Add the Maven dependencies on the remote business interfaces of the session beans to the pom.xml.
After the project is configured correctly, you can add the code to access and invoke the session beans.
Two of the methods used in the following code (InitialContext() and lookup()) have a checked exception of type javax.naming.NamingException. These method calls must either be enclosed in a try/catch block that catches NamingException or in a method that is declared to throw NamingException. The ejb-remote quickstart uses the second technique.
The connection properties for the JNDI service are read from the jboss-ejb-client.properties file.
Use the JNDI Context's lookup() method to obtain a bean proxy.
Invoke the lookup() method of the bean proxy and pass it the JNDI name of the session bean you require. This will return an object that must be cast to the type of the remote business interface that contains the methods you want to invoke.
Session bean JNDI names are defined using a special syntax. For more information, see EJB JNDI Naming Reference.
Invoke methods: Now that you have a proxy bean object you can invoke any of the methods contained in the remote business interface.
The proxy bean passes the method invocation request to the session bean on the server, where it is executed. The result is returned to the proxy bean which then returns it to the caller. The communication between the proxy bean and the remote session bean is transparent to the caller.
You should now be able to configure a Maven project to support invoking session beans on a remote server and write the code invoke the session beans' methods using a proxy bean retrieved from the server using JNDI.
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.
You must consider your application requirements when using a single EJB client context with standalone remote clients. For more information about the different types of remote clients, refer to: About EJB Client Contexts.
Remote client JNDI lookups are usually backed by a jboss-ejb-client.properties file, which is used to set up the EJB client context and the EJB receivers. This configuration also includes the security credentials, which are then used to create the EJB receiver that connects to the JBoss EAP server. When the above code is invoked, the EJB client API looks for the EJB client context, which is then used to select the EJB receiver that will receive and process the EJB invocation request. In this case, there is just the single EJB client context, so that context is used by the above code to invoke the bean. The procedure to invoke a session bean remotely using JNDI is described in greater detail here: Invoke a Session Bean Remotely using JNDI.
In this case, the application wants to connect to the same server instance to invoke the EJB hosted on that server, but wants to use two different credentials while connecting to the server. Because the client application has a single EJB client context, which can have only one EJB receiver for each server instance, this means the above code uses just one credential to connect to the server and the code does not execute as the application expects it to.
Scoped EJB client contexts offer a solution to this issue. They provide a way to have more control over the EJB client contexts and their associated JNDI contexts, which are typically used for EJB invocations. For more information about scoped EJB client contexts, refer to Using Scoped EJB Client Contexts and Configure EJBs Using a Scoped EJB Client Context.
Transaction attributes for distributed JBoss EAP applications must be handled such that the application is called on the same server. To discontinue a transaction, the destination method must be marked REQUIRES_NEW using different interfaces.
JBoss EAP does not require Java Transaction Services (JTS) for transaction propagation on server-to-server EJB invocations if both servers are JBoss EAP. JBoss EJB client API library handles it itself.
To invoke EJB session beans with a JBoss EAP standalone client, the client must have a reference to the InitialContext object while the EJB proxies or UserTransaction are used. It is also important to keep the InitialContext object open while EJB proxies or UserTransaction are being used. Control of the connections will be inside the classes created by the InitialContext with the properties.
The following code example shows an EJB client that holds a reference to the InitialContext object. This code example was taken from the ejb-multi-server quickstart that ships with JBoss EAP.
Obtaining a UserTransaction reference on the client is unsupported for scenarios with a scoped EJB client context and for invocations which use the remote-naming protocol. This is because in these scenarios, InitialContext encapsulates its own EJB client context instance; which cannot be accessed using the static methods of the EJBClient class. When EJBClient.getUserTransaction() is called, it returns a transaction from default (global) EJB client context (which might not be initialized) and not from the desired one.
The following example shows how to get UserTransaction reference on a standalone client.
Replace "yourServerName" with the name of your server. If a user transaction is started on a node all invocations are sticky on the node and the node must have all the needed EJBs. It is not possible to use UserTransaction with remote-naming protocol and scoped-context.
To invoke an EJB bean using an IIOP remote call, you must first enable IIOP on the server.
To enable IIOP you must have the iiop-openjdk 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.
For a bean to be reachable by IIOP remote call, it needs to use EJB 2 and home interface with narrowing. More details on IIOP remote invocation can be seen at Configure IIOP for Remote EJB Calls.
When a client intends to invoke an EJB bean via IIOP remote call to start transaction on client side, the JTS transaction implementation has to be used. On the other hand, if a client intends to invoke an EJB bean via EJB remoting call, the JTA transaction implementation has to be used.
For EJB invocation via IIOP remote call, the transaction is created on client and propagated via call to the server. Whereas, for EJB invocation via EJB remoting call, the transaction is looked up on the server and is managed on the client side.
To enable JTS transactions on the server, you must change the transactions attribute from value spec to full in the iiop-openjdk subsystem and set the jts attribute in the transactions subsystem to true. You can accomplish this by using the following management CLI commands.
For the client to successfully invoke an EJB transaction using an IIOP call, we need to add the client-side dependency on org.wildfly:wildfly-iiop-openjdk.
For more information, see Configuring Transactions in the JBoss EAP Configuration Guide.
JBoss EAP is secure by default. No communication can happen with a server instance from a remote client without passing the appropriate credentials, irrespective of whether it is a standalone client or another server instance. In order to allow a client server to communicate with a destination server, you must configure user credentials to be used during this server communication.
Client server: the server from which the EJB invocation happens.
Destination server: the server on which the EJB is deployed.
Configure the user with required credentials on the destination server. See Adding a Management User in the JBoss EAP Configuration Guide for details.
Deploy the application. See Deploying Applications in the JBoss EAP Configuration Guide for details.
You must let the client server know about the destination server's EJB remoting connector, over which it can communicate during the EJB invocations. To achieve this, you must add a remote-outbound-connection to the remoting subsystem on the client server. The remote-outbound-connection configuration indicates that an outbound connection will be created to a remote server instance from this client server. The remote-outbound-connection must have an outbound-socket-binding configured with itself, which points to a remote host and a remote port of the destination server.
Create a security realm on the client server to communicate with a secure destination server. The client server must provide the user credentials to the destination server. To achieve this, you need to create a security realm on the client server, which will pass the user information provided for the user that was added to the destination server.
You must use a security realm which stores a base64-encoded password and then passes on these credentials when asked for. You need to create the base64 encoded version of the password that was provided for the user created initially for the destination server. You may use OpenSSL to generate base64-encoded passwords at the command line.
Here the password in plain text - password - is piped into the OpenSSL digest function then piped into another OpenSSL function to convert into base64-encoded format. You can now use base64-encoded password in the security realm that you configure on the client server.
You may notice that the management CLI shows the message "process-state" ⇒ "reload-required", so you must restart the server before this change can be used.
The code snippet above creates a security realm named ejb-security-realm with the base64-encoded password.
Create an outbound-socket-binding on the client server. You must now create an outbound-socket-binding that points to the destination server's host and port.
The command above creates an outbound-socket-binding named remote-ejb which points to localhost as the host and port 8080 as the destination port. Note that the host information should match the host/IP of the destination server. In this example, we are running the client and destination servers on the same machine so we use localhost. Similarly, the port information should match the http-remoting connector port used by the ejb3 subsystem; by default it is 8080.
The command above creates a remote-outbound-connection named remote-ejb-connection in the remoting subsystem and uses the previously created remote-ejb outbound-socket-binding. Notice the outbound-socket-binding-ref in the command above, with the http-remoting protocol. Furthermore, we also set the security-realm attribute to point to the security realm that we created in the previous step. Also notice that the username attribute is set to use the user who is allowed to communicate with the destination server.
This step creates an outbound connection on the client server to the remote destination server and sets up the username to the user who is allowed to communicate with that destination server. It also sets up the security realm to a pre-configured security realm capable of passing along the user credentials (in this case the password). This way when a connection has to be established from the client server to the destination server, the connection creation logic will have the necessary security credentials to pass along and set up a successful secure connection.
This completes our configuration on the client server. Our next step is to deploy the application on the client server which will invoke the bean deployed on the destination server.
Notice that we have configured the EJB client context for this application to use a remoting-ejb-receiver that points to the remote-outbound-connection named remote-ejb-connection, which we had created earlier. This links the EJB client context to use the remote-ejb-connection pointing to the EJB remoting connector on the destination server.
The code above will invoke the bean deployed on the destination server and return the result.
Let us deploy the client application on the client server. You can use either the CLI or the admin console or a IDE or deploy manually to EAP_HOME/standalone/deployments folder. Ensure that the application is deployed successfully.
See Deploying Applications in the JBoss EAP Configuration Guide for details.
To invoke an EJB In earlier versions of JBoss EAP, you would typically create a JNDI context and pass it the PROVIDER_URL, which would point to the target server. Any invocations done on EJB proxies that were looked up using that JNDI context, would end up on that server. With scoped EJB client contexts, user applications have control over which EJB receiver is used for a specific invocation.
To use the scoped EJB client context, you configure EJB client properties programmatically and pass the properties on context creation. The properties are the same set of properties that are used in the standard jboss-ejb-client.properties file. To scope the EJB client context to the JNDI context, you must also specify the org.jboss.ejb.client.scoped.context property and set its value to true. This property notifies the EJB client API that it must create an EJB client context, which is backed by EJB receivers, and that the created context is then scoped or visible only to the JNDI context that created it. Any EJB proxies looked up or invoked using this JNDI context will only know of the EJB client context associated with this JNDI context. Other JNDI contexts used by the application to lookup and invoke EJBs will not know about the other scoped EJB client contexts.
JNDI contexts that do not pass the org.jboss.ejb.client.scoped.context property and are not scoped to an EJB client context will use the default behavior, which is to use the existing EJB client context that is typically tied to the entire application.
Scoped EJB client contexts provide user applications with the flexibility that was associated with the JNP based JNDI invocations in previous versions of JBoss EAP. It provides user applications with more control over which JNDI context communicates to which server and how it connects to that server.
With the scoped context, the underlying resources are no longer handled by the container or the API, so you must close the InitialContext when it is no longer needed. When the InitialContext is closed, the resources are released immediately. The proxies that are bound to it are no longer valid and any invocation will throw an Exception. Failure to close the InitialContext may result in resource and performance issues.
EJBs can be configured using a map-based scoped context. This is achieved by programmatically populating a properties map using the standard properties found in jboss-ejb-client.properties, specifying true for the org.jboss.ejb.client.scoped.context property, and passing the properties on the InitialContext creation.
The benefit of using a scoped context is that it allows you to configure access without directly referencing the EJB or importing JBoss classes. It also provides a way to configure and load balance a host at runtime in a multithreaded environment.
Configure the EJB client properties programmatically, specifying the same set of properties that are used in the standard jboss-ejb-client.properties file. To enable the scoped context, you must specify the org.jboss.ejb.client.scoped.context property and set its value to true. Following is an example that configures the properties programmatically.
Look up the root JNDI context for ejb: string to fetch the EJB naming context. Then use ejbRootNamingContext instance to look up the rest of the EJB JNDI name to fetch the EJB proxy. Use the close() method to close ejbRootNamingContext and the EJB JNDI context. Closing ejbRootNamingContext ensures that the scoped EJB client context associated with the JNDI context is closed too. Effectively, this closes the connection to the server within that EJB client context.
Contexts generated by lookup EJB proxies are bound by this scoped context and use only the relevant connection parameters. This makes it possible to create different contexts to access data within a client application or to independently access servers using different logins.
In the client, both the scoped InitialContext and the scoped proxy are passed to threads, allowing each thread to work with the given context. It is also possible to pass the proxy to multiple threads that can use it concurrently.
The scoped context EJB proxy is serialized on the remote call and then deserialized on the server. When it is deserialized, the scoped context information is removed and it returns to its default state. If the deserialized proxy is used on the remote server, because it no longer has the scoped context that was used when it was created, this can result in an EJBCLIENT000025 error or possibly call an unwanted target by using the EJB name.
The following tables list properties that can be configured programmatically or in the jboss-ejb-client.properties file.
The following table lists properties that are valid for the whole library within the same scope.
Name of the client endpoint. If not set, the default value is client-endpoint.
This can be helpful to distinguish different endpoint settings because the thread name contains this property.
Boolean value that specifies whether the SSL protocol is enabled for all connections.
The fully qualified name of the implementation of org.jboss.ejb.client.DeploymentNodeSelector.
This is used to load balance the invocation for the EJBs.
The timeout for the EJB handshake or method invocation request/response cycle. The value is in milliseconds.
The invocation of any method throws a java.util.concurrent.TimeoutException if the execution takes longer than the timeout period. The execution completes and the server is not interrupted.
The timeout for the background reconnect tasks. The value is in milliseconds.
If a number of connections are down, the next client EJB invocation will use an algorithm to decide if a reconnect is necessary to find the right node.
Boolean value that specifies whether to enable the scoped EJB client context. The default value is false.
If set to true, the EJB Client will use the scoped context that is tied to the JNDI context. Otherwise the EJB client context will use the global selector in the JVM to determine the properties used to call the remote EJB and host.
The connection properties start with the prefix remote.connection. where the CONNECTION_NAME is a local identifier only used to uniquely identify the connection.
A comma-separated list of active connection-names. Each connection is configured by using this name.
The host name or IP for the connection.
The port for the connection. The default value is 8080.
The user name used to authenticate connection security.
The password used to authenticate the user.
The timeout period for the initial connection. After that, the reconnect task will periodically check whether the connection can be established. The value is in milliseconds.
Fully qualified name of the CallbackHandler class. It will be used to establish the connection and can not be changed as long as the connection is open.
Integer value specifying the maximum number of outbound requests. The default is 80.
Boolean value that determines whether credentials must be provided by the client to connect successfully. The default value is true.
If set to true, the client must provide credentials. If set to false, invocation is allowed as long as the remoting connector does not request a security realm.
Disables certain SASL mechanisms used for authenticating during connection creation.
JBOSS-LOCAL-USER means the silent authentication mechanism, used when the client and server are on the same machine, is disabled.
Boolean value that enables or disables the use of plain text messages during the authentication. If using JAAS, it must be set to false to allow a plain text password.
Boolean value that specifies whether the SSL protocol is enabled for this connection.
Interval to send a heartbeat between client and server to prevent automatic close, for example, in the case of a firewall. The value is in milliseconds.
If the initial connection connects to a clustered environment, the topology of the cluster is received automatically and asynchronously. These properties are used to connect to each received member. Each property starts with the prefix remote.cluster. where the CLUSTER_NAME refers to the related to the servers infinispan subsystem configuration.
The fully qualified name of the implementation of org.jboss.ejb.client.ClusterNodeSelector.
This class, rather than org.jboss.ejb.client.DeploymentNodeSelector, is used to load balance EJB invocations in a clustered environment. If the cluster is completely down, the invocation will fail with the message No ejb receiver available.
Integer value specifying the maximum number of outbound requests that can be made to the entire cluster.
Integer value specifying the maximum number of outbound requests that can be made to this specific cluster-node.
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 compressionLevel setting defaults to Deflater.DEFAULT_COMPRESSION.
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.
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-remoting connector and instead uses a remoting connector. This is achieved by defining a new client-side connection property.
EJB remote calls are supported for JBoss EAP 7 with JBoss EAP 6 only.
Configure the ORB for JTS Transactions in the JBoss EAP Configuration Guide.
JBoss EAP supports CORBA/IIOP-based access to EJBs deployed on JBoss EAP.
enable-by-default: If this is true, then all the EJBs with EJB 2.x home interfaces are exposed through IIOP. Otherwise they must be explicitly enabled through jboss-ejb3.xml.
use-qualified-name: If this is true, 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 as myear/myejbjar/MyBean. If this is false, 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.0.
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.
Use the following management CLI command to access and update the iiop-openjdk subsystem.
The IIOP element takes two attributes that control the default behavior of the server.
The packed beans along with the descriptor in the JAR file is now ready to be deployed to the JBoss EAP container.
The client will need to have the wildfly iiop openjdk library added to its class path. The client might also need to add the org.wildfly:wildfly-iiop-openjdk artifact as Maven dependency.