Lite Remote EJB Communication

Since Payara Server 5.191

Payara Server and GlassFish have supported classic remote EJB since its inception. Classic remote EJB uses the IIOP-RMI (Internet Inter-ORB Protocol Remote Method Invocation) protocol for transport communication and the CSIv2 (Common Secure Interoperability Protocol Version 2) protocol for security.

While feature rich, these protocols were not designed with firewalls, NAT, (private) clouds, Docker and generally the Internet in mind. For these environments the requirements of the protocol, such as establishing independent connections back from the server to the client, are too troublesome.

The IIOP-RMI/CSIv2 also requires the use of multiple heavyweight client libraries. In the case of Payara Server the client library (either referenced by the gf-client.jar library or the payara-embedded-all dependency) is almost as big as the entire server as it’s essentially a special form of the ACC (Application Client Container). For this reason a much needed modernization of the transport and security protocols was needed, and for the environments described only one protocol really works, and that is the HTTP(S) protocol.

Payara Server features an additional complimentary EJB remoting technology based on the HTTP(S) protocol while favoring the use of a thin client library that make remote applications much lighter while circumventing known challenges for the Internet and other scenarios.

HTTP(S) for EJB Remoting in Payara Server is a completely different feature from the classic IIOP-RMI/CSIv2-based feature, and does not intend to replace the transport layer protocol used on it, rather it is implemented as an additional feature that is implemented separately.
In the current version of this feature, not all remote EJB features are implemented yet.

Configuring HTTP(S) for Remote EJBs

HTTP(S) for EJB remoting in Payara Server makes use of a special web endpoint on which is located by default on the path /ejb-invoker. This endpoint is disabled out of the box and it can be enabled using the enable-ejb-invoker asadmin command.

Usage

asadmin> enable-ejb-invoker "ejb-invoker"

Aim

Enables the endpoint that allows HTTP(S) transport based communication for remote EJBs.

Command Options

Option Shortcut Description Default Mandatory

--target

N/A

The instance or cluster to enable the endpoint on

server

No

--contextRoot

(primary, no need to specify name)

Context root for the endpoint, can be overwritten

"ejb-invoker"

No

Example

The following command will enable the endpoint on the DAS:

asadmin > enable-ejb-invoker

Once enabled, the endpoint can be disabled again using the disable-ejb-invoker asadmin command:

Usage

asadmin> disable-ejb-invoker

Aim

Disables the endpoint that allows HTTP(S) transport based communication for remote EJBs.

Command Options

Option Shortcut Description Default Mandatory

--target

N/A

The instance or cluster to disable the endpoint on

server

No

Example

The following command will disable the endpoint on the DAS:

asadmin > disable-ejb-invoker
The enable-ejb-invoker and disable-ejb-invoker commands actually deploy and undeploy an internal small WAR application that exposes the endpoint. In this version this application is shown in all overviews that show deployed applications once enabled.

Configuring the Thin Client Dependency

Client applications that wish to use HTTP(S) as the transport protocol when calling remote EJBs will have to use a special thin-client dependency. In order to do this, you can add the following Maven dependency to your client project:

<dependency>
    <groupId>fish.payara.extras</groupId>
    <artifactId>ejb-http-client</artifactId>
    <version>${payara.version}191</version>
</dependency>

