[[Scoped_EJB_client_contexts]]
= Scoped EJB client contexts

ifdef::env-github[]
:tip-caption: :bulb:
:note-caption: :information_source:
:important-caption: :heavy_exclamation_mark:
:caution-caption: :fire:
:warning-caption: :warning:
endif::[]

[abstract]

WildFly {wildflyVersion} introduced the EJB client API for managing remote EJB
invocations. The EJB client API works off EJBClientContext(s). An
EJBClientContext can potentially contain any number of EJB receivers. An
EJB receiver is a component which knows how to communicate with a server
which is capable of handling the EJB invocation. Typically EJB remote
applications can be classified into:

* A remote client which runs as a standalone Java application
* A remote client which runs within another WildFly {wildflyVersion} instance

Depending on the kind of remote client, from an EJB client API point of
view, there can potentially be more than 1 EJBClientContext(s) within a
JVM.

In case of standalone applications, typically a single EJBClientContext
(backed by any number of EJB receivers) exists. However this isn't
mandatory. Certain standalone applications can potentially have more
than one EJBClientContext(s) and an EJB client context selector will be
responsible for returning the appropriate context.

In case of remote clients which run within another WildFly {wildflyVersion} instance,
each deployed application will have a corresponding EJB client context.
Whenever that application invokes on another EJB, the corresponding EJB
client context will be used for finding the right EJB receiver and
letting it handle the invocation.

[[potential-shortcomings-of-a-single-ejb-client-context]]
== Potential shortcomings of a single EJB client context

In the Overview section we briefly looked at the different types of
remote clients. Let's focus on the standalone remote clients (the ones
that don't run within another WildFly {wildflyVersion} instance) for some of the next
sections. Like mentioned earlier, typically a remote standalone client
has just one EJB client context backed by any number of EJB receivers.
Consider this example:

[source,java,options="nowrap"]
----
public class MyApplication {
 
    public static void main(String args[]) {
 
        final javax.naming.Context ctxOne = new javax.naming.InitialContext();
        final MyBeanInterface beanOne = ctxOne.lookup("ejb:app/module/distinct/bean!interface");
        beanOne.doSomething();
        ...
    }
}
----

Now, we have seen in this other chapter
https://docs.jboss.org/author/display/WFLY8/EJB+invocations+from+a+remote+client+using+JNDI[EJB
invocations from a remote client using JNDI] that the JNDI lookups are
(typically) backed by jboss-ejb-client.properties file which is used to
setup the EJB client context and the EJB receivers. Let's assume we have
a jboss-ejb-client.properties with the relevant receivers
configurations. These configurations include the security credentials
that will be used to create an EJB receiver which connects to the AS7
server. Now when the above code is invoked, the EJB client API looks for
the EJB client context to pick an EJB receiver, to pass on the EJB
invocation request. Since we just have a single EJB client context, that
context is used by the above code to invoke the bean.

Now let's consider a case where the user application wants to invoke on
the bean more than once, but wants to connect to the WildFly {wildflyVersion} server
using different security credentials. Let's take a look at the following
code:

[source,java,options="nowrap"]
----
public class MyApplication {
 
    public static void main(String args[]) {
 
        // let's say we want to use "foo" security credential while connecting to the AS7 server for invoking on this bean instance
        final javax.naming.Context ctxOne = new javax.naming.InitialContext();
        final MyBeanInterface beanOne = ctxOne.lookup("ejb:app/module/distinct/bean!interface");
        beanOne.doSomething();
        ...
 
        // let's say we want to use "bar" security credential while connecting to the AS7 server for invoking on this bean instance
        final javax.naming.Context ctxTwo = new javax.naming.InitialContext();
        final MyBeanInterface beanTwo = ctxTwo.lookup("ejb:app/module/distinct/bean!interface");
        beanTwo.doSomething();
        ...
 
    }
}
----

So we have the same application, which wants to connect to the same
server instance for invoking the EJB(s) hosted on that server, but wants
to use two different credentials while connecting to the server.
Remember, the client application has a single EJB client context which
can have atmost 1 EJB receiver for each server instance. Which
effectively means that the above code will end up using just one
credential to connect to the server. So there was no easy way to have
the above code working.

That was one of the use cases which prompted the
https://issues.redhat.com/browse/EJBCLIENT-34 feature request. The
proposal was to introduce a way, where you can have more control over
the EJB client contexts and their association with JNDI contexts which
are typically used for EJB invocations.

[[scoped-ejb-client-contexts]]
== Scoped EJB client contexts

