EJB 3.2 : Remote View – Client and EJBs in different Containers (Tutorial 8)

How to configure an Application Server to connect to a Remote Application Server (idem EJBs deployed in a different Container) ?

How to configure multiple remote EJBs Containers?

How to invoke a Session Bean deployed in another EJB Container using JNDI Lookup and Dependency Injection?

How to make Dependency Injection work in a Web Service?

How to retain a Stateful Session Bean obtained within a Web Service Request?

How to automatically destroy a Stateful Session Bean bound to a Session?


Tutorial 1 : Eclipse + Maven 3 + Wildfly 9  

Tutorial 2 : Session Beans

Tutorial 3 : Solution Design

Tutorial 4 : Session Beans and Business Interfaces Projects

Tutorial 5 : Local View – Client and EJBs in the Same WAR

Tutorial 6 : Remote View – Client and EJBs in the Same EAR

Tutorial 7 : Remote View – Client and EJBs in Different WARs but Same Container

Tutorial 8 : Remote View – Client and EJBs in different Containers current-tutorial-icon-50 

Tutorial 9 : Standalone Client


 

Use Case

We are gonna package the Session beans in the WAR ejb3-server-war and deploy it in Application Sever 1.
Also we gotta create an application user “ejb-client” in Application Sever 1, this user must have permission to be used remotely from another AS.
The client invoking the Session Bean will be wrapped in a Web Service and packaged in the WAR ejb-remote-client-2-war that will be deployed in Application Server 2.
In the same example we will use JNDI Lookup and Dependency Injection, Yummyyyy!
different container

Configuring an AS to connect to a remote AS?

Remote Application Server (EJBs Container)

First, let’s create an application user in Application Server 1 (WildFly  9.0.2.Final 1). So execute add-user.bat file :

  1. Use option b) as we want an Application User.
  2. Answer by yes for the question “Is this new user going to be user for one AS process to connect to another AS process?”.
  3. Save the secret value as we will need it. But it’s okay if you lose it. It is the password encoded in the Base 64. So you can regenerate it yourself. I let you decoding “UHdkMTIzNCs=” to discvoer by yourself my password. 

ejb client : application user in wildfly

Client Application Server

Now, let’s refer to the app user “ejb-client” in Application Server 2 (WildFly  9.0.2.Final 2).

Let’s edit then the Client AS standalone.xml file :

See, here we are using the secret value “UHdkMTIzNCs=”, the 64 base encoded password of “ejb-client” we created. We are adding it as a security realm and giving it the name “ejb-security-realm”.

Next, we must configure an outbounding connection. See the highlighted line. In the option security-realm we are referencing the security realm above we created. For username option it is the same as the application username “ejb-client”. Since WildFly 8, remote connection uses the protocol HTTP instead of Netty. And for sure again we are giving this outbounding connection a name because we are going to refer somewhere else.

And finally, we are configuring an outbound socket binding, we gotta precise the hostname (or the IP Address) of the remote destination and the port on which this destination will receive the client invocation requests :

I am deploying the remote destination in the same machine as the client that is why I am using localhost.

How to configure multiple remote EJBs Containers?

Simple, you just got to create an application user in each additional remote EJB Container. Then, for each user (for each remote AS), you got to configure the additional blocks in the Client AS standalone.xml :

  • <security-realm />
  • <remote-outbound-connection />
  • <outbound-socket-binding />

Invoking a Remote Session Bean Deployed in a Different Container

pom.xml

Under Eclipse, create a war project ejb3-remote-client-2-war. As highlighted, we need :

  • the Business Interfaces of the Session Beans that we packaged in the JAR ejb3-server-api. Check this tutorial to have a complete idea.
  • the programmatic JNDI lookup we coded separately in jndi-lookup-util. Check this tutorial to have a complete idea.
  • The all-in-one JAR for Java EE 7 classes, javaee-api. This dependency will bring us not only the EJB packages, but also Web Service and Servlet packages. Awesome, isn’t it?  I so far prefer this lonely dependency than dealing with many dependencies and complaining later from exceptions such as ClassNotFoundException when mixing non-compliant versions of the dependencies,…

Configuring a Remoting EJB Receiver in jboss-ejb-client.xml

In the Client project, add the file jboss-ejb-client.xml under src\main\webapp\WEB-INF :

“remote-ejb-connection” is the name of <remote-outbound-connection /> that we have set in the standalone.xml file.

Programmatic JNDI Lookup

To factorize our code, the following is the LookerUp class that we created in jndi-lookup-util project.

As explicitly expressed in the comments bellow, for these cases we are setting the same environment properties :

  • Client and EJBs in Different Containers
  • Client and EJBs are in the same Container, but packaged in different applications.

The only different is that in the same Container we don’t need authentication, but from a different container we need authentication the way we described previously.

Dependency Injection

To be able to inject an EJB, you must add to the annotation @EJB the attribute mappedName and give a value that must respect this pattern :

Important (!) : As we will see in the example, we will have to add the annotation @Stateless to our webservice. The reason is that the Web Service is not managed by the Container as a Session Bean, as a result, the container won’t inject any EJB although annotated, and we will suffer from NullPointerException… The web services are by nature stateless, that is why to be managed as Stateless Session Bean is the most appropriate.

Is this the best way to do? I don’t know. You tell me. 

Invoking Session Beans from A Web Service Layer

Activating JAX-RS

Let’s activate JAX-RS programmatically, and choose “/ws” as a Context for the Web Service Context :

Retaining as Stateful Session Bean obtained within a Web Service Request?

Hey! What I’m going to describe is only “an idea” to rescue you from losing a pointer on the Stateful Session Bean that you will create in a Web Service Request. The idea is to bind the Stateful Session Bean to the Session Id in a HashMap.

For Stateful Session Beans, I really prefer to do a programmatic JNDI Lookup to be able to decide :

  • When to create a SFSB
  • When to remove the SFSB

What about if the Session expires? How to remove the SFBS bound to it?

As an idea, you can use the Servlet Annotation @WebListener to keep track of the sessions. Once a session expires you verify any SFSB is bound to that session by searching the HashMap. If yes, you can call the SFSB method annotated by @Remove. In our case it end() method highlighted below.

Singleton Dependency Injection and Stateful Session Lookup

And here we go! The REST Web Service QuizWebService.

As you notice, we annotated QuizWebService by @Stateless to enable Dependency Injection for the Remote Interface of the Singleton IRemotePlayedQuizzesCounter.

The Session Beans are packaged in the WAR ejb3-server-war deployed in the Application Server 1. No EAR package, and No Distinct Deployment Name, this has given as value for JNDI Mapped Name :

  • for the Singleton :

  • for the Stateful Session Bean :