All Downloads are FREE. Search and download functionalities are using the official Maven repository.

liquibase.integration.spring.MultiTenantSpringLiquibase Maven / Gradle / Ivy

There is a newer version: 4.28.0
Show newest version
/**
 * 
 */
package liquibase.integration.spring;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NameClassPair;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.sql.DataSource;

import liquibase.exception.LiquibaseException;
import liquibase.logging.LogFactory;
import liquibase.logging.Logger;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.ResourceLoader;

/**
 * A wrapper of Liquibase suitable in multi-tenant environments where multiple
 * data sources represent tenants. It utilizes {@link SpringLiquibase} per each
 * data source. All the parameters are the same as for {@link SpringLiquibase}
 * except of the data source definition - in this case it is a list of data
 * sources available under specified JNDI subtree. You have to define the
 * subtree with {@link #jndiBase} property.
*
* The wrapper scans the subtree for all data sources and creates * {@link SpringLiquibase} instances.
*
* Example:
*
 * <bean id="liquibase" class="liquibase.integration.spring.MultiTenantSpringLiquibase">
 *	<property name="jndiBase" value="java:comp/env/jdbc/db" />
 *	<property name="changeLog" value="classpath:db/migration/db-changelog.xml" />	
 * </bean>
 * 
* * @see SpringLiquibase * * @author ladislav.gazo */ public class MultiTenantSpringLiquibase implements InitializingBean, ResourceLoaderAware { private Logger log = LogFactory.getLogger(MultiTenantSpringLiquibase.class.getName()); /** Defines the location of data sources suitable for multi-tenant environment. */ private String jndiBase; private final List dataSources = new ArrayList(); private ResourceLoader resourceLoader; private String changeLog; private String contexts; private Map parameters; private String defaultSchema; private boolean dropFirst = false; private boolean shouldRun = true; private File rollbackFile; @Override public void afterPropertiesSet() throws Exception { resolveDataSources(); runOnAllDataSources(); } private void resolveDataSources() throws NamingException { Context context = new InitialContext(); int lastIndexOf = jndiBase.lastIndexOf("/"); String jndiRoot = jndiBase.substring(0, lastIndexOf); String jndiParent = jndiBase.substring(lastIndexOf + 1); Context base = (Context) context.lookup(jndiRoot); NamingEnumeration list = base.list(jndiParent); while(list.hasMoreElements()) { NameClassPair entry = list.nextElement(); String name = entry.getName(); String jndiUrl; if(entry.isRelative()) { jndiUrl = jndiBase + "/" + name; } else { jndiUrl = name; } Object lookup = context.lookup(jndiUrl); if(lookup instanceof DataSource) { dataSources.add((DataSource) lookup); log.debug("Added a data source at " + jndiUrl); } else { log.info("Skipping a resource " + jndiUrl + " not compatible with DataSource."); } } } private void runOnAllDataSources() throws LiquibaseException { for(DataSource dataSource : dataSources) { log.info("Initializing Liquibase for data source " + dataSource); SpringLiquibase liquibase = new SpringLiquibase(); liquibase.setChangeLog(changeLog); liquibase.setChangeLogParameters(parameters); liquibase.setContexts(contexts); liquibase.setDefaultSchema(defaultSchema); liquibase.setDropFirst(dropFirst); liquibase.setShouldRun(shouldRun); liquibase.setRollbackFile(rollbackFile); liquibase.setResourceLoader(resourceLoader); liquibase.setDataSource(dataSource); liquibase.afterPropertiesSet(); log.info("Liquibase ran for data source " + dataSource); } } public String getJndiBase() { return jndiBase; } public void setJndiBase(String jndiBase) { this.jndiBase = jndiBase; } public String getChangeLog() { return changeLog; } public void setChangeLog(String changeLog) { this.changeLog = changeLog; } public String getContexts() { return contexts; } public void setContexts(String contexts) { this.contexts = contexts; } public Map getParameters() { return parameters; } public void setParameters(Map parameters) { this.parameters = parameters; } public String getDefaultSchema() { return defaultSchema; } public void setDefaultSchema(String defaultSchema) { this.defaultSchema = defaultSchema; } public boolean isDropFirst() { return dropFirst; } public void setDropFirst(boolean dropFirst) { this.dropFirst = dropFirst; } public boolean isShouldRun() { return shouldRun; } public void setShouldRun(boolean shouldRun) { this.shouldRun = shouldRun; } public File getRollbackFile() { return rollbackFile; } public void setRollbackFile(File rollbackFile) { this.rollbackFile = rollbackFile; } @Override public void setResourceLoader(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy