[[EJB_invocations_from_a_remote_server_instance]]
= EJB invocations from a remote server instance

The purpose of this chapter is to demonstrate how to lookup and invoke
on EJBs deployed on an WildFly server instance *from another* WildFly
server instance. This is different from invoking the EJBs
https://docs.jboss.org/author/display/AS71/EJB+invocations+from+a+remote+client+using+JNDI[from
a remote standalone client]

Let's call the server, from which the invocation happens to the EJB, as
"Client Server" and the server on which the bean is deployed as the
"Destination Server".

[NOTE]

Note that this chapter deals with the case where the bean is deployed on
the "Destination Server" but *not* on the "Client Server".

[[application-packaging]]
== Application packaging

In this example, we'll consider a EJB which is packaged in a myejb.jar
which is within a myapp.ear. Here's how it would look like:

[source,java,options="nowrap"]
----
myapp.ear
|
|---- myejb.jar
|        |
|        |---- <org.myapp.ejb.*> // EJB classes
----

[NOTE]

Note that packaging itself isn't really important in the context of this
article. You can deploy the EJBs in any standard way (.ear, .war or
.jar).

[[beans]]
== Beans

In our example, we'll consider a simple stateless session bean which is
as follows:

[source,java,options="nowrap"]
----
package org.myapp.ejb;
 
public interface Greeter {
    
    String greet(String user);
}
----

[source,java,options="nowrap"]
----
package org.myapp.ejb;
 
import javax.ejb.Remote;
import javax.ejb.Stateless;
 
@Stateless
@Remote (Greeter.class)
public class GreeterBean implements Greeter {
 
    @Override
    public String greet(String user) {
        return "Hello " + user + ", have a pleasant day!";
    }
}
----

[[security]]
== Security

WildFly {wildflyVersion} is secure by default. What this means is that no communication
can happen with an WildFly instance from a remote client (irrespective
of whether it is a standalone client or another server instance) without
passing the appropriate credentials. Remember that in this example, our
"client server" will be communicating with the "destination server". So
in order to allow this communication to happen successfully, we'll have
to configure user credentials which we will be using during this
communication. So let's start with the necessary configurations for
this.

[[configuring-a-user-on-the-destination-server]]
== Configuring a user on the "Destination Server"

As a first step we'll configure a user on the destination server who
will be allowed to access the destination server. We create the user
using the `add-user` script that's available in the JBOSS_HOME/bin
folder. In this example, we'll be configuring a `Application User` named
`ejb` and with a password `test` in the `ApplicationRealm`. Running the
`add-user` script is an interactive process and you will see
questions/output as follows:

.add-user

[source,java,options="nowrap"]
----
jpai@jpai-laptop:bin$ ./add-user.sh
 
What type of user do you wish to add?
&nbsp;a) Management User (mgmt-users.properties)
&nbsp;b) Application User (application-users.properties)
(a): b
 
Enter the details of the new user to add.
Realm (ApplicationRealm) :
Username : ejb
Password :
Re-enter Password :
What roles do you want this user to belong to? (Please enter a comma separated list, or leave blank for none)\[&nbsp; \]:
About to add user 'ejb' for realm 'ApplicationRealm'
Is this correct yes/no? yes
Added user 'ejb' to file '/jboss-as-7.1.1.Final/standalone/configuration/application-users.properties'
Added user 'ejb' to file '/jboss-as-7.1.1.Final/domain/configuration/application-users.properties'
Added user 'ejb' with roles to file '/jboss-as-7.1.1.Final/standalone/configuration/application-roles.properties'
Added user 'ejb' with roles to file '/jboss-as-7.1.1.Final/domain/configuration/application-roles.properties'
----

As you can see in the output above we have now configured a user on the
destination server who'll be allowed to access this server. We'll use
this user credentials later on in the client server for communicating
with this server. The important bits to remember are the user we have
created in this example is `ejb` and the password is `test.`

[NOTE]

Note that you can use any username and password combination you want to.

[NOTE]

You do *not* require the server to be started to add a user using the
add-user script.