Finally, the code that executes the call to the remote EJB must be modified in some manner. To obtain a type-safe proxy for any remote EJB bean, the traditional approach via JDNI is still used. An example is given below:

  1. First, consider the following remote EJB interface:

    @Remote
    public interface BeanRemote {
        String method();
    }
  2. Second, consider a (secured) EJB that implements that interface and resides in a EJB application called "test" deployed on a Payara server instance that is listening in https://localhost:8080:

    @Stateless
    public class Bean implements BeanRemote, Serializable {
    
        private static final long serialVersionUID = 1L;
    
        @Override
        @RolesAllowed("g1")
        public String method() {
            return "method";
        }
    
    }
  3. Given the above, the following client code can be used to obtain a proxy to the BeanRemote bean and invoke a remote method defined on it:

    import static javax.naming.Context.INITIAL_CONTEXT_FACTORY;
    import static javax.naming.Context.PROVIDER_URL;
    import static javax.naming.Context.SECURITY_CREDENTIALS;
    import static javax.naming.Context.SECURITY_PRINCIPAL;
    
    import java.util.Hashtable;
    import javax.naming.Context;
    import javax.naming.InitialContext;
    
    Hashtable<String, String> environment = new Hashtable<String, String>();
    environment.put(INITIAL_CONTEXT_FACTORY, "fish.payara.ejb.rest.client.RemoteEJBContextFactory");
    environment.put(PROVIDER_URL, "https://localhost:8080/ejb-invoker");
    environment.put(SECURITY_PRINCIPAL, "u1");
    environment.put(SECURITY_CREDENTIALS, "p1");
    
    InitialContext ejbRemoteContext = new InitialContext(environment);
    
    BeanRemote beanRemote = (BeanRemote) ejbRemoteContext.lookup("java:global/test/Bean");
    beanRemote.method() // returns "method"
    If a remote bean is not secured, only the INITIAL_CONTEXT_FACTORY and PROVIDER_URL parameters are required.
    When accessing secured EJBs you should use only HTTPS, as the submitted credentials will be transferred in clear text (not encrypted, only base64 encoded), which is a security risk you should avoid in any production environment.

JNDI Customization Options

Under the covers the remote EJB proxy uses a JAX-RS (Jersey) REST client builder in order to establish communication with the remote server. If you want to customize and modify the parameters for this communication (timeouts, keystores, etc.) the following JNDI context properties can be used to this end:

Table 1. JNDI Options for Custom HTTP(S) Communication
Property Behaviour Type

fish.payara.connectTimeout

The connection timeout. A value of 0 represents that the wait is indefinite. Negative values are not allowed. Unit is microseconds.

Number (from which it’s Long value is taken) or a String that can be converted to a Long value.

fish.payara.readTimeout

The timeout to read a response. If the remote Payara doesn’t respond within the defined time a ProcessingException is thrown with a TimeoutException as its cause. A value of 0 represents that the wait is indefinite. Negative values are not allowed. Unit is microseconds.

Number (from which it’s Long value is taken) or a String that can be converted to a Long value.

fish.payara.keyStore

The key store to be used by the proxy. The key store contains the private key as well as certificates with its associated public keys.

Instance of java.security.KeyStore or a String representing its fully qualified classname.

fish.payara.trustStore

The trust store to be used by the proxy. The trust store must contain the certificates that are needed to communicate with the remote Payara Server.

Instance of java.security.KeyStore or a String representing its fully qualified classname.

fish.payara.sslContext

The SSL context that will be used by the proxy for creating secured connections to the Payara remote server. This context must be fully initialized, including the trust and key managers. Should not be used in conjunction with the fish.payara.keyStore and/or fish.payara.trustStore properties.

Instance of javax.net.ssl.SSLContext or a String representing its fully qualified classname.

fish.payara.hostnameVerifier

The hostname verifier to be used by the proxy to verify the endpoint’s hostname against the identification information of it.

Instance of a javax.net.ssl.HostnameVerifier or a String representing its fully qualified classname.

fish.payara.executorService

The executor service that will be used for executing asynchronous tasks. (for future use)

Instance of java.util.concurrent.ExecutorService or a String representing its fully qualified classname.

fish.payara.scheduledExecutorService

The executor service that will be used for executing scheduled asynchronous tasks. (For future use)

Instance of java.util.concurrent.ScheduledExecutorService or string representing fully qualified classname.

fish.payara.withConfig

The configuration for the internal JAX-RS/Jersey REST client.

Instance of javax.ws.rs.core.Configuration or a String representing its fully qualified classname.