[jboss-as7-dev] EJB Remote client design

David M. Lloyd david.lloyd at redhat.com
Fri Sep 16 11:09:14 EDT 2011


On 09/16/2011 08:14 AM, Carlo de Wolf wrote:
> On 09/15/2011 05:50 AM, David M. Lloyd wrote:
>> Okay so after a bunch of discussion with various personages, it looks
>> like we have some remote EJB client design shaken out. Please read
>> through a couple times to make sure you have gotten a clear
>> understanding to avoid questions that are already answered here.
>>
>> Client API
>> ----------
>>
>> We'll introduce a concept of an "EJB invocation receiver" or "EJB
>> receiver" for short. The job of this fellow is to receive invocations
>> on behalf of a connection to a peer or a cluster or locally. So for the
>> Remoting transport, there is a 1:1 correspondence between connections
>> and EJB receivers.
>>
>> Multiple EJB receivers can be collected up into a single "EJB client
>> context", each with a "preference" level. Same-VM receivers will
>> typically have a higher preference than remote receivers.
>
> The scheduling of these contexts must take care not to starve the lower
> preferred levels.

In the same-VM case, starvation is exactly what we want in most cases. 
The idea is to apply a policy wherein the same connection type is used 
whenever possible.  I have yet to come up with a good set of heuristics 
which would accomplish this other than simply preferring one type over 
another.

>> An EJB remote proxy (and by extension, its Handle) identify their EJB by
>> the combination of application name, module name, "distinct" name, and
>> bean name. All of the equals()-type operations that are specified by
>> EJB are implemented in terms of this basic level of equivalence (though
>> some types have additional criteria, like SFSB using session ID as
>> well). There is no notion of a specific server address or URI in a
>> proxy or handle.
>
> Definitely not a server address (or anything like that). An URI might
> have a different meaning, see below.

Yeah but URIs are clumsy to handle.  There's really no good reason to 
use them.

