/* vim: set ts=2 et sw=2 cindent fo=qroca: */ package com.globant.katari.tools; import java.io.File; import java.sql.Connection; import java.sql.SQLException; import javax.sql.DataSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; import org.springframework.web.context.support.XmlWebApplicationContext; import org.springframework.mock.web.MockServletContext; import org.springframework.core.io.FileSystemResourceLoader; import org.springframework.jdbc.datasource.DataSourceUtils; import javax.servlet.ServletContext; /** Utility class to give support to test cases. * * This class will give access to spring beans and help you with database * related tests. */ public abstract class SpringTestUtilsBase { /** The class logger. */ private static Log log = LogFactory.getLog(SpringTestUtilsBase.class); /** The spring configuration files for the global application context. */ private String[] globalConfigurationFiles; /** The spring configuration files for the spring dispatcher servlet * application context. */ private String[] servletConfigurationFiles; /** a data source. */ private DataSource dataSource = null; /** Bean factory. */ private ApplicationContext beanFactory; /** Company spring servlet Bean factory. */ private ApplicationContext servletBeanFactory; /** The katari transaction manager for the application context. */ private PlatformTransactionManager transactionManager = null; /** The current transaction status. */ private TransactionStatus transactionStatus = null; /** Constructor. * * @param theGlobalConfigurationFiles the list of configuration files to * create the global application context. It cannot be null. * * @param theServletConfigurationFiles the list of configuration files to * create the spring dispatcher servlet application context. It cannot be * null. */ protected SpringTestUtilsBase(final String[] theGlobalConfigurationFiles, final String[] theServletConfigurationFiles) { globalConfigurationFiles = theGlobalConfigurationFiles; servletConfigurationFiles = theServletConfigurationFiles; } /** Gets the configured data source. * * @return a DataSource. */ private synchronized DataSource getDataSource() { if (dataSource == null) { beanFactory = getBeanFactory(); dataSource = (DataSource) beanFactory.getBean("dataSource"); } return dataSource; } /** Gets the connection to the database, enlisted to the current transaction * if any. * * @return a Connection. * * @exception SQLException if a database access error occurs */ public synchronized Connection getConnection() throws SQLException { if (dataSource == null) { beanFactory = getBeanFactory(); dataSource = (DataSource) beanFactory.getBean("dataSource"); } Connection connection = DataSourceUtils.getConnection(dataSource); return connection; } /** This method returns a BeanFactory. * * @return a BeanFactory */ public synchronized ApplicationContext getBeanFactory() { log.trace("Entering getBeanFactory"); if (beanFactory == null) { log.debug("Creating the global beanFactory"); XmlWebApplicationContext appContext = new XmlWebApplicationContext(); appContext.setConfigLocations(globalConfigurationFiles); if (new File("./src/main/webapp").exists()) { // We assume that the module references a web application if there is a // webapp directory. ServletContext sc = new MockServletContext("./src/main/webapp", new FileSystemResourceLoader()); appContext.setServletContext(sc); } appContext.refresh(); beanFactory = appContext; } log.trace("Leaving getBeanFactory"); return beanFactory; } /** This method returns a BeanFactory. * * @return a BeanFactory */ public synchronized ApplicationContext getServletBeanFactory() { if (servletBeanFactory == null) { log.info("Creating the servlet beanFactory"); servletBeanFactory = new FileSystemXmlApplicationContext( servletConfigurationFiles, getBeanFactory()); } return servletBeanFactory; } /** Obtains a bean from the global bean factory. * * @param beanName the name of the bean to search for in the bean factory. It * cannot be null. * * @return the bean named beanName, or null if not found. */ public Object getBean(final String beanName) { return getBeanFactory().getBean(beanName); } /** Obtains a bean from the spring dispatcher servlet bean factory or its * parent. * * @param beanName the name of the bean to search for in the bean factory. It * cannot be null. * * @return Retrieve the bean named beanName, or null if not found. */ public Object getServletBean(final String beanName) { return getServletBeanFactory().getBean(beanName); } /** Obtains the transactionManager from the application context. * * @return a transaction manager. */ private synchronized PlatformTransactionManager getTransactionManager() { if (transactionManager == null) { log.info("Creating a transactionManager"); transactionManager = (PlatformTransactionManager) getBeanFactory().getBean("katari.transactionManager"); } return transactionManager; } /** Begins a global transaction. * * This is used to guarantee that each unit test use a single hibernate * session. Only one transaction can be active at any given time. Calling * this operation implicitely commits the pending transaction, if any. * * This is usually called in a @Before method. */ public synchronized void beginTransaction() { log.trace("Entering beginTransaction"); endTransaction(); transactionStatus = getTransactionManager().getTransaction( new DefaultTransactionDefinition()); log.trace("Leaving beginTransaction"); } /** Commits the pending transaction (opened with beginTransaction), if any. * * This is usually be called in a @After method. */ public synchronized void endTransaction() { log.trace("Entering endTransaction"); if (transactionStatus != null && !transactionStatus.isCompleted()) { if (transactionStatus.isRollbackOnly()) { log.debug("Rollbacking transaction"); transactionManager.rollback(transactionStatus); } else { log.debug("Committing transaction"); transactionManager.commit(transactionStatus); } } transactionStatus = null; log.trace("Leaving endTransaction"); } /** Sets the files to use to load the global spring application context. * * @param fileNames the list of files. */ protected final void setGlobalConfigurationFiles( final String[] fileNames) { globalConfigurationFiles = fileNames; } }