The JDBC populator is a library with one core interface: net.sf.opk.populator.JDBCPopulator, which in turn has a single method: populateDatabase(java.sql.Connection). Its purpose is to populate a database just before it is used. As such, it can help to build an Instant Developer Experience.
In order to make this all work, the library also contains several implementations of this interface, als also implementations of javax.sql.DataSource and javax.sql.XADataSource.
As an example says more than a long explanation, the following example is a glassfish-resources.xml file that defines both an XA and a non-XA data source, both of which use a net.sf.opk.populator.JDBCPopulator to fill their respective databases. All possible uses of a net.sf.opk.populator.JDBCPopulator are demonstrated.
The same example (except the XA part) is also available for other containers.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN"
"http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
<!--
Underlying Local DataSource
-->
<jdbc-connection-pool name="UnderlyingPool" datasource-classname="org.hsqldb.jdbc.JDBCDataSource"
non-transactional-connections="true">
<property name="Url" value="jdbc:hsqldb:mem:MyApplicationDB"/>
<property name="User" value="sa"/>
<property name="Password" value=""/>
</jdbc-connection-pool>
<jdbc-resource pool-name="UnderlyingPool" jndi-name="jdbc/underlyingDataSource"/>
<!--
Underlying XA DataSource
-->
<jdbc-connection-pool name="UnderlyingPool" datasource-classname="org.hsqldb.jdbc.JDBCXADataSource"
non-transactional-connections="true">
<property name="Url" value="jdbc:hsqldb:mem:MyApplicationDB"/>
<property name="User" value="sa"/>
<property name="Password" value=""/>
</jdbc-connection-pool>
<jdbc-resource pool-name="UnderlyingPool" jndi-name="jdbc/underlyingXADataSource"/>
<!--
JDBC Populators
-->
<custom-resource jndi-name="test/populator-file" res-type="net.sf.opk.populator.sql.FileSqlPopulator"
factory-class="org.glassfish.resources.custom.factory.JavaBeanFactory">
<property name="fileName" value="src/main/config/database.sql"/>
</custom-resource>
<custom-resource jndi-name="test/populator-dir" res-type="net.sf.opk.populator.sql.DirectorySqlPopulator"
factory-class="org.glassfish.resources.custom.factory.JavaBeanFactory">
<property name="directoryName" value="src/main/config/db-updates"/>
</custom-resource>
<custom-resource jndi-name="test/populator" res-type="net.sf.opk.populator.CompositeJDBCPopulator"
factory-class="org.glassfish.resources.custom.factory.JavaBeanFactory">
<property name="populatorNames" value="test/populator-file test/populator-dir"/>
</custom-resource>
<!--
Local DataSource for use by your application
-->
<jdbc-connection-pool name="LocalPool" datasource-classname="net.sf.opk.populator.PopulatingDataSource"
connection-validation-method="meta-data" is-connection-validation-required="true">
<property name="PopulatorName" value="test/populator"/>
<property name="DelegateName" value="jdbc/underlyingDataSource"/>
</jdbc-connection-pool>
<jdbc-resource pool-name="LocalPool" jndi-name="jdbc/myApplicationDataSource"/>
<!--
XA DataSource for use by your application
-->
<jdbc-connection-pool name="LocalPool" datasource-classname="net.sf.opk.populator.PopulatingXADataSource"
connection-validation-method="meta-data" is-connection-validation-required="true">
<property name="PopulatorName" value="test/populator"/>
<property name="DelegateName" value="jdbc/underlyingXADataSource"/>
</jdbc-connection-pool>
<jdbc-resource pool-name="LocalPool" jndi-name="jdbc/myApplicationXADataSource"/>
</resources>
The JDBCPopulator is called upon first use of each data source.
This enables the creation of an Instant Developer Experience, as a datasource for an in-memory database can be populated upon first use. This means that if you start the application, for example by using the Embedded GlassFish Web Plugin, your application will have data available.
Additionally, the JDBCPopulator can also populate our EJB component tests. Using JavaEE 6, you can use:
@DataSourceDefinition(name="java:global/MyApp/MyDataSource", ...)
public MyCodeTest
{
@Resource(name = "java:global/MyApp/MyDataSource")
DataSource datasource;
@Before
public void populateDatabase() throws SQLException, IOException
{
try (Connection connection = datasource.getConnection())
{
JDBCPopulator populator = new net.sf.opk.populator.sql.FileSqlPopulator("/path/to/file.sql");
populator.populateDatabase(datasource.getConnection());
}
}
}