+/*
+ * Copyright 2005-2010 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
/**
- * This package provide a number of utilities for database testing and in particular with
- * JPA.
+ * <p>
+ * This package provides test library for database testing in general and JPA testing
+ * specifically. As part of this it provides a means to transparently start an inmemory
+ * database from a junit test or connect to an external database. Also, given a persistence
+ * unit it is easy to start testing it in a junit test with only a few lines of code.
+ * </p>
*
- * The following utilities are available:
+ * <p>
+ * The main use cases are explained below:
+ * </p>
* <ul>
- * <li> {@link JpaTester}: The main entry point for all JPA tests.
+ * <li> <a href="#db-basic">Basic database testing, transparently connecting to a database</a>
+ * </li>
+ * <li> <a href="#db-basic-external">Connecting to an external database</a>
+ * </li>
+ * <li> <a href="#db-utils">Executing code within a JDBC transaction</a>
* </li>
- * <li> {@link JpaBuilder}: A utility constructed by <code>JpaTester</code> that provides a callback based
- * style of working with transaction-scoped entity managers.
+ * <li> <a href="#db-unit">Using DB Unit in your tests</a>
* </li>
- * <li> {@link DatabaseUtils}: A utility constructed by <code>JpaTester</code> for working with databases in general. Test code will not use this
- * utility often.
+ * <li> <a href="#db-jpa-basic">Basic JPA testing</a>
* </li>
- * <li> {@link org.dbunit.IDatabaseTester}: A DB unit database tester. The test code can use this database tester.
- * It is also created by <code>JpaTester</code>
+ * <li> <a href="#db-jpa-plus-jdbc">JPA testing combined with JDBC and DBUnit</a>
* </li>
- * <li> {@link DatabaseBuilder}: A utility by which test code can transparently create an inmemory database or
- * connect to an external database. This is also used by <code>JpaTester</code>
+ * <li> <a href="#db-jpa-services">Testing a service that requires a transaction</a>
* </li>
* </ul>
+ *
+ * <p>
+ * See also the <a href="#design-overview">design overview</a>.
+ * </p>
+ *
+ * <a name="db-basic">
+ * <h2>Basic database testing, transparently connecting to a database</h2>
+ * </a>
+ * Starting the database:
+ * <pre>
+ * Database db = DatabaseBuilder.getDatabase();
+ * DataSource dataSource = db.start();
+ * </pre>
+ * <p>
+ * If nothing is specified in the user's environment, an inmemory database is started (derby).
+ * Using the datasource is just standard JDBC now.
+ * </p>
+ * <p>
+ * After a test it is good practice to stop the database:
+ * </p>
+ * <pre>
+ * db.stop();
+ * </pre>
+ *
+ * <a name="db-basic-external">
+ * <h2>Connecting to an external database</h2>
+ * </a>
+ *
+ * Connecting to an external database can be done by requiring the 'external' capability on
+ * the database provider.
+ * <pre>
+ * Database db = DatabaseBuilder.getDatabase(DatabaseProvider.CAPABILITY_EXTERNAL);
+ * </pre>
+ * This also requires a number of environment variables or system properties to be set,
+ * see {@link ExternalDatabase}.
+ *
+ * <p>
+ * However, the most convenient way to set the capabilities is usually to set a system property or environment
+ * variable see the javadocs of {@link DatabaseBuilder}. and
+ * specifically <code>DatabaseBuilder.DB_CAPABILITIES_PROP</code>
+ * </p>
+ *
+ *
+ * <a name="db-utils">
+ * <h2>Executing code within a JDBC transaction</h2>
+ * </a>
+ * <p>
+ * To execute code withing a JDBC transaction, use the {@link DatabaseUtils} and
+ * use the {@link DatabaseUtils#executeInTransaction(org.wamblee.support.persistence.DatabaseUtils.JdbcUnitOfWork)}
+ * method.
+ * </p>
+ * <pre>
+ * DatabaseUtils dbutils = new DatabaseUtils(dataSource);
+ * boolean result = dbutils.executeInTransaction(
+ * new JdbcUnitOfWork<Boolean>() {
+ * @Override
+ * public Boolean execute(Connection aConnection) throws Exception {
+ * ResultSet res = jpaTester.getDbUtils().executeQuery(
+ * aConnection, GROUP_QUERY, aGroup);
+ * return res.next();
+ * }
+ * });
+ * </pre>
+ * {@link DatabaseUtils} also provides various other utility methods to work with JDBC queries.
+ *
+ * <a name="db-unit">
+ * <h2>Using DB Unit in your tests</h2>
+ * </a>
+ *
+ * <p>To work with <a href="http://dbunit.org">DBUnit</a>,
+ * <code>DatabaseUtils#createDbTester(org.dbunit.dataset.filter.ITableFilterSimple)</code>
+ * must be used passing it in the tables to use in the form of a {@link org.dbunit.dataset.filter.ITableFilterSimple}
+ * object. </p>
+ *
+ * <pre>
+ * IDatabaseTester dbtester = dbutils.createDbTester(new ITableFilterSimple() {
+ * public boolean accept(String aTableName) throws DataSetException {
+ * return aTableName.startsWith("XYZ_");
+ * }
+ * });
+ * </pre>
+ *
+ * <p>The reason for using a <code>DatabaseUtils</code> instead of DBUnit directly is that
+ * <code>DatabseUtils</code> will keep track of connections and close them when <code>DatabaseUtils</code>
+ * is closed</p>
+ *
+ * <a name="db-jpa-basic">
+ * <h2>Basic JPA testing</h2>
+ * </a>
+ * <p>
+ * First step is to create a {@link PersistenceUnitDescription} that matches the persistence unit you
+ * want to test.
+ * </p>
+ * <p>Second step is to make sure that all entities are listed explicitly in your
+ * <code>persistence.xml</code>. Currently, class path scanning appears to fail when
+ * run from junit.
+ * Specifying all entities explicitly is not necessarily a bad thing as it is also more efficient.
+ * </p>
+ *
+ * <p>
+ * Now create a <code>JpaTester</code> in your test code:
+ * </p>
+ * <pre>
+ * @Before
+ * public void setUp() throws Exception {
+ *
+ * // First we create the JpaTester by telling us which persistence unit we
+ * // are going to test
+ * jpaTester = new JpaTester(new MyPersistenceUnit());
+ * jpaTester.start();
+ * }
+ * </pre>
+ *
+ * <p>
+ * Then in test code execute some JPA code within a unit of work:
+ * </p>
+ * <pre>
+ * jpaTester.getJpaBuilder().execute(new JpaUnitOfWork<Void>() {
+ * public Void execute(EntityManager aEm) {
+ * MyEntity entity = new MyEntity("a", "b");
+ * aEm.persist(entity);
+ * return null;
+ * }
+ * });
+ * </pre>
+ *
+ * <a name="db-jpa-plus-jdbc">
+ * <h2>JPA testing combined with JDBC and DBUnit</h2>
+ * </a>
+ * <p>The <code>JPATester</code> provides access to all required object. It is usually convenient to
+ * get them directly from the <code>JPATester</code> after initializing it:
+ * <pre>
+ * builder = jpaTester.getJpaBuilder();
+ * dbutils = jpaTester.getDbUtils();
+ * dbtester = dbutils.createDbTester(new MyTables());
+ * </pre>
+ *
+ * <a name="db-jpa-services">
+ * <h2>Testing a service that requires a transaction</h2>
+ * </a>
+ *
+ * <p>Using {@link TransactionProxyFactory} it is possible to create a proxy for a given
+ * service interface to provide the semantics of 'requires new' transaction semantics.
+ * <pre>
+ * TransactionProxyFactory<Service> factory = new TransactionProxyFactory<Service>(
+ * jpaTester.getJpaBuilder(), Service.class);
+ * Service service = new ServiceImpl(factory.getTransactionScopedEntityManager());
+ * Service proxy = factory.getProxy(service);
+ * proxy.execute(...);
+ * </pre>
+ *
+ * <p>
+ * In the above example, the <code>Service</code> POJO requires an {@link EntityManager} in its
+ * constructor and it is passed a transaction scoped entitymanager from the factory. This entitymanager
+ * is in fact a so-called contextual reference.
+ * Next, the proxy is obtained from the factory. Invoking any method on it will make sure a new
+ * transaction is started and a new entity manager is created for the scope of that transaction.
+ * </p>
+ *
+ * <a name="design-overview">
+ * <h2>Design overview</h2>
+ * </a>
+ *
+ * <h3>Database transparency</h3>
+ *
+ * <br/>
+ * <img src="doc-files/Class_Diagram__org.wamblee.support.persistence__database.jpg"
+ * alt="database"/>
+ * </br/>
+ * <p>
+ * {@link DatabaseProvider} uses <code>java.util.ServiceLoader</code> to find all implementations
+ * of {@link DatabaseProvider} on the classpath. It then asks the database providers whether
+ * they support the required capabilities (by default inmemory), and the first provider that
+ * supports the capabilities is used to create the database.
+ * </p>
+ * <p>
+ * Note that the <code>Database</code> interface is not intended to always create a database.
+ * It will do so for {@link DerbyDatabase} (inmemory), but with {@link ExternalDatabase}
+ * it simply connects to an external database based on system properties or environment
+ * variables.
+ * </p>
+ *
+ * <h3>JPA tester overview</h3>
+ *
+ * <br/>
+ * <img src="doc-files/Class_Diagram__org.wamblee.support.persistence__jpatester.jpg"
+ * alt="database"/>
+ * </br/>
+ *
+ * <p><code>JPATester</code> is responsible for:</p>
+ * <ul>
+ * <li> Starting or connecting to a database, using {@link DatabaseBuilder}.
+ * </li>
+ * <li> Registering the acquired datasource in JNDI by first stubbing JNDI
+ * using {@link org.wamblee.support.jndi.StubInitialContextFactory}.
+ * </li>
+ * <li> Creating the {@link JPABuilder} that will do the JPA heavy lifting.
+ * </li>
+ * <li> Creating the {@link DatabaseUtils} for JDBC and DBUnit testing.
+ * </li>
+ * </ul>
+ *
+ *
*/
package org.wamblee.support.persistence;
+
+