I've got a software component that can initialize the database from an SQL script. Such an SQL script (in what follows: The DDL, or data definition language script) is ideally generated by the Hibernate Schema Exporter, aka "hbm2ddl", which in turn is available in Maven by running the Hibernate3 Maven Plugin. But, if just creating the database is not sufficient and you need to run a second SQL script (in what follows: The data script) to populate the DB with some initial entries? Well, I came up with the following solution:
- At build time, have Maven create the DDL script (below target/classes, so that it is available at run time)
- At development time, manually create the data script (in src/main/db)
- At build time, have Maven concatenate these scripts into a third SQL script (in what follows: The concatenated script, also below target/classes, as it must also be available at runtime)
So I came up with another idea: Why not have a small Groovy Script in the Maven POM. And, as is usually the case, someone else already had that idea and there is a Maven Plugin, which already provides just that:
I can embed a Groovy snippet into my Maven POM and have it executed at a suitable point of my build script. Here's the snippet I came up with:
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source><![CDATA[
def concat(s1, s2, t) {
def java.io.File f1 = new java.io.File(s1)
def java.io.File f2 = new java.io.File(s2)
def java.io.File ft = new java.io.File(t)
def long l1 = f1.lastModified()
def long l2 = f2.lastModified()
def long lt = ft.lastModified()
if (l1 == 0) {
throw new IllegalStateException("Source file must exist:" + f1);
} else if (l2 == 0) {
throw new IllegalStateException("Source file must exist:" + f2);
} else if (lt == 0 || l1 > lt || l2 > lt) {
java.io.File pd = ft.getParentFile()
if (pd != null && !pd.isDirectory() && !pd.mkdirs()) {
throw new IOException("Unable to create parent directory: " + pd)
}
println("Creating target file: " + ft)
println("Source1 = " + f1)
println("Source2 = " + f2)
java.io.FileInputStream fi1 = new java.io.FileInputStream(f1)
java.io.FileInputStream fi2 = new java.io.FileInputStream(f2)
ft.append(fi1)
ft.append(fi2)
fi1.close()
fi2.close()
} else {
println("Target file is uptodate: " + ft)
println("Source1 = " + f1)
println("Source2 = " + f2)
}
}
concat("target/classes/com/softwareag/de/s/framework/demo/db/derby/initZero.sql",
"src/main/db/init0.sql",
"target/classes/com/softwareag/de/s/framework/demo/db/hsqldb/init0.sql")
concat("target/classes/com/softwareag/de/s/framework/demo/db/derby/initZero.sql",
"src/main/db/init0.sql",
"target/classes/com/softwareag/de/s/framework/demo/db/hsqldb/init0.sql")
]]></source>
</configuration>
</execution>
</executions>
</plugin>
perhaps in combination with a byte array, for performance reasons, but in Groovy a file has got a method append(InputStream), which does exactly that. And, although I am declaring the variable ft above as an instance of java.io.File, it is nevertheless a Groovy file, with all the added sugar of Groovy! Which is, why embedding Groovy into the POM is much nicer than embedding Java!
In the future. I will most likely never ever write Maven plugins and use Groovy scripts instead.
Second: We are inside a Maven POM, or, to put it different: Inside an XML file. As a consequence, I've got to be careful with characters like '&', or '!'. Which is why I am using the strings ">" and "&" instead. I might as well use a CDATA section, or, even better: An external script (in src/main/groovy) However, I believed to make this postings point better with an internal (albeit somewhat lengthy) snippet. Hope, you agree, so let's be groovy!
1 comment:
Why not just jump to Gradle and skip the XML altogether?
Post a Comment