>> The "distinct" name is an _optional_ name which can be associated with a
>> deployment (by deployment descriptor, and possibly also by
>> configuration) in the event that two different deployments which are
>> visible from one client have the same application and module name.
>> (Yes, I know you can't have two deployments with the same app+module
>> name in one server; however, a client can "see" more than one server at
>> once and may need to distinguish, especially if the user does not
>> control the name of the deployment.)
>
> An EJB client can at any point start communication with another server.
> That other server can have the same set of EJBs. So having an "distinct"
> name is not optional and needs to be in the proxy. It identifies the
> client context to use over which the invocation needs take place. The
> identification of the client context could be an URI (I don't see why not).

Yes the possibility of the same-named deployment existing on multiple 
servers is the reason why the deployer (human) should have the option to 
disambiguate it on the server if necessary.  If it's the *same* EJB JAR 
on both servers though, then they do not need to be disambiguated one 
from the other.  The distinct name is optional, but if it is not present 
in the proxy then only deployments without a distinct name will receive 
the invocations.  In other words, empty doesn't mean "match all".

>> Each EJB receiver has an obligation to keep the EJB client context
>> updated with the list of module identities that it can access. When a
>> proxy is invoked upon, the EJB client context uses this table to select
>> the destination. This means that for the Remoting protocol for example,
>> the server sends back messages informing the client of changes in
>> deployment status (which should be relatively infrequent) as well as
>> sending an initial summary of what modules are available.
>
> This doesn't scale up. If there are 10K EJBs deployed a client is rarely
> interested in more than 5%, just the EJBs it invokes upon. Nor do we
> want to send an update of 1K+ EJBs to every client connected on each
> status change.

Sure it does.  We're not sending a list of EJBs.  We're sending a list 
of *module names*.  Even if you had a thousand EJB deployments it 
wouldn't be that large of a list.

>> Most client interceptors are associated with both an EJB client context
>> and a receiver type. This is because things like transactions,
>> security, etc. will vary in their implementation based upon the protocol
>> in use.
>>
>> We _may_ support protocol-independent interceptors, however we'll have
>> to evaluate use cases first. If we do then most likely they'd work with
>> a protocol-dependent counterpart; for example, a general security
>> interceptor might attach additional principal information to the
>> invocation in a standard spot, which the protocol-specific interceptor
>> might then publish to the server (or not).
>
> Maybe it is possible to use Externalizable as the protocol-independent
> contract?
> The only requirement here is backwards compatibility, not?

It would be nice to have a byte layout for these things outside of 
serialization; otherwise, your marshalling strategy becomes limited to 
things which can serialize any arbitrary object.  Attaching a block of 
bytes would be language-agnostic if you're using a multi-language 
serialization format.

> JBossPrincipal -> Principal10 -> bits -> Principal10 -> JBossPrincipal
> Where the JBossPrincipal -> Principal10 transformation is done by a
> specific interceptor.
>> An invocation on a remote proxy will use whatever EJB client context is
>> current for the calling thread. Thus remote proxies and handles can be
>> passed from one context to another (directly or via cloning or
>> serialization) without any special action being taken. If no EJB client
>> context is available, remote invocation will fail immediately.
>>
>> Remote Async Invocation
>> -----------------------
>>
>> Any Session Bean remote interface method which returns a Future will
>> always be treated as asynchronous by the client. Methods which return
>> void but are visibly (to the client) marked with the appropriate
>> annotation will be treated as asynchronous. Other methods which return
>> void will not be automatically treated as asynchronous, though the
>> server protocol allows for a message to come back to inform the client
>> that the invocation will proceed asynchronously.
>
> A method is only asynchronous if designated as such. (EJB 3.1 FR 4.5.1)
> This is independent of the return type.

The client cannot know whether it was designated as such, since the 
designation may be on the DD (also 4.5.1) which may not be visible to 
the client.  So whatever means we have to determine this fact we should 
utilize.  If there is a case where a non-async method legitimately could 
return Future, then we can skip this trick.  Also, see below...

>> If the client knows that a method is asynchronous or wants to call a
>> void method asynchronously, it may use a static API method to acquire an
>> asynchronous "view" of that interface so that all calls to void methods
>> proceed asynchronously:
>>
>> myProxy.theVoidMethod(); // called sync unless the server unblocks
>> EJB.async(myProxy).theVoidMethod(); // called async always
>>
>> This cannot be solved any other way as the client might not have access
>> to the EJB metadata which specifies whether the method is asynchronous.
>
> The underlying protocol is asynchronous regardless of any method
> metadata. So the client is more or less always faced with a decision to
> process async or sync. Or so you want to add a pre-result packet?
>
> You also need the divine methods (see
> http://java.net/jira/browse/EJB_SPEC-11).

You're saying "yeah the method was declared synchronously on the server 
but that *should* be the client's decision", which is one step farther 
than I have taken it.  I'm merely stopping at allowing the user to 
invoke a method asynchronously which was actually declared to be 
asynchronous.

If you want to go this route though, I think it should just be rolled 
right in to the same EJB client static class that we use for everything 
else.

I just want to be sure that if the user invokes a method which was 
declared async, that they get their as close to their expected behavior 
as possible, without *forcing* them to use the async wrapper stuff.

>> Client JNDI
>> -----------
>>
>> Client JNDI is just a simple in-memory JNDI implementation. We will not
>> automatically bind anything to it at all, except in two possible cases:
>> 1. A simple configuration file which describes what to bind, or 2. A
>> configuration instructing a binding list to be fetched from somewhere.
>>
>> Clients running in an AS7 instance or in an AS7 application client
>> container will be using our server JNDI implementation which supports
>> injection, not the client JNDI implementation, which is reserved for
>> truly standalone clients.
>>
>> Server Implementation
>> ---------------------
>>
>> The EE subsystem already contains most of the required APIs for handling
>> remote invocations. Any remotely accessible ComponentView will be
>> registered with the remote invocation service along with its
>> app/module/distinctName identification.
>>
>> A special in-VM EJB receiver will also exist and will be similarly
>> updated with the current available component views and their modules.
>>
>> Management configurations will be introduced for the purpose of
>> establishing and maintaining Remoting connections to remote servers.
>>
>> EJB client contexts should be created for each deployment, and a
>> deployment descriptor should be made available to any EE deployment for
>> the purpose of associating Remoting connections (and probably clusters
>> etc.) with the EJB client context for that EE module. This allows each
>> deployment to specify what remote servers it can "see", while still
>> keeping the network configuration business in the central management
>> model.
>>
>> All deployments on the server which have an EE client context will have
>> the in-VM receiver added to it automatically, so that it can access all
>> EJBs in the server via remote interface locally.
>
> This does not scale up. Especially with large deployments and/or many
> small ones.

The alternatives are:

1. One server-wide EE client context, which means that all deployments 
"see" the same remote systems
2. Configurable EE client contexts (in standalone.xml or equiv) and each 
deployment can be associated with one such context

>> Summary
>> -------
>>
>> Okay I think that's it for the first draft. Please give feedback on
>> anything that I might have missed or anything that's just outright wrong
>> and needs to be changed. In particular I'm currently assuming that IIOP
>> exists in a world outside of other invocation forms, but that might not
>> actually be desirable.
>>
> IIOP invocations should come in via the same facility as the EJB
> receivers invoke. Binding and interceptors are in this case very
> protocol specific. So IIOP can be left out of scope.

Yeah the server View API should be usable for IIOP invocations.  Though 
reviewing it, some of the stuff on ComponentViewInstance probably 
belongs on ComponentView, and there may be other changes needed.

-- 
- DML


More information about the jboss-as7-dev mailing list