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

net.java.ao.test.junit.ActiveObjectTransactionMethodRule Maven / Gradle / Ivy

There is a newer version: 6.1.1
Show newest version
package net.java.ao.test.junit;

import net.java.ao.DelegateConnection;
import net.java.ao.EntityManager;
import net.java.ao.builder.EntityManagerBuilder;
import net.java.ao.builder.EntityManagerBuilderWithDatabaseProperties;
import net.java.ao.schema.FieldNameConverter;
import net.java.ao.schema.IndexNameConverter;
import net.java.ao.schema.SequenceNameConverter;
import net.java.ao.schema.TableNameConverter;
import net.java.ao.schema.TriggerNameConverter;
import net.java.ao.schema.UniqueNameConverter;
import net.java.ao.test.jdbc.Data;
import net.java.ao.test.jdbc.DatabaseUpdater;
import net.java.ao.test.jdbc.JdbcConfiguration;
import net.java.ao.test.jdbc.NonTransactional;
import net.java.ao.test.jdbc.NullDatabase;
import org.junit.rules.MethodRule;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.HashMap;
import java.util.Map;

import static net.java.ao.sql.SqlUtils.closeQuietly;

/**
 *
 */
public class ActiveObjectTransactionMethodRule implements MethodRule {
    private static final Map DATABASES = new HashMap();

    private final Object test;
    private final JdbcConfiguration jdbc;
    private final TableNameConverter tableNameConverter;
    private final FieldNameConverter fieldNameConverter;
    private final SequenceNameConverter sequenceNameConverter;
    private final TriggerNameConverter triggerNameConverter;
    private final IndexNameConverter indexNameConverter;
    private final UniqueNameConverter uniqueNameConverter;

    private EntityManager entityManager;
    private File indexDirectory;

    public ActiveObjectTransactionMethodRule(Object test,
                                             JdbcConfiguration jdbc,
                                             TableNameConverter tableNameConverter,
                                             FieldNameConverter fieldNameConverter,
                                             SequenceNameConverter sequenceNameConverter,
                                             TriggerNameConverter triggerNameConverter,
                                             IndexNameConverter indexNameConverter,
                                             UniqueNameConverter uniqueNameConverter) {
        this.test = test;
        this.jdbc = jdbc;
        this.tableNameConverter = tableNameConverter;
        this.fieldNameConverter = fieldNameConverter;
        this.sequenceNameConverter = sequenceNameConverter;
        this.triggerNameConverter = triggerNameConverter;
        this.indexNameConverter = indexNameConverter;
        this.uniqueNameConverter = uniqueNameConverter;
    }

