Here is the other issue with "separate hierarchies"...
Code that deals with connections now becomes more complicated, having to first
see if there is a SpecializedConnectionProvider and if so grab a connection
from it, otherwise check the ConnectionProvider.
Obviously there are techniques to work around that like making all Connection
access route back through the Session which could expose a singular contract
for getting a connection. Then the "dirtiness" could be contained to just
that "thing".
On Wednesday, March 23, 2011, at 04:58 pm, Steve Ebersole wrote:
Well I think I am leaning towards a "parameter object" no
matter what we do
otherwise. So call this param object interface ConnectionOptions. It
would have a single method today (err, tomorrow when I write all this :)
to get the tenant id.
The tenant id is really associated with the session. Either session
implements that interface or hands it off to a delegate it manages, but
thats the "scope"... the session.
So in your examnple, you would inject the entitymanager's session with the
proper tenant id. Ideally I want this to be specified up front when the
session is opended to make sure there is no possibility of changing it mid-
stream, but that further relies on
http://opensource.atlassian.com/projects/hibernate/browse/HHH-2860
Anyway, in thinking about this sme more I think the way I really like is
this:
1) ConnectionProvider remains as is
2) introduce a new provider contract (names as always are preliminary):
public interface SpecializedConnectionProvider extends ConnectionProvider {
public static interface ConnectionOptions {
public String getTenantIdentifier();
}
public Connection getSpecializedConnection(ConnectionOptions);
public void releaseSpecializedConnection(ConnectionOptions,
Connection); }
Having SpecializedConnectionProvider extend ConnectionProvider addressed
another issue I encountered when implementing this. How do you account for
situations where you need *some* connection? Like when reading
java.sql.DatabaseMetaData on "startup". The other option for that is to
not have SpecializedConnectionProvider extend ConnectionProvider (so they
are back to distinct hierarchies) and adding an extra method to
SpecializedConnectionProvider. This additional method would either give
access to a connection with out providing tenant information or if
obtaining java.sql.DatabaseMetaData is deemed the only acceptable use case
there then just have a method to scrape that info passing back
DatabaseMetaData is not an option if that is the decision because of
java.sql.DatabaseMetaData#getConnection
Also, I was not sure if there is really a need for a specialized "release
this connection" method in the case where SpecializedConnectionProvider
extends ConnectionProvider. There is still the
ConnectionProvider#closeConnection method. Now obviously if the
herarchies are distinct we would need release capability on both...
On Wednesday, March 23, 2011, at 04:24 pm, Chris Bredesen wrote:
> But 3 is how it's done today since we don't have the other solutions.
> So yeah it's magical, but people do manage to make it work. I will
> concede that it is not always perceived as straightforward, however.
>
> Something to think about in the grander scheme of things is how someone
> would deal with obtaining a tenant-specific connection when resource
> injection is in use. #3 solves this but what about #1 and #2? There
> are some pretty neat things that I can envision wrt CDI but I haven't
> thought through what the implementations would look like.
>
> @Inject @TenantSpecific @UserDatabase private EntityManager em;
>
> How would you drill the tenant information into the CP?
>
> -CB
>
> On 03/23/2011 04:25 PM, Adam Warski wrote:
> > I think for a user the best option (easiest to understand) would be 1).
> >
> > 3) is too magical. 2) is putting everything in one sack.
> >
> > Adam
> >
> > On Mar 22, 2011, at 10:21 PM, Steve Ebersole wrote:
> >> reference
> >>
http://opensource.atlassian.com/projects/hibernate/browse/HHH-5697
> >>
> >> For multi-tenancy implemented by sepaerate schema we need the ability
> >> to tell the ConnectionProvider about the tenant for the given
> >> getConnection() request. I really see 3 approaches to this:
> >>
> >> 1) Have 2 hierarchies here. The current ConnectionProvider contract
> >> remains the same. Add a new MultiTenantConnectionProvider with
> >> methods accounting for tenant
> >> 2) Just alter the ConnectionProvider contract to pass information in.
> >> If we go this route I prefer the "parameter object" pattern where
we
> >> pass in ConnectionOptions interface (see issue).
> >> 3) Use contextual lookup. ConnentionProviders interested in (or
> >> capable of understanding) mulit-tenancy would perform some kind of
> >> "contextual" (ThreadLocal, etc) lookup for the needed
information.
> >>
> >> Thoughts? Discussions?
> >>
> >> ---
> >> Steve Ebersole<steve(a)hibernate.org>
> >>
http://hibernate.org
> >> _______________________________________________
> >> hibernate-dev mailing list
> >> hibernate-dev(a)lists.jboss.org
> >>
https://lists.jboss.org/mailman/listinfo/hibernate-dev
>
> _______________________________________________
> hibernate-dev mailing list
> hibernate-dev(a)lists.jboss.org
>
https://lists.jboss.org/mailman/listinfo/hibernate-dev
---
Steve Ebersole <steve(a)hibernate.org>
http://hibernate.org