[[start-the-destination-server]]
== Start the "Destination Server"

As a next step towards running this example, we'll start the
"Destination Server". In this example, we'll use the standalone server
and use the _standalone-full.xml_ configuration. The startup command
will look like:

[source,options="nowrap"]
----
./standalone.sh -server-config=standalone-full.xml
----

Ensure that the server has started without any errors.

[NOTE]

It's very important to note that if you are starting both the server
instances on the same machine, then each of those server instances
*must* have a unique `jboss.node.name` system property. You can do that
by passing an appropriate value for `-Djboss.node.name` system property
to the startup script:

[source,options="nowrap"]
----
./standalone.sh -server-config=standalone-full.xml -Djboss.node.name=<add appropriate value here>
----

[[deploying-the-application]]
== Deploying the application

The application ( _myapp.ear_ in our case) will be deployed to
"Destination Server". The process of deploying the application is out of
scope of this chapter. You can either use the Command Line Interface or
the Admin console or any IDE or manually copy it to
JBOSS_HOME/standalone/deployments folder (for standalone server). Just
ensure that the application has been deployed successfully.

So far, we have built a EJB application and deployed it on the
"Destination Server". Now let's move to the "Client Server" which acts
as the client for the deployed EJBs on the "Destination Server".

[[configuring-the-client-server-to-point-to-the-ejb-remoting-connector-on-the-destination-server]]
== Configuring the "Client Server" to point to the EJB remoting connector
on the "Destination Server"

As a first step on the "Client Server", we need to let the server know
about the "Destination Server"'s EJB remoting connector, over which it
can communicate during the EJB invocations. To do that, we'll have to
add a " _remote-outbound-connection_" to the remoting subsystem on the
"Client Server". The " _remote-outbound-connection_" configuration
indicates that a outbound connection will be created to a remote server
instance from that server. The " _remote-outbound-connection_" will be
backed by a " _outbound-socket-binding_" which will point to a remote
host and a remote port (of the "Destination Server"). So let's see how
we create these configurations.

[[start-the-client-server]]
== Start the "Client Server"

In this example, we'll start the "Client Server" on the same machine as
the "Destination Server". We have copied the entire server installation
to a different folder and while starting the "Client Server" we'll use a
port-offset (of 100 in this example) to avoid port conflicts:

[source,options="nowrap"]
----
./standalone.sh -server-config=standalone-full.xml -Djboss.socket.binding.port-offset=100
----

[[create-a-security-realm-on-the-client-server]]
== Create a security realm on the client server

Remember that we need to communicate with a secure destination server.
In order to do that the client server has to pass the user credentials
to the destination server. Earlier we created a user on the destination
server who'll be allowed to communicate with that server. Now on the
"client server" we'll create a security-realm which will be used to pass
the user information.

In this example we'll use a security realm which stores a Base64 encoded
password and then passes on that credentials when asked for. Earlier we
created a user named `ejb` and password `test`. So our first task here
would be to create the base64 encoded version of the password `test`.
You can use any utility which generates you a base64 version for a
string. I used http://www.base64encode.org/[this online site] which
generates the base64 encoded string. So for the `test` password, the
base64 encoded version is `dGVzdA==`

[TIP]

While generating the base64 encoded string make sure that you don't have
any trailing or leading spaces for the original password. That can lead
to incorrect encoded versions being generated.

[TIP]

With new versions the add-user script will show the base64 password if
you type 'y' if you've been ask

[source,java,options="nowrap"]
----
Is this new user going to be used for one AS process to connect to another AS process e.g. slave domain controller?
----

Now that we have generated that base64 encoded password, let's use in
the in the security realm that we are going to configure on the "client
server". I'll first shutdown the client server and edit the
standalone-full.xml file to add the following in the `<management>`
section

Now let's create a " _security-realm_" for the base64 encoded password.

[source,options="nowrap"]
----
/core-service=management/security-realm=ejb-security-realm:add()
/core-service=management/security-realm=ejb-security-realm/server-identity=secret:add(value=dGVzdA==)
----