Developers familiar with earlier versions of JBoss AS would remember
that for invoking an EJB, you would typically create a JNDI context
passing it the PROVIDER_URL which would point to the target server. That
way any invocation is done on EJB proxies looked up using that JNDI
context, would end up on that server. If we look back at the example
above, we'll realize that, we are ultimately aiming for a similar
functionality through https://issues.redhat.com/browse/EJBCLIENT-34. We
want the user applications to have more control over which EJB receiver
gets used for a specific invocation.

Before we introduced https://issues.redhat.com/browse/EJBCLIENT-34
feature, the EJB client context was typically scoped to the client
application. As part of https://issues.redhat.com/browse/EJBCLIENT-34 we
now allow the EJB client contexts to be scoped with the JNDI contexts.
Consider the following example:

[source,java,options="nowrap"]
----
public class MyApplication {
 
    public static void main(String args[]) {
 
        // let's say we want to use "foo" security credential while connecting to the AS7 server for invoking on this bean instance
        final Properties ejbClientContextPropsOne = getPropsForEJBClientContextOne():
        final javax.naming.Context ctxOne = new javax.naming.InitialContext(ejbClientContextPropsOne);
        final MyBeanInterface beanOne = ctxOne.lookup("ejb:app/module/distinct/bean!interface");
        beanOne.doSomething();
        ...
        closeContext(ctxOne); // read on the entire article to understand more about closing scoped EJB client contexts
 
        // let's say we want to use "bar" security credential while connecting to the AS7 server for invoking on this bean instance
        final Properties ejbClientContextPropsTwo = getPropsForEJBClientContextTwo():
        final javax.naming.Context ctxTwo = new javax.naming.InitialContext(ejbClientContextPropsTwo);
        final MyBeanInterface beanTwo = ctxTwo.lookup("ejb:app/module/distinct/bean!interface");
        beanTwo.doSomething();
        ...
        closeContext(ctxTwo); // read on the entire article to understand more about closing scoped EJB client contexts
    }
}
----

Notice any difference between this code and the earlier one? We now
create and pass EJB client context specific properties to the JNDI
context. So what do the EJB client context properties look like? The
properties are the same that you would pass through the
jboss-ejb-client.properties file, except for one additional property
which is required to scope the EJB client context to the JNDI context.
The name of the property is:

`org.jboss.ejb.client.scoped.context`

which is expected to have a value true. This property lets the EJB
client API know that it has to created an EJB client context (backed by
EJB receiver(s)) and that created context is then scoped/visible to only
that JNDI context which created it. Lookup and invocation on any EJB
proxies looked up using this JNDI context will only know of the EJB
client context associated with this JNDI context. This effectively means
that the other JNDI contexts which the application uses to lookup and
invoke on EJBs will _not_ know about the other scoped EJB client
contexts at all.

JNDI contexts which aren't scoped to a EJB client context (for example,
not passing the org.jboss.ejb.client.scoped.context property) will
fallback to the default behaviour of using the "current" EJB client
context which typically is the one tied to the entire application.

This scoping of the EJB client context helps the user applications to
have more control over which JNDI context "talks to" which server and
connects to that server in "what way". This gives the user applications
the flexibility that was associated with the JNP based JNDI invocations
prior to WildFly {wildflyVersion} versions.

[NOTE]

*IMPORTANT:* *It is very important to remember that scoped EJB client
contexts which are scoped to the JNDI contexts are NOT fire and forget
kind of contexts. What that means is the application program which is
using these contexts is solely responsible for managing their lifecycle
and the application itself is responsible for closing the context at the
right moment. After closing the context the proxies which are bound to
this context are no longer valid and any invocation will throw an
Exception. Not closing the context will end in resource problems as the
underlying physical connection will stay open.*

*Read the rest of the sections in this article to understand more about
the lifecycle management of such scoped contexts.*

[[lifecycle-management-of-scoped-ejb-client-contexts]]
== Lifecycle management of scoped EJB client contexts

Like you saw in the previous sections, in case of scoped EJB client
contexts, the EJB client context is tied to the JNDI context. It's very
important to understand how the lifecycle of the EJB client context
works in such cases. Especially since any EJB client context is almost
always backed by connections to the server. Not managing the EJB client
context lifecycle correctly can lead to connection leaks in some cases.

When you create a scoped EJB client context, the EJB client context
connects to the server(s) listed in the JNDI properties. An internal
implementation detail of this logic includes the ability of the EJB
client context to cache connections based on certain internal algorithm
it uses. The algorithm itself isn't publicly documented (yet) since the
chances of it changing or even removal shouldn't really affect the
client application and instead it's supposed to be transparent to the
client application.

