Announcement Announcement Module
Collapse
No announcement yet.
SessionFactory configured for multi-tenancy, but no tenant identifier specified Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • SessionFactory configured for multi-tenancy, but no tenant identifier specified

    Config:
    * Spring 3.1.1.RELEASE
    * Hibernate 4.1.0.FINAL
    * Commons-DBCP 1.4

    I'm trying to setup multi-tenancy with Hibernate 4.1 but it seems that SessionFactory isn't correctly configured by the transaction manager (or else).

    Code:
    	<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"
    		p:packagesToScan="com.company" 
    		>
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.dialect">org.hibernate.dialect.MySQLMyISAMDialect</prop>
    				<prop key="hibernate.show_sql">true</prop>
    				<prop key="hibernate.multiTenancy">DATABASE</prop>
    				<prop key="hibernate.tenant_identifier_resolver">com.mycompany.datasource.MultiTenantIdentifierResolver</prop>
    				<prop key="hibernate.multi_tenant_connection_provider">com.mycompany.datasource.MultiTenantConnectionProvider</prop>
    			</props>
    		</property>
    	</bean>
    
     	<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager" p:autodetectDataSource="false" p:sessionFactory-ref="sessionFactory"/>
    * I removed the p:dataSource-ref from LocalSessionFactoryBena because if I read correctly the documentation, it overrides the other settings.
    * Because of that, I also had to put "p:autodetectDataSource="false" in HibernateTransactionManager otherwise it tries to get the datasource & generates a NullPointerException
    * I finally removed the hibernate.current_session_context_class (previous set up as "jta") because it doesn't seem to change anything anymore with HibernateTransactionManager of hibernate4 package.

    So I have a simple MultiTenantConnectionProvider:

    Code:
    package com.mycompany.datasource;
    
    public class MultiTenantConnectionProvider extends org.hibernate.service.jdbc.connections.spi.AbstractMultiTenantConnectionProvider {
    	private static final long serialVersionUID = 1L;
    
    	@Override
    	public org.hibernate.service.jdbc.connections.spi.ConnectionProvider getAnyConnectionProvider() {
    		return MultiTenantConnectionHolder.getAnyConnectionProvider();
    	}
    
    	@Override
    	public org.hibernate.service.jdbc.connections.spi.ConnectionProvider selectConnectionProvider(String tenantIdentifier) {
    		return MultiTenantConnectionHolder.getConnectionProvider(tenantIdentifier);
    	}
    }
    Whatever the details of MultiTenantConnectionHolder...

    Then I have my TenantIdentifierResolver implementation which seems to be loaded correctly:

    Code:
    package com.mycompany.datasource;
    
    public class MultiTenantIdentifierResolver implements org.hibernate.context.spi.CurrentTenantIdentifierResolver {
    
    	@Autowired
    	UserDetailsService userService;
    
    	public String resolveCurrentTenantIdentifier() {
    		return userService.getCurrentlyAuthenticatedUser().getTenantId();
    	}
    
    	public boolean validateExistingCurrentSessions() {
    		return true;
    	}
    }
    Then I have a webservice endpoint which is transactional

    Code:
    	@Transactional @ResponsePayload @PayloadRoot(localPart = "ActionRequest", namespace = NAMESPACE_URI)
    	public ActionResponse handleAWSRequest(@RequestPayload ActionRequest request) throws ActionRequestException {
    		...
    	}
    With all that, I get the exception "SessionFactory configured for multi-tenancy, but no tenant identifier specified".

    * I can see with AOP that the MultiTenantIdentifierResolver isn't called.
    * With the following stack trace, I can see that we are in a transaction context (HibernateTransactionManager.doBegin) but it can't pass the tenantIdentifier...

    Code:
    org.hibernate.HibernateException: SessionFactory configured for multi-tenancy, but no tenant identifier specified
    	at org.hibernate.internal.AbstractSessionImpl.<init>(AbstractSessionImpl.java:82)
    	at org.hibernate.internal.SessionImpl.<init>(SessionImpl.java:226)
    	at org.hibernate.internal.SessionFactoryImpl$SessionBuilderImpl.openSession(SessionFactoryImpl.java:1801)
    	at org.hibernate.internal.SessionFactoryImpl.openSession(SessionFactoryImpl.java:1009)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    	at java.lang.reflect.Method.invoke(Method.java:597)
    	at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:191)
    	at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:176)
    	at org.springframework.orm.hibernate4.SessionFactoryUtils.openSession(SessionFactoryUtils.java:114)
    	at org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:340)
    	at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:371)
    	at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:335)
    	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:105)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    	at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)
    	at com.mycompany.webservice.endpoint.AWSEndPoint$$EnhancerByCGLIB$$f46141a4.handleAWSRequest(<generated>)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    	at java.lang.reflect.Method.invoke(Method.java:597)
    	at org.springframework.ws.server.endpoint.MethodEndpoint.invoke(MethodEndpoint.java:132)
    	at org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter.invokeInternal(DefaultMethodEndpointAdapter.java:229)
    	at org.springframework.ws.server.endpoint.adapter.AbstractMethodEndpointAdapter.invoke(AbstractMethodEndpointAdapter.java:53)
    	at org.springframework.ws.server.MessageDispatcher.dispatch(MessageDispatcher.java:231)
    	at org.springframework.ws.server.MessageDispatcher.receive(MessageDispatcher.java:172)
    	at org.springframework.ws.transport.support.WebServiceMessageReceiverObjectSupport.handleConnection(WebServiceMessageReceiverObjectSupport.java:88)
    	at org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter.handle(WebServiceMessageReceiverHandlerAdapter.java:59)
    ......
    Searching for Hibernate implementation, I found in hibernate *SessionContext (JTA or Thread) the buildOrObtainSession() which calls baseSessionBuilder() which calls the tenantIdentifier, but obviously it's not going through this code. Probably because antother implementation is called...

    org.hibernate.context.spi.AbstractCurrentSessionCo ntext
    Code:
    	
    	protected SessionBuilder baseSessionBuilder() {
    		final SessionBuilder builder = factory.withOptions();
    		final CurrentTenantIdentifierResolver resolver = factory.getCurrentTenantIdentifierResolver();
    		if ( resolver != null ) {
    			builder.tenantIdentifier( resolver.resolveCurrentTenantIdentifier() );
    		}
    		return builder;
    	}
    I'm quite lost with this...
    I feel like the usage of HibernateTransactionManager isn't using the Hibernate classes that supports the multi-tenancy configuration OR that it doesn't configure the sessionFactory with all parameters (TenantIdentifierResolver is this case)...
    Any help?

  • #2
    I have the same issue. Obviously the CurrentTenantIdentifierResolver is only used by calling SessionFactory#getCurrentSession() (would only work with JTASessionContext and ThreadLocalSessionContext but not with SpringSessionContext, which is used in your configuration). But the TransactionManagers (at least the HibernateTransactionManager) call #openSession() instead of #getCurrentSession(), so the SessionContexts are never used by @Transactional.

    So the bug seems mainly to be in Hibernate instead of Spring. I think SpringSessionContext should use the CurrentTenantIdentifierResolver, but I guess this wouldn't solve the issue with @Transactional.

    I think the only solution would be to override HibernateTransactionManager, modify the TransactionInterceptor, don't use @Transactional or don't use CurrentTenantIdentifierResolver (so you also can't use @Transactional)
    Any other ideas?

    Comment


    • #3
      Hi,
      Have the same issue. Any workaround or suggested solution ?
      I found this : http://stackoverflow.com/questions/9...ng-3-hibernate
      Is it the only workaround ?

      Comment


      • #4
        I tried overiding the HibernateTransactionManager as suggested but it's quite difficult and couldn't get it to work.

        I don't know why, but no one at SpringSource has a clear explaination for this...

        Comment


        • #5
          Few weeks ago I migrated a project from Hibernate 3 to Hibernate 4.
          Since it is a multi-user application I decided to test multy-tenancy of Hibernate 4 (with Hibernate 3 we adopted a custom solution).
          After this migration I decided to test Spring with this application and I found a lot of problems during the integration.
          I read a lot of threads here and on Stackoverflow and finally I found a solution.
          I want to share it with you, it is still embryonic and doesn't want to be the final solution of the problem rather an initial implementation to be improved.

          The solution is suited only when using annotations. It's due to the fact that multi-tenancy is a runtime concept.

          I created a custom annotation for the purpose.

          Code:
          @Retention(RetentionPolicy.RUNTIME)
          public @interface Tenant {
          
          }

          And the advice:

          Code:
          @Aspect
          @Order(1)
          public class TenantAdvice {
          
          	@Autowired
          	@Qualifier("transactionManager")
          	MultiTenantHibernateTransactionManager transactionManager;
          	
          	@Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)")
          	public void openSession() {
          	}
          
          	@Before("openSession()")
          	public void injectTenant(JoinPoint jp) {
          		MethodSignature signature = (MethodSignature) jp.getSignature();
          		Method method = signature.getMethod();
          		Annotation[][] paramAnnots = method.getParameterAnnotations();
          		Object[] args = jp.getArgs();
          		
          		int i = 0;
          		for (Annotation[] annotations : paramAnnots) {
          			Object arg = args[i++];
          			for (Annotation annotation : annotations) {
          				if (annotation instanceof Tenant) {
          					String tenantIdentifier = arg.toString();
          					transactionManager.setTenantIdentifier(tenantIdentifier);
          					break;
          				}
          			}
          		}
          	}
          }
          It observes every @Transactional method and look for annotated parameters to be set in the modified Transaction Manager with the new parameter tenantIdentifier.
          It's worth noting the order annotation. It's explained further in the post.

          The third and final class is the new Transaction Manager:

          Code:
          public class MultiTenantHibernateTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, InitializingBean {
          
          	/**
          	 * 
          	 */
          	private static final long serialVersionUID = 6292693746575619760L;
          
          	public MultiTenantHibernateTransactionManager() {
          		super();
          	}
          
          	private static final Method getCurrentSessionMethod = ClassUtils.getMethod(SessionFactory.class, "getCurrentSession");
          	private SessionFactory sessionFactory;
          	private DataSource dataSource;
          	private boolean autodetectDataSource = true;
          	private boolean prepareConnection = true;
          	private boolean hibernateManagedSession = false;
          	private String tenantIdentifier = "";
          
          	public MultiTenantHibernateTransactionManager(SessionFactory sessionFactory) {
          		this.sessionFactory = sessionFactory;
          		afterPropertiesSet();
          	}
          
          	public void setSessionFactory(SessionFactory sessionFactory) {
          		this.sessionFactory = sessionFactory;
          	}
          
          	public SessionFactory getSessionFactory() {
          		return this.sessionFactory;
          	}
          
          	...
          	...
          	...
          
          	@Override
          	protected void doBegin(Object transaction, TransactionDefinition definition) {
          		HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
          
          		if (txObject.hasConnectionHolder() && !txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
          			throw new IllegalTransactionStateException("Pre-bound JDBC Connection found! HibernateTransactionManager does not support "
          					+ "running within DataSourceTransactionManager if told to manage the DataSource itself. " + "It is recommended to use a single HibernateTransactionManager for all transactions "
          					+ "on a single DataSource, no matter whether Hibernate or JDBC access.");
          		}
          
          		Session session = null;
          
          		try {
          			if (txObject.getSessionHolder() == null || txObject.getSessionHolder().isSynchronizedWithTransaction()) {
          				Session newSession = null;
          				// multi-tenant management
          				if (tenantIdentifier != null && !"".equals(tenantIdentifier)) {
          					SessionFactory sessionFactory = getSessionFactory();
          					SessionBuilder sb = sessionFactory.withOptions().tenantIdentifier(tenantIdentifier);
          					newSession = sb.openSession();
          					txObject.setSession(newSession);
          				} else {
          					newSession = SessionFactoryUtils.openSession(getSessionFactory());
          					txObject.setSession(newSession);
          				}
          				// end multi-tenant management
          
          				if (logger.isDebugEnabled()) {
          					logger.debug("Opened new Session [" + newSession + "] for Hibernate transaction");
          				}
          			}
          
          			session = txObject.getSessionHolder().getSession();
          
          			if (this.prepareConnection && isSameConnectionForEntireSession(session)) {
          				// We're allowed to change the transaction settings of the JDBC Connection.
          				if (logger.isDebugEnabled()) {
          					logger.debug("Preparing JDBC Connection of Hibernate Session [" + session + "]");
          				}
          				Connection con = ((SessionImplementor) session).connection();
          				Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
          				txObject.setPreviousIsolationLevel(previousIsolationLevel);
          			} else {
          				// Not allowed to change the transaction settings of the JDBC Connection.
          				if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
          					// We should set a specific isolation level but are not allowed to...
          					throw new InvalidIsolationLevelException("HibernateTransactionManager is not allowed to support custom isolation levels: "
          							+ "make sure that its 'prepareConnection' flag is on (the default) and that the "
          							+ "Hibernate connection release mode is set to 'on_close' (SpringTransactionFactory's default).");
          				}
          				if (logger.isDebugEnabled()) {
          					logger.debug("Not preparing JDBC Connection of Hibernate Session [" + session + "]");
          				}
          			}
          
          			if (definition.isReadOnly() && txObject.isNewSession()) {
          				// Just set to NEVER in case of a new Session for this transaction.
          				session.setFlushMode(FlushMode.MANUAL);
          			}
          
          			if (!definition.isReadOnly() && !txObject.isNewSession()) {
          				// We need AUTO or COMMIT for a non-read-only transaction.
          				FlushMode flushMode = session.getFlushMode();
          				if (FlushMode.isManualFlushMode(session.getFlushMode())) {
          					session.setFlushMode(FlushMode.AUTO);
          					txObject.getSessionHolder().setPreviousFlushMode(flushMode);
          				}
          			}
          
          			Transaction hibTx;
          
          			// Register transaction timeout.
          			int timeout = determineTimeout(definition);
          			if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
          				// Use Hibernate's own transaction timeout mechanism on Hibernate 3.1+
          				// Applies to all statements, also to inserts, updates and deletes!
          				hibTx = session.getTransaction();
          				hibTx.setTimeout(timeout);
          				hibTx.begin();
          			} else {
          				// Open a plain Hibernate transaction without specified timeout.
          				hibTx = session.beginTransaction();
          			}
          
          			// Add the Hibernate transaction to the session holder.
          			txObject.getSessionHolder().setTransaction(hibTx);
          
          			// Register the Hibernate Session's JDBC Connection for the DataSource, if set.
          			if (getDataSource() != null) {
          				Connection con = ((SessionImplementor) session).connection();
          				ConnectionHolder conHolder = new ConnectionHolder(con);
          				if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
          					conHolder.setTimeoutInSeconds(timeout);
          				}
          				if (logger.isDebugEnabled()) {
          					logger.debug("Exposing Hibernate transaction as JDBC transaction [" + con + "]");
          				}
          				TransactionSynchronizationManager.bindResource(getDataSource(), conHolder);
          				txObject.setConnectionHolder(conHolder);
          			}
          
          			// Bind the session holder to the thread.
          			if (txObject.isNewSessionHolder()) {
          				TransactionSynchronizationManager.bindResource(getSessionFactory(), txObject.getSessionHolder());
          			}
          			txObject.getSessionHolder().setSynchronizedWithTransaction(true);
          		}
          
          		catch (Exception ex) {
          			if (txObject.isNewSession()) {
          				try {
          					if (session.getTransaction().isActive()) {
          						session.getTransaction().rollback();
          					}
          				} catch (Throwable ex2) {
          					logger.debug("Could not rollback Session after failed transaction begin", ex);
          				} finally {
          					SessionFactoryUtils.closeSession(session);
          				}
          			}
          			throw new CannotCreateTransactionException("Could not open Hibernate Session for transaction", ex);
          		}
          	}
          
          	
          	...
          	...
          	...
          
          
          	public String getTenantIdentifier() {
          		return tenantIdentifier;
          	}
          
          	public void setTenantIdentifier(String tenantIdentifier) {
          		this.tenantIdentifier = tenantIdentifier;
          	}
          
          	...
          	...
          	...
          
          }
          I highlighted the modified code and omitted unmodified one.

          Finally the configuration:

          Code:
          ...
          ...
          <tx:annotation-driven transaction-manager="transactionManager" order="2"/>
          ...
          ...
          <bean id="transactionManager" class="mypackage.MultiTenantHibernateTransactionManager">
          		<property name="sessionFactory" ref="sessionFactory" />
          		<property name="autodetectDataSource" value="false" />
          </bean>
          ...
          ...
          Transaction Manager is loaded with order 2 while the advice has order 1, it means the advice has a higher priority than the transaction manager.
          It is needed since tenantIdentifier needs to be read and set before transaction is started.

          Here it is my solution.
          Any suggestion, improvement... Or even insult is accepted and listened carefully

          Regards,
          Simone.

          Comment


          • #6
            Do you really need to override the HibernateTransactionManager? It should work without it BUT You need at least Hibernate 4.1.4 because there was a bug between 4.0 and 4.1.2 that make multitenant+spring not working. http://in.relation.to/Bloggers/HibernateORM414Release.

            I personaly used org.springframework.orm.hibernate4.LocalSessionFac toryBean depending on a MultiTenantConnectionHolder (custom class) that is based on a custom ConnectionProvider. The connection provider give the datasource to sessionFactory.

            hibernate.multiTenancy=DATABASE
            hibernate.tenant_identifier_resolver=com.......Mul tiTenantIdentifierResolver
            hibernate.multi_tenant_connection_provider=com.... ..MultiTenantConnectionProvider


            <bean id="transactionManager" class="org.springframework.orm.hibernate4.Hibernat eTransactionManager" p:autodetectDataSource="false" p:sessionFactory-ref="sessionFactory"/>

            And that's it.

            Comment


            • #7
              Default implementation of HibernateTransactionManager opens the session without options.
              To set tenantIdentifier, you need to open the session as described in bold in my previous example.

              I forgot to say that I'm using 4.1.4 version of Hibernate.

              Other considerations: my colleague Valerio pointed out that the implementation of the custom transaction manager is not thread safe.
              I then modified it storing tenantIdentifier in a ThreadLocal object:


              Code:
              ...
              ...
              private ThreadLocal<String> threadLocal = new ThreadLocal<String>();
              ...
              ...
              	public String getTenantIdentifier() {
              		return threadLocal.get();
              	}
              
              	public void setTenantIdentifier(String tenantIdentifier) {
              		threadLocal.set(tenantIdentifier);
              	}
              ...
              ...
              I realized the I missed also the configuration of the Advice in applicationContext.xml:

              Code:
              ...
              ...
              	<aop:aspectj-autoproxy />
              
              	<bean id="tenantAdvice" class=mypackage.TenantAdvice" />
              ...
              ...

              Comment


              • #8
                I used to think that Spring HibernateTransactionManager should open session with options. They say it's not their responsability to set it, and guys from Hibernate did something that makes the standard openSession() implicitely use the tenant identifier. It seems logical because when Hibernate is configured with a CurrentTenantIdentifier, it now uses it ! Fixed in Hibernate, no change required in Spring!

                See this jira:
                https://jira.springsource.org/browse/SPR-9222

                Comment


                • #9
                  I agree with you, it's better to solve the issue in hibernate rather than Spring, but I want to explain better the scenario.

                  I want to be able to set tenantIdentifier at runtime, every HTTP request could have its tenant.
                  How can I do that by resolveCurrentTenantIdentifier method of CurrentTenantIdentifierResolver?
                  Last edited by deggesim; Jul 11th, 2012, 05:04 AM.

                  Comment


                  • #10
                    Yes, that's good.
                    Here my currentTenantIdentifierResolver:
                    You can also have other methods to determine the tenant...

                    Code:
                    import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
                    import org.springframework.security.core.Authentication;
                    import org.springframework.security.core.context.SecurityContext;
                    import org.springframework.security.core.context.SecurityContextHolder;
                    import org.springframework.security.core.userdetails.UserDetails;
                    
                    public class MultiTenantIdentifierResolver implements CurrentTenantIdentifierResolver {
                    	
                    	public String resolveCurrentTenantIdentifier() {
                    		String tenantId = null;
                    
                            SecurityContext context = SecurityContextHolder.getContext();
                            Authentication authentication = context.getAuthentication();
                            if (authentication != null) {
                                if (authentication.getPrincipal() instanceof CustomUserDetails) {
                                	CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal();
                                	tenantId = userDetails.getUser().getMyTenantIdentifier();
                                } else {
                                	tenantId = ((CustomUser) authentication.getPrincipal()).getMyTenantIdentifier();
                                }
                            } else {
                                return null;
                            }
                    
                            return tenantId;
                    	}
                    
                    	public boolean validateExistingCurrentSessions() {
                    		return true;
                    	}
                    }

                    Comment


                    • #11
                      Ok, I followed your suggestion.

                      I implemented my CurrentTenantIdentifierResolver and used a ThreadLocal to store tenantIdentifier (always by the advice).

                      It is the new Advice:

                      Code:
                      @Aspect
                      @Order(1)
                      public class TenantAdvice {
                      
                      	@Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)")
                      	public void openSession() {
                      	}
                      
                      	@Before("openSession()")
                      	public void injectTenant(JoinPoint jp) {
                      		MethodSignature signature = (MethodSignature) jp.getSignature();
                      		Method method = signature.getMethod();
                      		Annotation[][] paramAnnots = method.getParameterAnnotations();
                      		Object[] args = jp.getArgs();
                      		
                      		int i = 0;
                      		for (Annotation[] annotations : paramAnnots) {
                      			Object arg = args[i++];
                      			for (Annotation annotation : annotations) {
                      				if (annotation instanceof Tenant) {
                      					String tenantIdentifier = arg.toString();
                      					MyCurrentTenantIdentifierResolver.setTenantIdentifier(tenantIdentifier);
                      					break;
                      				}
                      			}
                      		}
                      	}
                      }
                      No more references to the transactionManager. I set directly tenant identifier in the resolver.

                      Here is the code of the resolver:

                      Code:
                      public class MyCurrentTenantIdentifierResolver implements CurrentTenantIdentifierResolver {
                      
                      	private static ThreadLocal<String> threadLocal = new ThreadLocal<String>();
                      
                      	public static void setTenantIdentifier(String tenantIdentifier) {
                      		threadLocal.set(tenantIdentifier);
                      	}
                      
                      	@Override
                      	public String resolveCurrentTenantIdentifier() {
                      		return threadLocal.get();
                      	}
                      
                      	@Override
                      	public boolean validateExistingCurrentSessions() {
                      		String tenantIdentifier = threadLocal.get();
                      		if (tenantIdentifier != null) {
                      			return true;
                      		} else {
                      			return false;
                      		}
                      	}
                      
                      }
                      This is my solution without rewriting Spring transaction manager.

                      EDIT: post written without reading your last answer. Thank you for your code. It will be a good hint when I'll decide to use Spring Security
                      Last edited by deggesim; Sep 28th, 2012, 02:37 AM.

                      Comment


                      • #12
                        Nice write up and explanation!
                        Is it possible to create a sample maven app so we can see how the whole thing is combined together?
                        Last edited by maksimu; Sep 28th, 2012, 02:29 PM. Reason: Changed "manen" to "maven"

                        Comment


                        • #13
                          manen?

                          Maybe maven?

                          Comment


                          • #14
                            Also vote for a small maven app. Got stuck at *ConnectionProvider implementation.

                            Comment

                            Working...
                            X