Home  >  Development  >  features

Anatomy of an Enterprise Flex RIA Part 6: The Data Project Maven Build

| | Comments (1)
AddThis Social Bookmark Button
 
riaseries_part6.jpg
Last installment we examined the Maven build lifecycle and where the tests are located in our sample application. Now, we'll look at how Maven and Ant integrate and how we'll use DBUnit and DDLUtils to build and populate the database.


First, let’s look at how we’ll make an Ant build perform our data-related tasks, such as updating the schema and loading sample data. Then, we’ll see how Maven is configured to call Ant.

<project default="data-tasks" basedir="." name="Bookie Database Tasks">
    <property name="maven.repo.local"
        value="${user.home}/.m2/repository"/>
    <property file="jdbc.properties.mysql" />
    <property location="src/data" name="src.dir" />
    <property location="${src.dir}/datasets" name="dataset.dir" />
    <path id="maven.repo.classpath">
        <fileset dir="${maven.repo.local}">
            ...lots of includes to jars...
        </fileset>
    </path>
Here’s the beginning of the bookie-data build.xml. First we set up a few properties, such as the location of the Maven local repository. Maven will pass in the user.home variable when it calls Ant. We’ll also load some connection properties for MySQL, tell Ant where the source for the data definition part of the data project exists, and then set up Ant to load a whole lot of libraries. If you look at the actual file, you’ll see references to a lot of JARs here. We need these JARs included in case we want to run any of the Ant tasks in here separate from the Maven build.


Isn’t this defeating the purpose of Maven if we have to tell Ant about the dependencies too? Well, it is a bit of extra configuration, but at least Maven can make it easy for us by automatically generating the code for that part. It’s a little hackish, but it’s better than having separate JARs that Ant needs checked into the source control system and duplicated in the Maven repository. Here’s how to get the code generated for the includes.

First, use Maven’s Ant plug-in to generate a build file.


Note that you may want to copy the existing build.xml somewhere safe, because it will be overwritten. Just type `mvn ant:ant` in the bookie-data project and Maven will generate the equivalent of what it takes to build the project into an Ant build file named build.xml. Then, copy the section that includes all the libraries from the user’s Maven repository and paste it into the build file that does what you need to do. These are the steps I took, and because we only need to use DBUnit in our build file, we can get that part straightened out even before we build out other parts of the project with more dependencies. Figure 5 shows a screenshot of the process.


anatomy6_bash.jpg
Figure 5. Generating a build file


Now that that’s done, there are a few task definitions in the data project’s build.xml:

<taskdef name="ddlToDatabase" classname=
"org.apache.ddlutils.task.DdlToDatabaseTask">

    <classpath>
        <path refid="maven.repo.classpath"/>
    </classpath>
</taskdef>
<taskdef name="databaseToDdl" classname="
org.apache.ddlutils.task.DatabaseToDdlTask">

    <classpath>
        <path refid="maven.repo.classpath"/>
    </classpath>
</taskdef>
<taskdef name="dbunit" classname="org.dbunit.ant.DbUnitTask">
    <classpath>
        <path refid="maven.repo.classpath"/>
    </classpath>
</taskdef>

These task definitions allow us to use DDLUtils and DBUnit in our Ant build.

<target 
    name
="dump-schema"
    description="Dumps the database schema"
    depends="data-tasks">
    <databaseToDdl modelName="bookie">
        <database
        url="${datasource.url}"
         driverClassName="${datasource.driverClassName}"
        username="${datasource.username}"
         password="${datasource.password}" />
        <writeSchemaToFile outputFile="${src.dir}/schema.xml"/>
    databaseToDdl>
</
target>
<target
    name="load-schema"
    description="loads schema from schema.xml"
    depends="data-tasks">
    <ddlToDatabase>
        <database
            url="${datasource.url}"
            driverClassName="${datasource.driverClassName}"
            username="${datasource.username}"
            password="${datasource.password}" />
        <fileset dir="${src.dir}">
            <include name="schema.xml"/>
        </fileset>
        <writeSchemaToDatabase />
    </ddlToDatabase>
</target>

These are the tasks to deal with keeping the database up-to-date. dump-schema writes the tables in the database to a file called schema.xml in the data source directory. This is a helpful task to create the schema in a form that DDLUtils can read. Once this is done, I usually make edits directly to that schema file. This is a database-independent way to keep the data definition up-to-date, and I think it’s easier to read and understand than SQL create statements.