[NOTE]

Notice that the CLI show the message _"process-state" =>
"reload-required"_, so you have to restart the server before you can use
this change.

upon successful invocation of this command, the following configuration
will be created in the _management_ section:

.standalone-full.xml

[source,xml,options="nowrap"]
----
<management>
        <security-realms>
            ...
            <security-realm name="ejb-security-realm">
                <server-identities>
                    <secret value="dGVzdA=="/>
                </server-identities>
            </security-realm>
        </security-realms>
...
----

As you can see I have created a security realm named
"ejb-security-realm" (you can name it anything) with the base64 encoded
password. So that completes the security realm configuration for the
client server. Now let's move on to the next step.

[[create-a-outbound-socket-binding-on-the-client-server]]
== Create a outbound-socket-binding on the "Client Server"

Let's first create a _outbound-socket-binding_ which points the
"Destination Server"'s host and port. We'll use the CLI to create this
configuration:

[source,options="nowrap"]
----
/socket-binding-group=standard-sockets/remote-destination-outbound-socket-binding=remote-ejb:add(host=localhost, port=8080)
----

The above command will create a outbound-socket-binding named "
_remote-ejb_" (we can name it anything) 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 on the same machine so we use "localhost")
and the port information should match the http-remoting connector port
used by the EJB subsystem (by default it's 8080). When this command is
run successfully, we'll see that the standalone-full.xml (the file which
we used to start the server) was updated with the following
outbound-socket-binding in the socket-binding-group:

[source,xml,options="nowrap"]
----
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
        ...
        <outbound-socket-binding name="remote-ejb">
            <remote-destination host="localhost" port="8080"/>
        </outbound-socket-binding>
    </socket-binding-group>
----

[[create-a-remote-outbound-connection-which-uses-this-newly-created-outbound-socket-binding]]
== Create a "remote-outbound-connection" which uses this newly created
"outbound-socket-binding"

Now let's create a " _remote-outbound-connection_" which will use the
newly created outbound-socket-binding (pointing to the EJB remoting
connector of the "Destination Server"). We'll continue to use the CLI to
create this configuration:

[source,options="nowrap"]
----
/subsystem=remoting/remote-outbound-connection=remote-ejb-connection:add(outbound-socket-binding-ref=remote-ejb, protocol=http-remoting, security-realm=ejb-security-realm, username=ejb)
----

The above command creates a remote-outbound-connection, named "
_remote-ejb-connection_" (we can name it anything), in the remoting
subsystem and uses the previously created " _remote-ejb_"
outbound-socket-binding (notice the outbound-socket-binding-ref in that
command) 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 we have set the username
attribute to use the user name who is allowed to communicate with the
destination server.

What this step does is, it creates a outbound connection, on the client
server, to the remote destination server and sets up the username to the
user who allowed to communicate with that destination server and 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 setup a successful
secured connection.

Now let's run the following two operations to set some default
connection creation options for the outbound connection:

[source,options="nowrap"]
----
/subsystem=remoting/remote-outbound-connection=remote-ejb-connection/property=SASL_POLICY_NOANONYMOUS:add(value=false)
----

[source,options="nowrap"]
----
/subsystem=remoting/remote-outbound-connection=remote-ejb-connection/property=SSL_ENABLED:add(value=false)
----

Ultimately, upon successful invocation of this command, the following
configuration will be created in the remoting subsystem:

[source,xml,options="nowrap"]
----
<subsystem xmlns="urn:jboss:domain:remoting:1.1">
....
            <outbound-connections>
                <remote-outbound-connection name="remote-ejb-connection" outbound-socket-binding-ref="remote-ejb" protocol="http-remoting" security-realm="ejb-security-realm" username="ejb">
                    <properties>
                        <property name="SASL_POLICY_NOANONYMOUS" value="false"/>
                        <property name="SSL_ENABLED" value="false"/>
                    </properties>
                </remote-outbound-connection>
            </outbound-connections>
        </subsystem>
----

