package grails.plugin.multitenant.core.datasource;

import grails.plugin.multitenant.core.CurrentTenant;
import org.apache.log4j.Logger;
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;

/**
 * Created by IntelliJ IDEA.
 * User: scottryan
 * Date: Aug 9, 2010
 * Time: 2:10:14 PM
 * To change this template use File | Settings | File Templates.
 */
public class TenantTransactionAwareDataSourceProxy extends TransactionAwareDataSourceProxy {
    /**
     * This is the resolver to be used to determine the datasource.
     */
    private DataSourceUrlResolver dataSourceUrlResolver;
    /**
     * This is the tenant this data source is associated with.
     */
    private CurrentTenant currentTenant;
    /**
     * This allows the TenantBeanFactoryPostProcessor to assign a proxy to this object in spring since there is one of
     * there for each client.
     */
    public static final boolean multiTenant = true;
    /**
     * This is a logger for logging status or errors
     */
    private static Logger log = Logger.getLogger(TenantTransactionAwareDataSourceProxy.class);

    TenantTransactionAwareDataSourceProxy(DataSource targetDataSource) {
        super(targetDataSource);
    }

    @Override
    public DataSource getTargetDataSource() {
        DataSource ds = super.getTargetDataSource();
        if (currentTenant.get() != 0) {
            // If not tenant 0 then look up the jndi name from the tenant.
            final String jndiNameForTenant = dataSourceUrlResolver.getDataSourceUrl(currentTenant.get());
            try {
                // TODO Support other than JNDI Data Sources
                // TODO Either cache the context lookup or cache the data source for performance
                Context ctx = new InitialContext();
                ds = (DataSource) ctx.lookup(jndiNameForTenant);
            }
            catch (Exception ex) {
                log.fatal("Exception in Multi-tenant data source provider", ex);
            }
        }
        if (log.isDebugEnabled()) {
            log.debug("Returning the dataSource " + ds.toString() + " for tenant " + currentTenant.get());
        }
        return ds;
    }

    /**
     * This will set the resolver type for this datasource object.
     *
     * @param inDataSourceUrlResolver The resolver to use to determine the datasource for the tenant.  The types could
     *                                be database or properties file.
     */

    public void setDataSourceUrlResolver(DataSourceUrlResolver inDataSourceUrlResolver) {
        this.dataSourceUrlResolver = inDataSourceUrlResolver;
    }

    /**
     * Since this object is cached this allows you to resolve which tenant this resource applies to.
     *
     * @param inCurrentTenant The tenant id this data source is associated with.
     */
    public void setCurrentTenant(CurrentTenant inCurrentTenant) {
        this.currentTenant = inCurrentTenant;
    }
}

@@ -313,157 +313,567 @@
 %0A * 
-Created by IntelliJ IDEA.%0A * User: scottryan%0A * Date: Aug 9, 2010%0A * Time: 2:10:14 PM%0A * To change this template use File %7C Settings %7C File Templates
+This class will intercept any calls by the grails infrastructure for a data source and return the proper%0A * data source for the current tenant.  If a transaction is already open and you make a tenant change the%0A * data source will not change.  If you want to change tenants then you need to close all open transactions and then%0A * change tenant and open the transaction.  Also you should flush and clear the hibernate session first level cache so%0A * you don't mix tenant data in the cache.  This class only supports JNDI based data sources at the current time
 .%0A *
@@ -964,17 +964,17 @@
 rceProxy
- 
+%0A
 %7B%0A    /*
@@ -990,24 +990,40 @@
 This is the 
+data source url 
 resolver to 
@@ -1051,22 +1051,27 @@
 the data
+ 
 source
+ url
 .%0A     *
@@ -1161,49 +1161,86 @@
 he t
-enant this data source is associated with
+hread local tenant that is active at the time of the interation with the class
 .%0A  
@@ -1423,17 +1423,17 @@
    * the
-r
+s
 e for ea
@@ -1668,16 +1668,149 @@
 lass);%0A%0A
+    /**%0A     * This is the default constructor.%0A     *%0A     * @param targetDataSource The target data source for this class.%0A     */%0A
     Tena
@@ -1871,16 +1871,20 @@
 aSource)
+%0A   
  %7B%0A     
@@ -1914,24 +1914,335 @@
 ce);%0A    %7D%0A%0A
+    /**%0A     * This method will return the actual data source for the active tenant.  If no tenant can be resolve then the%0A     * default data source is returned and assumed to connect to the configuration database as tenant 0.%0A     *%0A     * @return The data source for the current thread local tenant.%0A     */%0A
     @Overrid
@@ -2286,16 +2286,20 @@
 Source()
+%0A   
  %7B%0A     
@@ -2383,16 +2383,24 @@
 () != 0)
+%0A       
  %7B%0A     
@@ -2591,11 +2591,209 @@
     
-try
+if (log.isDebugEnabled())%0A            %7B%0A                log.debug(%22Returning the jndi dataSource %22 + jndiNameForTenant + %22 for tenant %22 + currentTenant.get());%0A            %7D%0A            try%0A           
  %7B%0A 
@@ -3112,16 +3112,28 @@
 tion ex)
+%0A           
  %7B%0A     
@@ -3236,161 +3236,8 @@
   %7D%0A
-        if (log.isDebugEnabled()) %7B%0A            log.debug(%22Returning the dataSource %22 + ds.toString() + %22 for tenant %22 + currentTenant.get());%0A        %7D%0A
     
@@ -3314,24 +3314,25 @@
 or this data
+ 
 source objec
@@ -3416,24 +3416,25 @@
 ine the data
+ 
 source for t
@@ -3539,17 +3539,16 @@
      */%0A
-%0A
     publ
@@ -3626,16 +3626,20 @@
 esolver)
+%0A   
  %7B%0A     
@@ -3970,16 +3970,20 @@
 tTenant)
+%0A   
  %7B%0A     
@@ -4030,9 +4030,8 @@
 %0A    %7D%0A%7D
-%0A

fix debugging to log the jndi data source used for the tenant. Also added some documentation.