The connections thus created for an EJB client context are kept open as
long as the EJB client context is open. This allows the EJB client
context to be usable for EJB invocations. The connections associated
with the EJB client context are closed when the EJB client context
itself is closed.

[NOTE]

The connections that were manually added by the application to the EJB
client context are *not* managed by the EJB client context. i.e. they
won't be opened (obviously) nor closed by the EJB client API when the
EJB client context is closed.

[[how-to-close-ejb-client-contexts]]
=== How to close EJB client contexts?

The answer to that is simple. Use the close() method on the appropriate
EJB client context.

[[how-to-close-scoped-ejb-client-contexts]]
=== How to close scoped EJB client contexts?

The answer is the same, use the close() method on the EJB client
context. But the real question is how do you get the relevant scoped EJB
client context which is associated with a JNDI context. Before we get to
that, it's important to understand how the ejb: JNDI namespace that's
used for EJB lookups and how the JNDI context (typically the
InitialContext that you see in the client code) are related. The JNDI
API provided by Java language allows "URL context factory" to be
registered in the JNDI framework (see this for details
http://docs.oracle.com/javase/jndi/tutorial/provider/url/factory.html).
Like that documentation states, the URL context factory can be used to
resolve URL strings during JNDI lookup. That's what the ejb: prefix is
when you do a remote EJB lookup. The ejb: URL string is backed by a URL
context factory.

Internally, when a lookup happens for a ejb: URL string, a relevant
javax.naming.Context is created for that ejb: lookup. Let's see some
code for better understanding:

[source,java,options="nowrap"]
----
// JNDI context "A"
Context jndiCtx = new InitialContext(props);
// Now let's lookup a EJB
MyBean bean = jndiCtx.lookup("ejb:app/module/distinct/bean!interface");
----

So we first create a JNDI context and then use it to lookup an EJB. The
bean lookup using the ejb: JNDI name, although, is just one statement,
involves a few more things under the hood. What's actually happening
when you lookup that string is that a separate javax.naming.Context gets
created for the ejb: URL string. This new javax.naming.Context is then
used to lookup the rest of the string in that JNDI name.

Let's break up that one line into multiple statements to understand
better:

[source,java,options="nowrap"]
----
// Remember, the ejb: is backed by a URL context factory which returns a Context for the ejb: URL (that's why it's called a context factory)
final Context ejbNamingContext = (Context) jndiCtx.lookup("ejb:");
// Use the returned EJB naming context to lookup the rest of the JNDI string for EJB
final MyBean bean = ejbNamingContext.lookup("app/module/distinct/bean!interface");
----

As you see above, we split up that single statement into a couple of
statements for explaining the details better. So as you can see when the
ejb: URL string is parsed in a JNDI name, it gets hold of a
javax.naming.Context instance. This instance is different from the one
which was used to do the lookup (jndiCtx in this example). This is an
important detail to understand (for reasons explained later). Now this
returned instance is used to lookup the rest of the JNDI string
("app/module/distinct/bean!interface"), which then returns the EJB
proxy. Irrespective of whether the lookup is done in a single statement
or multiple parts, the code works the same. i.e. an instance of
javax.naming.Context gets created for the ejb: URL string.

So why am I explaining all this when the section is titled
`"How to close scoped EJB client contexts"`? The reason is because
client applications dealing with scoped EJB client contexts which are
associated with a JNDI context would expect the following code to close
the associated EJB client context, but will be surprised that it won't:

[source,java,options="nowrap"]
----
final Properties props = new Properties();
// mark it for scoped EJB client context
props.put("org.jboss.ejb.client.scoped.context","true");
// add other properties
props.put(....);
...
Context jndiCtx = new InitialContext(props);
try {
      final MyBean bean = jndiCtx.lookup("ejb:app/module/distinct/bean!interface");
      bean.doSomething();
} finally {
  jndiCtx.close();
}
----

Applications expect that the call to jndiCtx.close() will effectively
close the EJB client context associated with the JNDI context. That
doesn't happen because as explained previously, the javax.naming.Context
backing the ejb: URL string is a different instance than the one the
code is closing. The JNDI implementation in Java, only just closes the
context on which the close was called. As a result, the other
javax.naming.Context that backs the ejb: URL string is still not closed,
which effectively means that the scoped EJB client context is not closed
too which then ultimately means that the connection to the server(s) in
the EJB client context are not closed too.

So now let's see how this can be done properly. We know that the ejb:
URL string lookup returns us a javax.naming.Context. All we have to do
is keep a reference to this instance and close it when we are done with
the EJB invocations. So here's how it's going to look:

[source,java,options="nowrap"]
----
final Properties props = new Properties();
// mark it for scoped EJB client context
props.put("org.jboss.ejb.client.scoped.context","true");
// add other properties
props.put(....);
...
Context jndiCtx = new InitialContext(props);
Context ejbRootNamingContext = (Context) jndiCtx.lookup("ejb:");
try {
    final MyBean bean = ejbRootNamingContext.lookup("app/module/distinct/bean!interface"); // the rest of the EJB jndi string
    bean.doSomething();
} finally {
    try {
        // close the EJB naming JNDI context
        ejbRootNamingContext.close();
    } catch (Throwable t) {
        // log and ignore
    }
    try {
        // also close our other JNDI context since we are done with it too
        jndiCtx.close();
    } catch (Throwable t) {
        // log and ignore
    }
 
}
----

As you see, we changed the code to first do a lookup on just the "ejb:"
string to get hold of the EJB naming context and then used that
ejbRootNamingContext instance to lookup the rest of the EJB JNDI name to
get hold of the EJB proxy. Then when it was time to close the context,
we closed the ejbRootNamingContext (as well as the other JNDI context).
Closing the ejbRootNamingContext ensures that the scoped EJB client
context associated with that JNDI context is closed too. Effectively,
this closes the connection(s) to the server(s) within that EJB client
context.

[[can-that-code-be-simplified-a-bit]]
==== Can that code be simplified a bit?

If you are using that JNDI context only for EJB invocations, then yes
you can get rid of some instances and code from the above code. You can
change that code to:

[source,java,options="nowrap"]
----
final Properties props = new Properties();
// mark it for scoped EJB client context
props.put("org.jboss.ejb.client.scoped.context","true");
// add other properties
props.put(....);
...
Context ejbRootNamingContext = (Context) new InitialContext(props).lookup("ejb:");
try {
    final MyBean bean = ejbRootNamingContext.lookup("app/module/distinct/bean!interface"); // the rest of the EJB jndi string
    bean.doSomething();
} finally {
    try {
        // close the EJB naming JNDI context
        ejbRootNamingContext.close();
    } catch (Throwable t) {
        // log and ignore
    }
}
----

Notice that we no longer hold a reference to 2 JNDI contexts and instead
just keep track of the ejbRootNamingContext which is actually the root
JNDI context for our "ejb:" URL string. Of course, this means that you
can only use this context for EJB lookups or any other EJB related JNDI
lookups. So it depends on your application and how it's coded.

[[cant-the-scoped-ejb-client-context-be-automatically-closed-by-the-ejb-client-api-when-the-jndi-context-is-no-longer-in-scope-i.e.-on-gc]]
=== Can't the scoped EJB client context be automatically closed by the
EJB client API when the JNDI context is no longer in scope (i.e. on GC)?

That's one of the common questions that gets asked. No, the EJB client
API can't take that decision. i.e. it cannot automatically go ahead and
close the scoped EJB client context by itself when the associated JNDI
context is eligible for GC. The reason is simple as illustrated by the
following code:

[source,java,options="nowrap"]
----
void doEJBInvocation() {
    final MyBean bean = lookupEJB();
    bean.doSomething();
    bean.doSomeOtherThing();
    ... // do some other work
    bean.keepDoingSomething();
}
 
MyBean lookupEJB() {
    final Properties props = new Properties();
    // mark it for scoped EJB client context
    props.put("org.jboss.ejb.client.scoped.context","true");
    // add other properties
    props.put(....);
    ...
    Context ejbRootNamingContext = (Context) new InitialContext(props).lookup("ejb:");
    final MyBean bean = ejbRootNamingContext.lookup("app/module/distinct/bean!interface"); // rest of the EJB jndi string
    return bean;
}
----

As you can see, the doEJBInvocation() method first calls a lookupEJB()
method which does a lookup of the bean using a JNDI context and then
returns the bean (proxy). The doEJBInvocation() then uses that returned
proxy and keeps doing the invocations on the bean. As you might have
noticed, the JNDI context that was used for lookup (i.e. the
ejbRootNamingContext) is eligible for GC. If the EJB client API had
closed the scoped EJB client context associated with that JNDI context,
when that JNDI context was garbage collected, then the subsequent EJB
invocations on the returned EJB (proxy) would start failing in
doEJBInvocation() since the EJB client context is no longer available.

That's the reason why the EJB client API doesn't automatically close the
EJB client context.

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