    public final Statement apply(final Statement base, final FrameworkMethod method, final Object target) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                before(method);
                final boolean useTransaction = useTransaction(method);
                Connection c = null;
                try {
                    if (useTransaction) {
                        c = entityManager.getProvider().startTransaction();
                    }

                    base.evaluate();
                } finally {
                    if (useTransaction && c != null) {
                        entityManager.getProvider().rollbackTransaction(c);

                        // make it closeable
                        if (c instanceof DelegateConnection)
                            ((DelegateConnection) c).setCloseable(true);
                        // close it
                        closeQuietly(c);
                    }
                    after(method);
                }
            }
        };
    }

    protected void before(FrameworkMethod method) throws Throwable {
        entityManager = createEntityManagerAndUpdateDatabase();
        injectEntityManager();
    }

    private void createIndexDir() {
        try {
            indexDirectory = File.createTempFile("ao_test", "index");
            indexDirectory.delete();
            indexDirectory.mkdirs();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    protected void after(FrameworkMethod method) {
        if (!useTransaction(method)) {
            // make sure that the next test gets a clean database
            final DatabaseConfiguration databaseConfiguration = DATABASES.remove(jdbc);
            databaseConfiguration.getEntityManager().getProvider().dispose();
        }
        entityManager = null;
    }

    private boolean useTransaction(FrameworkMethod method) {
        return !method.getMethod().isAnnotationPresent(NonTransactional.class);
    }

    private void removeIndexDir() {
        removeFile(indexDirectory);
    }

    private void removeFile(File file) {
        if (file == null || !file.exists()) {
            return;
        }

        if (file.isFile()) {
            file.delete();
        } else {
            for (File f : file.listFiles()) {
                removeFile(f);
            }
            file.delete(); // now we can delete the empty directory
        }
    }

    private EntityManager createEntityManagerAndUpdateDatabase() throws Exception {
        final Class databaseUpdater = isDataAnnotationPresent() ? getDataAnnotationValue() : getDataAnnotationDefaultValue();
        final DatabaseConfiguration dbConfiguration = newDatabaseConfiguration(databaseUpdater);
        final EntityManager entityManager;
        if (databaseUpdater == NullDatabase.class) {
            entityManager = createEntityManager();
            entityManager.migrateDestructively(); // empty the database
            DATABASES.remove(jdbc);
        } else if (!DATABASES.containsKey(jdbc) || !DATABASES.get(jdbc).equals(dbConfiguration)) {
            entityManager = createEntityManager();
            entityManager.migrateDestructively(); // empty the database
            newInstance(databaseUpdater).update(entityManager);
            dbConfiguration.setEntityManager(entityManager);
            DATABASES.put(jdbc, dbConfiguration);
        } else {
            entityManager = DATABASES.get(jdbc).getEntityManager();
        }

        return entityManager;
    }

    private DatabaseConfiguration newDatabaseConfiguration(Class databaseUpdater) {
        final Class tableNameConverterClass = (Class) getClass(tableNameConverter);
        final Class fieldNameConverterClass = (Class) getClass(fieldNameConverter);
        final Class sequenceNameConverterClass = (Class) getClass(sequenceNameConverter);
        final Class triggerNameConverterClass = (Class) getClass(triggerNameConverter);
        final Class indexNameConverterClass = (Class) getClass(indexNameConverter);
        return new DatabaseConfiguration(databaseUpdater, tableNameConverterClass, fieldNameConverterClass, sequenceNameConverterClass, triggerNameConverterClass, indexNameConverterClass);
    }

    private Class getClass(Object o) {
        return o != null ? o.getClass() : null;
    }

    private EntityManager createEntityManager() {
        EntityManagerBuilderWithDatabaseProperties entityManagerBuilder = EntityManagerBuilder.url(jdbc.getUrl()).username(jdbc.getUsername()).password(jdbc.getPassword()).schema(jdbc.getSchema()).auto();

        if (tableNameConverter != null) {
            entityManagerBuilder = entityManagerBuilder.tableNameConverter(tableNameConverter);
        }
        if (fieldNameConverter != null) {
            entityManagerBuilder = entityManagerBuilder.fieldNameConverter(fieldNameConverter);
        }
        if (sequenceNameConverter != null) {
            entityManagerBuilder = entityManagerBuilder.sequenceNameConverter(sequenceNameConverter);
        }
        if (triggerNameConverter != null) {
            entityManagerBuilder = entityManagerBuilder.triggerNameConverter(triggerNameConverter);
        }
        if (indexNameConverter != null) {
            entityManagerBuilder = entityManagerBuilder.indexNameConverter(indexNameConverter);
        }
        if (uniqueNameConverter != null) {
            entityManagerBuilder = entityManagerBuilder.uniqueNameConverter(uniqueNameConverter);
        }

        return entityManagerBuilder.build();
    }

    private void injectEntityManager() {
        final Field field = getEntityManagerField(getTestClass());
        final boolean isFieldAccessible = field.isAccessible();
        try {
            field.setAccessible(true);
            try {
                field.set(test, entityManager);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        } finally {
            field.setAccessible(isFieldAccessible);
        }
    }

    private Class getDataAnnotationDefaultValue() throws NoSuchMethodException {
        @Data
        final class C {
        }
        return C.class.getAnnotation(Data.class).value();
    }

    private Class getDataAnnotationValue() {
        return getTestClass().getAnnotation(Data.class).value();
    }

    private boolean isDataAnnotationPresent() {
        return getTestClass().isAnnotationPresent(Data.class);
    }

    private  T newInstance(Class aClass) {
        try {
            return aClass.newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    private Class getTestClass() {
        return test.getClass();
    }

    private Field getEntityManagerField(Class aClass) {
        for (Field field : aClass.getDeclaredFields()) {
            if (field.getType().equals(EntityManager.class)) {
                return field;
            }
        }

        if (!aClass.getSuperclass().equals(Object.class)) {
            return getEntityManagerField(aClass.getSuperclass());
        }

        return null;
    }

    private static final class DatabaseConfiguration {
        private final Class databaseUpdaterClass;
        private final Class tableNameConverterClass;
        private final Class fieldNameConverterClass;
        private final Class sequenceNameConverterClass;
        private final Class triggerNameConverterClass;
        private final Class indexNameConverterClass;

        private EntityManager entityManager;

        public DatabaseConfiguration(Class databaseUpdaterClass,
                                     Class tableNameConverterClass,
                                     Class fieldNameConverterClass,
                                     Class sequenceNameConverterClass,
                                     Class triggerNameConverterClass,
                                     Class indexNameConverterClass) {
            this.databaseUpdaterClass = databaseUpdaterClass;
            this.tableNameConverterClass = tableNameConverterClass;
            this.fieldNameConverterClass = fieldNameConverterClass;
            this.sequenceNameConverterClass = sequenceNameConverterClass;
            this.triggerNameConverterClass = triggerNameConverterClass;
            this.indexNameConverterClass = indexNameConverterClass;
        }

        public void setEntityManager(EntityManager entityManager) {
            this.entityManager = entityManager;
        }

        public EntityManager getEntityManager() {
            return entityManager;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }

            final DatabaseConfiguration that = (DatabaseConfiguration) o;

            if (databaseUpdaterClass != null ? !databaseUpdaterClass.equals(that.databaseUpdaterClass) : that.databaseUpdaterClass != null) {
                return false;
            }
            if (fieldNameConverterClass != null ? !fieldNameConverterClass.equals(that.fieldNameConverterClass) : that.fieldNameConverterClass != null) {
                return false;
            }
            if (indexNameConverterClass != null ? !indexNameConverterClass.equals(that.indexNameConverterClass) : that.indexNameConverterClass != null) {
                return false;
            }
            if (sequenceNameConverterClass != null ? !sequenceNameConverterClass.equals(that.sequenceNameConverterClass) : that.sequenceNameConverterClass != null) {
                return false;
            }
            if (tableNameConverterClass != null ? !tableNameConverterClass.equals(that.tableNameConverterClass) : that.tableNameConverterClass != null) {
                return false;
            }
            if (triggerNameConverterClass != null ? !triggerNameConverterClass.equals(that.triggerNameConverterClass) : that.triggerNameConverterClass != null) {
                return false;
            }

            return true;
        }

        @Override
        public int hashCode() {
            int result = databaseUpdaterClass != null ? databaseUpdaterClass.hashCode() : 0;
            result = 31 * result + (tableNameConverterClass != null ? tableNameConverterClass.hashCode() : 0);
            result = 31 * result + (fieldNameConverterClass != null ? fieldNameConverterClass.hashCode() : 0);
            result = 31 * result + (sequenceNameConverterClass != null ? sequenceNameConverterClass.hashCode() : 0);
            result = 31 * result + (triggerNameConverterClass != null ? triggerNameConverterClass.hashCode() : 0);
            result = 31 * result + (indexNameConverterClass != null ? indexNameConverterClass.hashCode() : 0);
            return result;
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy