[wildfly-dev] New JNDI-based remote service API (for EJB etc.)
David M. Lloyd
david.lloyd at redhat.com
Mon Jan 20 23:19:20 EST 2014
We've been having some discussions around improving the way that the EJB
invocation API looks, feels, and behaves to produce smaller, simpler,
and perhaps more "expected" code for more common cases. I'm going to
outline some of the design points here so that everyone knows what's
coming and has a chance to ask questions.
Part 1: JNDI API
----------------
Right now connection management is accomplished via a mishmash of APIs
from different client libraries. In most cases the connections are
automatically "managed", but in different ways, and such that each
client really cannot interact with each other.
From the user's perspective, this is really not desirable. Most users
are, for better or worse, expecting to use an API like JNDI to establish
and maintain their connection to the remote system. So the first idea
here is to encapsulate all common Remoting-based services into a single
JNDI context. The user should be able to do something like this:
Hashtable env = new Hashtable();
env.put(Context.PROVIDER_URL, "remote+http://myserver.com:8080");
...couple other properties here...
InitialContext c = new InitialContext(env);
Now 'c' is a useful server connection that can be used for various
services. These services would include remote transaction control:
UserTransaction ut = (UserTransaction) c.lookup("UserTransaction");
Remote authentication/authorization:
SomeLoginContextLike lc = (...) c.lookup("AuthenticationService");
lc.login(subject, ...);
subject.doAs(...{
...do stuff...
});
Remote JNDI:
Context rc = (Context) c.lookup("RemoteNaming");
And of course EJBs:
MyEJBRemote rem = (MyEJBRemote)
c.lookup("EJB/MyApp/MyModule/MyEJB!com.mycom.MyEJB");
Please note that none of these JNDI names or APIs are final, just examples.
Once these services use a common infrastructure, a couple of things
become possible:
1) The services shared among a connection can work together more
effectively; for example, a UserTransaction can encapsulate all services
running over that connection, rather than just EJBs. Likewise for the
upcoming authentication service.
2) This API can be expanded to cover transport protocols other than
Remoting-based protocols for use cases in which a single persistent
connection is not the best option.
Part 2: Connection Management
-----------------------------
By using a URI as the connection destination, we can have one unified
configuration infrastructure for connection establishment. We can also
potentially cache and reuse connections with the same URI. In this
case, the user would not need to close the initial context; it could be
maintained indefinitely or closed after a configurable "idle" interval.
Configuration could be set up in a properties file for simple clients.
However there will also (often) be cases where the user simply wants to
establish a connection programmatically in the InitialContext
environment. To support this use case, a context will also be able to
be configured in this way (though there is still a little bit of
figuring out to do to work out a way that won't result in weird behavior
if this method is used when there is also an external configuration).
Part 3: Connection Authentication
---------------------------------
In order for connection reuse to work in the presence of multiple
identities (and make various other things nicer, as an aside), we need
to create a separate concept of connection authentication, to avoid the
situation where we ask for a connection as user A and get user B's
connection instead, or a situation where a user feels they must make one
connection per identity. Thus we need a separate client authentication
context and configuration method to determine the client authentication
method and credentials to use for the connection itself.
Once a connection is established, the authentication service on that
connection can be used to switch between authenticated identities. The
connection itself need only authenticate to an identity which has
adequate authorization to switch to, or authenticate as, those
identities. On the other hand, for simple cases, the client might only
need one identity: in this case the authentication service need not be
used; instead the client authentication context would be set up to
authenticate the desired user from the outset, and no other identity
would be established during its usage.
To switch identities, the user would have to acquire some type of
JAAS-like login context and authenticate a JAAS-like subject with it.
Then the user would use a typical "doAs"-style construct to perform some
body of work as that identity. This will be the subject (!) of a
different email.
Again, there will be cases where an external configuration for this
purpose will be too heavy-handed for the specific use case; in this case
we should allow an environment-based configuration mode.
Part 4: EJB Proxy Behavior
--------------------------
An EJB proxy which was acquired from this sort of connection can attain
an association to the remote system by URI. The identifying
characteristic of the proxy would then be: view type, URI, application
name, module name, EJB name. The 'distinct name' concept will no longer
be necessary and could possibly be deprecated if there is no remaining
use case for it.
The URI is significant primarily when the proxy is realized in a new
context. When the proxy is invoked upon for the first time, it must be
associated with a connection to the target system. The information in
the URI must therefore be sufficient to establish such a connection and
register it with the connection cache in order to allow such proxies to
be useful.
This is simple in the case of a URL; if a proxy is deserialized in an
unknown context, the URL plus any environment security settings may be
used to establish a new connection to allow the proxy to be invoked upon
again automatically (without compromising security in any way).
However on the negative side, if a URL is used for the URI, the URL may
not be valid after deserialization across certain types of NAT
configuration. This is a very real problem in some environments. In
order to mitigate this problem, a discovery mechanism is introduced.
Part 5: Discovery
-----------------
It will be possible for more advanced environments to utilize a URN
instead of a URL for connection establishment. The benefit of doing
this is that the URN given can be resolved in a location-specific
manner. A proxy with a URN of, say, "node:usa-1" might use a discovery
protocol to locate a node named "usa-1", find a URL that can be used to
connect, and establish and maintain the connection automatically. An
EJB proxy associated with this URN may be serialized and deserialized in
a completely different network environment, and the URN may still be
used (but resolved in a different manner) allowing the proxy (and its
connection) to continue to function.
The discovery mechanism should be pluggable to allow support for cloud
environments and potentially the Service Location Protocol (SLP, RFC
2608) for data center environments. Other schemes may be introduced
which do simple name-to-DNS-name mappings or other such simple schemes.
Part 6: Compatibility
---------------------
EJB Proxies acquired using the existing AS 7/WildFly 8 EJB API should
map the EJB locator information to a locator which is compatible with
the URI scheme given here, and vice versa, so that there is a seamless
migration path between old and new location schemes.
The wire protocol should also be made compatible so that old clients
will continue to function against new servers (and the reverse as well,
if possible).
--
- DML
More information about the wildfly-dev
mailing list