Saturday, September 19, 2015

Hibernate Multitenancy Implementation

Hi All,

After many efforts,I have implemented multitenant  with hibernate and Spring based using seperate schema approach.Iam providing the code for you.

If you need an introduction to hibernate multi-tenancy please refer to following hibernate documentation.

http://docs.jboss.org/hibernate/orm/4.2/devguide/en-US/html/ch16.html


So starting with Context file to initialize your sessionfactory and datasoure

        class="org.springframework.orm.hibernate4.HibernateTransactionManager">     
 

class="in.sridhar.persistance.dao.SessionCurrentTenantIdentifierResolver">
   

            class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"
        abstract="true"> destroy-method="close">
               

SessionCurrentTenantIdentifierResolver is used to resolve the current tenent during the establishment of connection to database.

Here Iam using ThreadLocal to identify my tenent id.

public class SessionCurrentTenantIdentifierResolver implements CurrentTenantIdentifierResolver
{

    private static final Logger LOG = LoggerFactory
            .getLogger(SessionCurrentTenantIdentifierResolver.class);

    @Override
    public String resolveCurrentTenantIdentifier()
    {
        String tenantId = ThreadContext.getDataSourceIdentifier();
        System.out.println("Found TenantId=" + tenantId);
        return tenantId;
    }

    @Override
    public boolean validateExistingCurrentSessions()
    {
        return false;
    }

}


MultiTenantSchemaConnectionProvider  provides the implementation of getting and releasing conneciton  from data source and setting up the schema specific to tenant identifier



public class MultiTenantSchemaConnectionProvider implements MultiTenantConnectionProvider

{
    private static final long serialVersionUID = 4368575201221677384L;
    @Autowired
    private DataSource dataSource;

    @Override
    public boolean supportsAggressiveRelease()
    {
        return false;
    }

    @Override
    public boolean isUnwrappableAs(Class clazz)
    {
        return false;
    }

    @Override
    public T unwrap(Class clazz)
    {
        return null;
    }

    @Override
    public Connection getAnyConnection() throws SQLException
    {
        return dataSource.getConnection();
    }

    @Override
    public Connection getConnection(String tenantIdentifier) throws SQLException
    {
        final Connection connection = getAnyConnection();
        try
        {
            System.out.println("inside sridharconnection :" + connection + " and tenantIdentifier "
                    + tenantIdentifier);
            connection.createStatement().execute("SET search_path to '" + tenantIdentifier + "'");
        }
        catch (SQLException e)
        {
            throw new HibernateException("Could not alter JDBC connection to specified schema ["
                    + tenantIdentifier + "]", e);
        }
        return connection;
    }

    @Override
    public void releaseAnyConnection(Connection connection) throws SQLException
    {
        try
        {
            connection.createStatement().execute("SET search_path to 'public'");
        }
        catch (SQLException e)
        {
            throw new HibernateException(
                    "Could not alter JDBC connection to specified schema [public]", e);
        }
        connection.close();
    }

    @Override
    public void releaseConnection(String tenantIdentifier, Connection connection)
            throws SQLException
    {
        releaseAnyConnection(connection);
    }

}

ThreadContext class has the the logic of implementing thread local

public class ThreadContext
{
    private static final ThreadLocal dataSourceIdentifier = new ThreadLocal();

    public static String getDataSourceIdentifier()
    {
        return dataSourceIdentifier.get();
    }

    public static void setDataSourceIdentifier(String contextStr)
    {
        dataSourceIdentifier.set(contextStr);
    }

    public static void resetDataSourceIdentifier()
    {
        dataSourceIdentifier.remove();
    }
}

Few things observed during the implementation of multi tenancy are:

1)hibernate.hbm2ddl.auto does work in multi tenancy approch
2) when you try to use


Session session = sessionFactory.withOptions() .tenantIdentifier( yourTenantIdentifier ) ... .openSession();

you will not able to use @transactional spring annotation.Because when we use this annotation spring internally uses session.getCurrentSession() which will not identify your tenent.

Tuesday, June 16, 2015

Useful Linux commands


nohup :Used to run a start another program in such a way that if parent process is killed still it runs.

eg: $: nohup java test.class &
 even if the console is closed .the java program will be running


 If you want to add any default directories  or files while creating new user add those files/directories in   /etc/skel so during user creation they will be added

Thursday, March 26, 2015

Script to run a simple Java Service in linux

#!/bin/sh
SERVICE_NAME=MyService
PATH_TO_JAR=/usr/local/MyProject/MyJar.jar
PID_PATH_NAME=/tmp/MyService-pid
case $1 in
    start)
        echo "Starting $SERVICE_NAME ..."
        if [ ! -f $PID_PATH_NAME ]; then
            nohup java -jar $PATH_TO_JAR /tmp 2>> /dev/null >> /dev/null &
                        echo $! > $PID_PATH_NAME
            echo "$SERVICE_NAME started ..."
        else
            echo "$SERVICE_NAME is already running ..."
        fi
    ;;
    stop)
        if [ -f $PID_PATH_NAME ]; then
            PID=$(cat $PID_PATH_NAME);
            echo "$SERVICE_NAME stoping ..."
            kill $PID;
            echo "$SERVICE_NAME stopped ..."
            rm $PID_PATH_NAME
        else
            echo "$SERVICE_NAME is not running ..."
        fi
    ;;
    restart)
        if [ -f $PID_PATH_NAME ]; then
            PID=$(cat $PID_PATH_NAME);
            echo "$SERVICE_NAME stopping ...";
            kill $PID;
            echo "$SERVICE_NAME stopped ...";
            rm $PID_PATH_NAME
            echo "$SERVICE_NAME starting ..."
            nohup java -jar $PATH_TO_JAR /tmp 2>> /dev/null >> /dev/null &
                        echo $! > $PID_PATH_NAME
            echo "$SERVICE_NAME started ..."
        else
            echo "$SERVICE_NAME is not running ..."
        fi
    ;;
esac