*
* It is used for instance to pass a transaction scoped entity manager around.
*
+ * The {@link #set(Object)} method sets the current service instance for the current thread.
+ * The {@link #get()} method gets the current service instance for the current thread.
+ * The {@link #getProxy()} method gets a proxy that will delegate at runtime to the thread-specific
+ * instance. The result from this method can be passed at construction of an object that will be used
+ * by multiple threads.
+ *
* @param T
* Interface to proxy.
* @author Erik Brakkee
import org.apache.commons.dbcp.PoolingDataSource;
import org.apache.commons.pool.impl.GenericObjectPool;
+/**
+ * Abstract database class providing the creation of the datasource,
+ * preventing duplicate starts of the same database, and checking
+ * for connection leaks when the database is stopped.
+ *
+ * @author Erik Brakkee
+ *
+ */
public abstract class AbstractDatabase implements Database {
/**
private boolean started;
+ /**
+ * Constructs the database.
+ */
protected AbstractDatabase() {
started = false;
}
+ /**
+ * To be implemented by subclasses to start the database.
+ */
protected abstract void doStart();
+ /**
+ * To be implemented by subclasses to stop the database.
+ */
protected abstract void doStop();
/**
// / BELOW THIS LINE IS NOT OF INTEREST TO SUBCLASSES.
+ /**
+ * Starts the database.
+ */
public final DataSource start() {
if (started) {
throw new RuntimeException("Database already started");
return getDatasource();
}
+ /**
+ * Stops the database and tests for connection leaks.
+ * In cast the system property with the name given by {@link #IGNORE_CONNECTION_LEAK_PROPERTY}
+ * is set then the connection leaks are not checked.
+ */
public final void stop() {
if (!started) {
return; // nothing to do.
package org.wamblee.support.persistence;
import java.util.List;
-
+/**
+ * Base class for database providers.
+ *
+ * @author Erik Brakkee
+ */
public abstract class AbstractDatabaseProvider implements DatabaseProvider {
+ /**
+ * @return List of database capabilities.
+ */
protected abstract List<String> getCapabilities();
+ /**
+ * Standard implementation of the capabalities check.
+ */
public final boolean supportsCapabilities(String[] aCapabilities) {
for (String capability : aCapabilities) {
if (!getCapabilities().contains(capability)) {
import org.dbunit.dataset.filter.ITableFilterSimple;
+/**
+ * Composite JPA customizer that applies the customizations from several
+ * JPA customizers.
+ *
+ * @author Erik Brakkee
+ */
public class CompositeJpaCustomizer implements JpaCustomizer {
private List<JpaCustomizer> customizers;
private CompositeJpaTables tables;
+ /**
+ * Construcst the customizer.
+ * @param aCustomizers List of customizers.
+ */
public CompositeJpaCustomizer(List<JpaCustomizer> aCustomizers) {
customizers = aCustomizers;
tables = new CompositeJpaTables();
}
@Override
+ /**
+ * Applies all customizations in an undefined order.
+ */
public void customize(PersistenceUnitDescription aPersistenceUnit,
Map<String, String> aJpaProperties) {
for (JpaCustomizer customizer : customizers) {
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.filter.ITableFilterSimple;
+/**
+ * Composite JPA tables. Implements the logical or of several table filters.
+ *
+ * @author Erik Brakkee
+ */
public class CompositeJpaTables implements ITableFilterSimple {
private List<ITableFilterSimple> tables;
+ /**
+ * Construcst the tables.
+ */
public CompositeJpaTables() {
tables = new ArrayList<ITableFilterSimple>();
}
+ /**
+ * Adds a table filter.
+ * @param aFilter filter.
+ */
public void add(ITableFilterSimple aFilter) {
tables.add(aFilter);
}
private static ServiceLoader<DatabaseProvider> LOADER =
ServiceLoader.load(DatabaseProvider.class);
+ /**
+ * Constructs the database builder.
+ */
private DatabaseBuilder() {
// Empty.
}
package org.wamblee.support.persistence;
/**
- * This class is used for starting the database from ant.
+ * This class is used for starting the database as a main program.
*/
public class DatabaseStarter {
*/
public class DatabaseUtils {
+ /**
+ * Represents a set of tables.
+ *
+ * @author Erik Brakkee
+ */
public static interface TableSet {
boolean contains(String aTableName);
}
+ /**
+ * Represents a unit of work (transaction).
+ *
+ * @author Erik Brakkee
+ *
+ * @param <T> Type of return value.
+ */
public static interface JdbcUnitOfWork<T> {
+ /**
+ * Executes statement within a transaction.
+ * @param aConnection Connection.
+ * @return Result of the work.
+ * @throws Exception
+ */
T execute(Connection aConnection) throws Exception;
}
+ /**
+ * Operation to be executed on a set of tables for each table
+ * individually.
+ *
+ * @author Erik Brakkee
+ */
public static interface TableSetOperation {
+ /**
+ * Executes on a table.
+ * @param aTable Table name.
+ * @throws Exception
+ */
void execute(String aTable) throws Exception;
}
connections.clear();
}
+ /**
+ * Creates database tester.
+ * @param aTables Tables to create the tester for.
+ * @return Database tester.
+ * @throws Exception
+ */
public IDatabaseTester createDbTester(ITableFilterSimple aTables) throws Exception {
return createDbTester(getTableNames(aTables));
}
-
+
+ /**
+ * Creates database tester.
+ * @param aTables Tables to create the tester for.
+ * @return Database tester.
+ * @throws Exception
+ */
public IDatabaseTester createDbTester(String[] aTables) throws Exception {
IDatabaseConnection connection = dbtester.getConnection();
connections.add(connection);
return dbtester;
}
+ /**
+ * Executes an operation on a set of tables.
+ * @param aTables Tables.
+ * @param aOperation Operation.
+ * @throws Exception
+ */
public void executeOnTables(ITableFilterSimple aTables,
final TableSetOperation aOperation) throws Exception {
final String[] tableNames = getTableNames(aTables);
});
}
+ /**
+ * Cleans a number of database tables. This means deleting the content not dropping the tables.
+ * This may fail in case of cyclic dependencies between the tables (current limitation).
+ * @param aSelection Tables.
+ * @throws Exception
+ */
public void cleanDatabase(ITableFilterSimple aSelection) throws Exception {
final String[] tableNames = getTableNames(aSelection);
}
- public <T> T executeInTransaction(JdbcUnitOfWork<T> aCallback)
+ /**
+ * Executes a unit of work within a transaction.
+ * @param <T> Result type of th ework.
+ * @param aWork Unit of work.
+ * @return
+ * @throws Exception
+ */
+ public <T> T executeInTransaction(JdbcUnitOfWork<T> aWork)
throws Exception {
Connection connection = dataSource.getConnection();
connection.setAutoCommit(false);
try {
- T value = aCallback.execute(connection);
+ T value = aWork.execute(connection);
connection.commit();
return value;
} finally {
}
/**
- * @throws SQLException
+ * Returns table names based on a table filter.
+ * @param aSelection Table filter.
+ * @return Table names.
+ * @throws Exception
*/
public String[] getTableNames(ITableFilterSimple aSelection)
throws Exception {
}
/**
- * @return
- * @throws SQLException
+ * Use {@link #cleanDatabase(ITableFilterSimple)} instead.
*/
+ @Deprecated
public void emptyTables(final ITableFilterSimple aSelection)
throws Exception {
executeOnTables(aSelection, new TableSetOperation() {
}
/**
- * @return
- * @throws SQLException
+ * User {@link #cleanDatabase(ITableFilterSimple)} instead.
*/
+ @Deprecated
public void emptyTable(String aTable) throws Exception {
executeSql("delete from " + aTable);
}
+ /**
+ * Drops tables. This only works if there are no cyclic dependencies between the tables.
+ * @param aTables Tables to drop.
+ * @throws Exception
+ */
public void dropTables(ITableFilterSimple aTables) throws Exception {
final String[] tableNames = getTableNames(aTables);
String[] sortedTables = executeInTransaction(new JdbcUnitOfWork<String[]>() {
}
/**
- * @return
- * @throws SQLException
+ * Drops a table.
+ * @param aTable Table to drop.
+ * @throws Exception
*/
public void dropTable(final String aTable) throws Exception {
executeInTransaction(new JdbcUnitOfWork<Void>() {
}
}
+ /**
+ * Executes an update.
+ * @param aConnection Connection to use.
+ * @param aSql SQL update to use.
+ * @param aArgs Arguments to the update.
+ * @return Number of rows updated.
+ */
public int executeUpdate(Connection aConnection, final String aSql,
final Object... aArgs) {
try {
}
/**
- * @return
+ * Gets the table size.
+ * @param aTable Table.
+ * @return Table size.
* @throws SQLException
*/
public int getTableSize(final String aTable) throws Exception {
}
+ /**
+ * Counts the results in a result set.
+ * @param aResultSet Resultset.
+ * @return Number of rows in the set.
+ * @throws SQLException
+ */
public int countResultSet(ResultSet aResultSet) throws SQLException {
int count = 0;
import java.util.List;
/**
+ * Derby database provider.
*
- * @author $author$
- * @version $Revision$
+ * @author Erik Brakkee
*/
public class DerbyDatabaseProvider extends AbstractDatabaseProvider {
/**
import java.util.Arrays;
import java.util.List;
+/**
+ * Database provider for an external database.
+ *
+ * @author Erik Brakkee
+ */
public class ExternalDatabaseProvider extends AbstractDatabaseProvider {
/**
*/
public interface JpaCustomizer {
+ /**
+ * Customizes the persistence unit through properties.
+ * @param aPersistenceUnit Persistence unit.
+ * @param aJpaProperties Current properties.
+ */
void customize(PersistenceUnitDescription aPersistenceUnit,
Map<String, String> aJpaProperties);
+ /**
+ * Gets the tables specific to the JPA provider.
+ * @return Tables.
+ */
ITableFilterSimple getJpaTables();
}
import java.util.List;
import java.util.ServiceLoader;
+/**
+ * JPA customizer builder implements the {@link ServiceLoader} based mechanism for looking up
+ * JPA customizers.
+ */
public class JpaCustomizerBuilder {
private static final ServiceLoader<JpaCustomizer> CUSTOMIZERS = ServiceLoader
.load(JpaCustomizer.class);
+ /**
+ * Gets the customizer to use. This is a composite customizer that combines all customizers that
+ * were found.
+ * @return JPA customizer.
+ */
public static JpaCustomizer getCustomizer() {
List<JpaCustomizer> customizers = new ArrayList<JpaCustomizer>();
for (JpaCustomizer customizer : CUSTOMIZERS) {
}
}
+ /**
+ * Gets the database.
+ * @return Database.
+ */
public Database getDb() {
return db;
}
+ /**
+ * Gets the datasource.
+ * @return Datasource.
+ */
public DataSource getDataSource() {
return dataSource;
}
+ /**
+ * Gets the database utilities.
+ * @return Database utilities.
+ */
public DatabaseUtils getDbUtils() {
return dbUtils;
}
+ /**
+ * Gets the jpa builder.
+ * @return JPA builder.
+ */
public JpaBuilder getJpaBuilder() {
return jpaBuilder;
}
+ /**
+ * Gets the persistence unit.
+ * @return Persistence unit.
+ */
public PersistenceUnitDescription getPersistenceUnit() {
return persistenceUnit;
}