From a server configuration point of view, that's all we need on the
"Client Server". Our next step is to deploy an application on the
"Client Server" which will invoke on the bean deployed on the
"Destination Server".

[[packaging-the-client-application-on-the-client-server]]
== Packaging the client application on the "Client Server"

Like on the "Destination Server", we'll use .ear packaging for the
client application too. But like previously mentioned, that's not
mandatory. You can even use a .war or .jar deployments. Here's how our
client application packaging will look like:


----
client-app.ear
|
|--- META-INF
|        |
|        |--- jboss-ejb-client.xml
|
|--- web.war
|        |
|        |--- WEB-INF/classes
|        |        |
|        |        |---- <org.myapp.FooServlet> // classes in the web app
----

In the client application we'll use a servlet which invokes on the bean
deployed on the "Destination Server". We can even invoke the bean on the
"Destination Server" from a EJB on the "Client Server". The code remains
the same (JNDI lookup, followed by invocation on the proxy). The
important part to notice in this client application is the file
_jboss-ejb-client.xml_ which is packaged in the META-INF folder of a top
level deployment (in this case our client-app.ear). This
_jboss-ejb-client.xml_ contains the EJB client configurations which will
be used during the EJB invocations for finding the appropriate
destinations (also known as, EJB receivers). The contents of the
jboss-ejb-client.xml are explained next.

[NOTE]

If your application is deployed as a top level .war deployment, then the
jboss-ejb-client.xml is expected to be placed in .war/WEB-INF/ folder
(i.e. the same location where you place any web.xml file).

[[contents-on-jboss-ejb-client.xml]]
== Contents on jboss-ejb-client.xml

The jboss-ejb-client.xml will look like:

[source,xml,options="nowrap"]
----
<jboss-ejb-client xmlns="urn:jboss:ejb-client:1.0">
    <client-context>
        <ejb-receivers>
            <remoting-ejb-receiver outbound-connection-ref="remote-ejb-connection"/>
        </ejb-receivers>
    </client-context>
</jboss-ejb-client>
----

You'll notice that we have configured the EJB client context (for this
application) to use a remoting-ejb-receiver which points to our earlier
created " _remote-outbound-connection_" named "
_remote-ejb-connection_". This links the EJB client context to use the "
_remote-ejb-connection_" which ultimately points to the EJB remoting
connector on the "Destination Server".

[[deploy-the-client-application]]
== Deploy the client application

Let's deploy the client application on the "Client Server". The process
of deploying the application is out of scope, of this chapter. You can
use either the CLI or the admin console or a IDE or deploy manually to
JBOSS_HOME/standalone/deployments folder. Just ensure that the
application is deployed successfully.

[[client-code-invoking-the-bean]]
== Client code invoking the bean

We mentioned that we'll be using a servlet to invoke on the bean, but
the code to invoke the bean isn't servlet specific and can be used in
other components (like EJB) too. So let's see how it looks like:

[source,java,options="nowrap"]
----
import javax.naming.Context;
import java.util.Hashtable;
import javax.naming.InitialContext;
 
...
public void invokeOnBean() {
        try {
            final Hashtable props = new Hashtable();
            // setup the ejb: namespace URL factory
            props.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
            // create the InitialContext
            final Context context = new javax.naming.InitialContext(props);
 
            // Lookup the Greeter bean using the ejb: namespace syntax which is explained here https://docs.jboss.org/author/display/AS71/EJB+invocations+from+a+remote+client+using+JNDI
            final Greeter bean = (Greeter) context.lookup("ejb:" + "myapp" + "/" + "myejb" + "/" + "" + "/" + "GreeterBean" + "!" + org.myapp.ejb.Greeter.class.getName());
 
   // invoke on the bean
   final String greeting = bean.greet("Tom");
 
            System.out.println("Received greeting: " + greeting);
 
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
}
----

That's it! The above code will invoke on the bean deployed on the
"Destination Server" and return the result.

NOTE: References in this document to Enterprise JavaBeans(EJB) refer to the Jakarta Enterprise Beans unless otherwise noted.