When a developer checks in changes to this schema, other team members can get their local databases in sync with the latest version by running the next task: load-schema. DDLUtils is pretty good at doing non-destructive updates to the database too, but don’t worry too much about development data that’s in local databases. If there are changes to the database, there’s a chance that that data is wrong anyway. If you’d like to keep a set of data around for development that all developers can load easily, look at the next tasks:

<target
    name="export-full-dataset"
    description="creates dbunit dataset file for all tables based on
existing data.">
    <
dbunit
        driver="${datasource.driverClassName}"
        url="${datasource.url}"
        userid="${datasource.username}"
        password="${datasource.password}">
             <
export dest="${src.dir}/full_dataset.xml" />
    </
dbunit>
</target>
<target
    name="clean-database"
    description="clears all data from the database. ARE YOU SURE
YOU WANT TO DO THIS?">
    <
dbunit
        driver="${datasource.driverClassName}"
        url="${datasource.url}"
        userid="${datasource.username}"
        password="${datasource.password}">
            <
operation
                type="DELETE_ALL"
                src="${src.dir}/datasets/empty_dataset.xml" />
    </dbunit>
<
/target>
<plugin>
These tasks use DBUnit to insert data sets defined in XML into the database. We’ll see more of these data sets in the testing section, but they’re basically XML files that describe rows of data which goes in one or more tables. These two tasks are just two examples of what you could do with DBUnit and Ant. The first task exports all the data in the database to a file called full_dataset.xml. If you get your database in a form that you want to share with other developers, execute this task, copy the full dataset.xml file to a new file with a descriptive name, and make an Ant task to load that data.


The next task shows how to load data instead of exporting it. It comes with a little twist, though: I use a file that has rows for each table with no data in them, with a DELETE_ALL-type operation, and all the data is deleted. This is an easy utility task for cleaning out the database. Of course, you could adapt this task easily with a data set that actually has data so that you can share data with all the members of the team. Perhaps you could have a set of data which contains a lot of products and a test customer, making it easy to set up some shopping-cart tests. Maybe you’d like to share a lot of data to be used with performance tests. In any case, this approach is easier to maintain than a lot of SQL statements in a text file.

Better than having each team member have to remember to run `ant load-schema` every time the schema changes, or just every time they check out, is to have Maven run it for them. Here’s the relevant section of the data project’s pom.xml:

<artifactId>maven-antrun-plugin</artifactId>
    <executions>
        <execution">
            <phase<process-resources</phase<
            <id>ant-data-tasks</id>
            <configuration>
                    <tasks>
                    <property name="user.home" value="${user.home}" />
                    <ant antfile="${basedir}/build.xml" inheritRefs="
true">
                    <target name="load-schema"/>
                </ant>
            </tasks>
        </configuration>
        <goals>
            <goal>run</goal>
            </goals>
        </execution>
         </executions>
</plugin>

This configures the Maven Ant run plug-in to run from build.xml a task called load-schema every time during the process-resources phase of the build. It also helps Ant by passing in the value of the user’s home directory, where the local repository is kept.

In the next installment, we'll examine the UI part of the project including building Flex from Maven through Ant and automatically running external tasks from Eclipse. You can always find the entire series here.

1 Comments

Martin said:

Greetings once more..

Id like to note in relation to dbunit that if the deployed application is launched in the browser and a book is eventually reserved, running "mvn package" afterwards will cause TestBrowsing.setup() to fail...

This is due to the fact that there is an entry in the reservations table already, I believe. Dbunit tries to clear the table with CLEAN_INSERT, which seems to fail?! Therefore, I replaced line 36 in lcds.examples.bookie.entity.TestBrowsing:

DatabaseOperation.CLEAN_INSERT.execute(connection, searchableBooksDataset);

with

DatabaseOperation.REFRESH.execute(connection, searchableBooksDataset);

This does not try to clear the reservations table and allows passing the tests.

The other option in my hands was to always delete ALL rows from the reservations table MANUALLY before each project build!!! ugh..

;)

Leave a comment


Type the characters you see in the picture above.

Related Books

Development Series

Get an overview of the tools and technologies that work together to allow developers to build Rich Internet Applications (RIAs) quickly and easily.

Anatomy of an Enterprise Flex RIA

Archives


 
 


Or, visit our complete archive.  

About This Site

Welcome to the premiere community site for all things RIA sponsored by O'Reilly Media and Adobe Systems Incorporated.

About Us
Meet the Experts
Meet Our Contributors
Send Us Feedback