jsr343-experts@jms-spec.java.net

[jsr343-experts] Re: (JMS_SPEC-57) Add Java EE 7 multi-tenancy support

From: Nigel Deakin <nigel.deakin_at_oracle.com>
Date: Wed, 23 Nov 2011 16:51:51 +0000

(I'm using HTML email to allow me to paste some tables below...)

On 11/11/2011 18:25, Nigel Deakin wrote:
> I've created this JIRA issue:
> http://java.net/jira/browse/JMS_SPEC-57
>
> This is a placeholder for work to extend the JMS 2.0 specification to support multi-tenancy as defined in Java EE 7.
>
> I've written some proposals (and some options) in a document (13 pages) which I have uploaded to the project download
> page: http://java.net/projects/jms-spec/downloads/download/JMS20MTv3.pdf
>
> Here's a synopsis of the document:
>
> * It reviews the Java EE 7 proposals for resource configuration metadata in respect of JMS resources.
>
> * It reviews the Java EE 7 proposals for multi-tenancy and discusses the three ways in which the destinations used by
> different instances of a multi-tenant application might be isolated from one another.
>
> * It proposes extensions to the @JMSDestinationDefinition and @JMSConnectionFactoryDefinition annotations (and their
> XML equivalents) to allow the application to specify the tenant isolation level of a given destination to be either
> "shared" or "isolated".
>
> * It proposes extensions to the javax.jms.Destination and javax.jms.ConnectionFactory interfaces to allow a deployer
> to specify the isolation level to be used with these administered objects.
>
> * If suggests four alternative means by which an application server could pass the tenantId of a running application
> to the JMS client. Two of these options would require changes to the JCA spec. I'm not sure which one to recommend, so
> that's the section I'd particularly appreciate comments and help on.
>
> This is all closely tied to the requirements for multi-tenancy support being defined by the Java EE platform expert
> group, so I'd particularly welcome any comments and contributions from JSR 343 EG members who are also on the Java EE
> platform expert group.
>
> Nigel

No-one has commented on this document. I can't say I'm surprised. Multi-tenancy is an area where JMS seems to be ahead
of other specs, notably the Java EE platform spec and the various database specs.

I had a long meeting with the Java EE spec leads to review this document, which I've summarised below and in a new
chapter in the document, which is now available at:
http://java.net/projects/jms-spec/downloads/download/JMS20MTv4.pdf

In summary:

  * My proposals to extend the JMS resource metadata (JMSConnectionFactoryDefintiion and JMSDestinationDefinition) to
    allow the required tenant isolation to be specified as "isolated" or "shared" received support.
  * My proposal of four alternative ways for passing tenantId from the app server to the JMS client are all rejected
    because they could not be extended to support per-thread tenantId in Java EE 8. Instead the Java EE platform EG will
    devise a generic way of passing per-thread tenantId, probably via Java SE security APIs, which can be used by JMS,
    JPA and other resource managers.

Detailed notes below:


    Notes from a review of version 3

The following notes were made following a review of version 3 of this document with the Java EE platform specification
leads.


      Specifying the required isolation level in resource metadata

The use of resource metadata to specify the required isolation level was endorsed.

@JMSDestinationDefinition {

description=“MDB input queue”

name="ims/inboundQueue",

className="javax.jms.Queue",

resourceName="orderQueue",

tenantIsolation="ISOLATED"

}

@JMSConnectionFactoryDefinition {

className="javax.jms.ConnectionFactory",

tenantIsolation="ISOLATED"

}

To avoid any possible confusion with database technology, the term "isolation level" should be avoided and the term
"tenant isolation" used.


      Passing tenantId to the connection used by a MDB to consume messages

In the discussion "How to pass tenantId to the JMS client", option 3 discussed how the JCA spec allows the application
server to pass a javax.security.auth.Subject objectto the resource adapter when creating a new connection or fetching
one from the pool. This Subject object could be extended to hold a new Principal object that containedthe tenantId..

However this doesn't coverthe connection used by a MDB to receive messages.

JCA defines a security inflow contract, which, is a mechanism for allowing the RA to pass a caller
java.security.Principal to the MDB application. The application can obtain this by calling
EJBContext.getCallerPrincipal(). (Can it also call Subject.getPrincipals() to obtain this Principal?).

However this doesn't help with Java EE 7 multi-tenancy, where we need a way for the /application server/ to pass the
tenant information to the RA when the endpoint is activated.

JCA 1.6 doesn't specify a way to do this currently. One possibility is to add a third argument to
ResourceAdapter.endpointActivation(MessageEndpointFactory endpointFactory, ActivationSpec spec) as follows:

ResourceAdapter.endpointActivation(

MessageEndpointFactory endpointFactory, ActivationSpec spec,

javax.security.auth.Subject subject)

The application server would need to set an appropriate javax.security.auth.Subject. This would require a change to the
JCA specification.

An alternative to passing this in via the JCA API would be for the app server to associate the tenantId with the current
thread (how would it do this?), so that the endpointActivation() implementation could call Subject.getPrincipals() and
obtain, say, a TenantPrincipal.

Note that I don't see tenantId as flowing in with each message: it's the other way round: the call to
endpointActivation() would pass the tenantId to the JMS server when creating the consumer.


      Passing tenantId in a Java EE 8 SaaS application

The document makes four proposals for passing tenantId to the JMS client when a connection was created.These proposals
were reviewed to assess which of them could be easily extended to support the needs of Java EE 8. This will provide full
support for SaaS, which will mean the ability of a single deployed application to work on behalf of multiple tenants.

Although the details of how this would work do not need to be decided for Java EE 7, the basic idea would be that
tenantId would be associated not with the deployed application but with the current thread.

We reviewed which of the four options for passing tenantId to the JMS client discussed above, could be extended to
handle SaaS multi-tenancy:

Mechanism for passing tenantId to the JMS client

        

Would it work in a SaaS application?

1.The deployer would set the tenantId on the connection factory or destination administered objects used by a tenant
application instance.

        

No, since all tenants using a given deployed application would see the same administered objects.

2.The JMS client could use JNDI to lookup the tenantId from a well-known JNDI context, such as java:comp/tenantId.

        

Yes, JNDI could be made to return a different tenantId depending on the thread that called it. However since the
tenantId would need to be checked every time a JMS client method was used, and JNDI may be relatively slow, this is
potentially a slow solution.

3.The JCA API could be extended to allow the application server to pass the tenantId to the resource adapter by means of
a javax.security.auth.Subject object when a connection was created or fetched from the pool (and when an endpoint was
activated).

        

No, this would allow per-connection tenantId but not per-thread tenantId.

4.Extend JCA API to allow tenantId to be passed as an argument when a connection was created or fetched from the pool
(and when an endpoint was activated).

        

No, this would allow per-connection tenantId but not per-thread tenantId.

However it was considered that the use of a javax.security.auth.Subject object to pass tenantId might be a good way to
pass a per-thread tenantId, since Java SE already has the concept of per-thread security credentials. This would by-pass
any need to pass this information using the JCA API.

The Java EE 7 expert group would take on the issue of how best to pass tenantId to a resource manager in a way which
would work on a per-thread basis for Java EE 8. There is therefore no need for a JMS-specific solution.