package org.genedb.db.loading;
import org.genedb.db.dao.OrganismDao;
import org.genedb.db.loading.EmblLoader.OverwriteExisting;
import org.gmod.schema.mapped.Organism;
import org.apache.log4j.Logger;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.springframework.transaction.annotation.Transactional;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/**
* A utility class to help in writing tests for the EMBL loader.
* An instance of this class corresponds to a single input EMBL file,
* and utility methods make it easy to test specific properties of
* the loaded data. See the test classes {@link EmblLoaderBergheiTest}
* and {@link EmblLoaderMansoniTest} for examples of its use.
* <p>
* Note that this class explicitly manages the Hibernate session,
* so your test class should <b>not</b> be annotated as <code>@Transactional</code>.
*
* @author rh11
*
*/
public class EmblLoaderTestHelper {
private static final Logger logger = TestLogger.getLogger(EmblLoaderTestHelper.class);
private EmblLoader loader;
private SessionFactory sessionFactory;
private OrganismDao organismDao;
private Session session;
private String filename;
private EmblLoaderTestHelper() {
// empty
}
/**
* Create a test helper for the given organism and filename. This loads the given
* file into the organism, and returns a helper object that should be used to test
* that the data have been loaded as expected.
* <p>
* This method should usually be called from a <code>@BeforeClass</code> method of
* the test class.
* <p>
* The <code>cleanUp</code> method <strong>must</strong> be called when you have finished
* with the object.
*
* @param organismCommonName the common name of the organism
* @param filename the filename
* @return the test helper, which is used to test that the data have been loaded as expected
* @throws IOException if there is a problem reading the file
* @throws ParsingException if there is a problem interpreting the file
*/
public static EmblLoaderTestHelper create(String organismCommonName, String filename)
throws IOException, ParsingException
{
return create(organismCommonName, null, null, null, filename);
}
/**
* Create a test helper for the given organism and filename. This loads the given
* file into the organism, and returns a helper object that should be used to test
* that the data have been loaded as expected.
* <p>
* This method will create the organism, if there is not already an organism with the
* given common name.
* <p>
* This method should usually be called from a <code>@BeforeClass</code> method of
* the test class.
* <p>
* The <code>cleanUp</code> method <strong>must</strong> be called when you have finished
* with the object.
*
* @param organismCommonName the common name of the organism. If there is already an organism
* with the given common name, that organism is used.
* @param organismGenus the genus assigned to the organism, if a new organism is created (because
* there is no organism with the given common name in the skeleton database)
* @param organismSpecies the species name assigned to the organism, if a new organism is created (because
* there is no organism with the given common name in the skeleton database)
* @param organismStrain the strain name assigned to the organism, if a new organism is created (because
* there is no organism with the given common name in the skeleton database)
* @param filename the filename
* @return the test helper, which is used to test that the data have been loaded as expected
* @throws IOException if there is a problem reading the file
* @throws ParsingException if there is a problem interpreting the file
*/
public static EmblLoaderTestHelper create(String organismCommonName, String organismGenus,
String organismSpecies, String organismStrain, String filename)
throws IOException, ParsingException {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(new String[] {"Load.xml", "Test.xml"});
EmblLoaderTestHelper helper = applicationContext.getBean("emblLoaderTestHelper", EmblLoaderTestHelper.class);
helper.doLoad(organismCommonName, organismGenus,
organismSpecies, organismStrain, filename);
return helper;
}
private void doLoad(String organismCommonName, String organismGenus,
String organismSpecies, String organismStrain, String filename)
throws IOException, ParsingException {
if (organismGenus != null) {
createOrganismIfNecessary(organismCommonName, organismGenus,
organismSpecies, organismStrain);
}
loader.setReportUnusedQualifiers(true);
loader.setOrganismCommonName(organismCommonName);
loadFile(filename);
this.filename = filename;
}
/**
* Reload the same file as before, with the <tt>overwriteExisting</tt> flag set.
*
* @throws ParsingException
* @throws IOException
*/
public void reload() throws IOException, ParsingException {
if (this.filename == null) {
throw new IllegalStateException("Filename not set");
}
logger.info("Reloading file: " + filename);
loader.setOverwriteExisting(OverwriteExisting.YES);
loadFile(filename);
}
/**
* Close the session and shut down the database.
* This method should be called once the tests are complete.
* It should ordinarily be called from an <code>@AfterClass</code> method
* of the test class.
*/
public void cleanUp() {
/*
* If the database is not shutdown, the changes will not be
* persisted to the data file. It's useful to be able to inspect
* the loaded data directly sometimes, so it's important to do
* this. (The HSLQDB documentation suggests that comitted changes
* will never be lost even if the database is not shut down. That
* does not appear to be true.)
*/
session.createSQLQuery("shutdown").executeUpdate();
SessionFactoryUtils.releaseSession(session, sessionFactory);
session = null;
}
@Transactional
private void createOrganismIfNecessary(String organismCommonName,
String organismGenus,String organismSpecies, String organismStrain)
{
Session session = SessionFactoryUtils.getSession(sessionFactory, false);
Organism organism = organismDao.getOrganismByCommonName(organismCommonName);
if (organism != null) {
logger.debug(String.format("Organism '%s' already exists", organismCommonName));
return;
}
if (organismStrain != null) {
organismSpecies += " " + organismStrain;
}
logger.debug(String.format("Creating organism '%s' (%s %s)",
organismCommonName, organismGenus, organismSpecies));
organism = new Organism(organismGenus, organismSpecies, organismCommonName,
organismCommonName, null);
session.persist(organism);
session.flush();
}
@Transactional
private void loadFile(String filename) throws IOException, ParsingException,
FileNotFoundException, DataError {
File file = new File(filename);
EmblFile emblFile = new EmblFile(file, new FileReader(file));
loader.load(emblFile);
logger.debug("Finished loading");
}
/**
* Create a FeatureTester for the loaded data.
*
* @return
*/
public FeatureTester tester() {
return new FeatureTester(session);
}
/* Setters for Spring injection */
public void setLoader(EmblLoader loader) {
this.loader = loader;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
this.session = SessionFactoryUtils.getSession(sessionFactory, true);
}
public void setOrganismDao(OrganismDao organismDao) {
this.organismDao = organismDao;
}
}