<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>BeeWorks</title>
	<atom:link href="http://www.beeworks.be/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.beeworks.be</link>
	<description>Wij bouwen websites, ontwikkelen software op maat en integreren bestaande toepassingen in websites en webapplicaties.</description>
	<lastBuildDate>Mon, 08 Feb 2010 22:03:14 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Kiezerregistratiesoftware met biometrie</title>
		<link>http://www.beeworks.be/cds/</link>
		<comments>http://www.beeworks.be/cds/#comments</comments>
		<pubDate>Mon, 08 Feb 2010 21:00:22 +0000</pubDate>
		<dc:creator>Jurgen</dc:creator>
				<category><![CDATA[Portfolio]]></category>

		<guid isPermaLink="false">http://www.beeworks.be/?p=247</guid>
		<description><![CDATA[Software voor de registratie van kiezers bij nationale verkiezingen, met biometrie (vingerafdrukken en gezichtsherkenning) om fraude tegen te gaan. Deze software wordt binnenkort ingezet bij de kiezerregistratie voor een referendum in Kenia.

BeeWorks werkte in onderaanneming aan dit project. Jurgen tekende de globale architectuur en nam een groot deel van de ontwikkeling voor zijn rekening.]]></description>
			<content:encoded><![CDATA[<p>Software voor de registratie van kiezers bij nationale verkiezingen, met biometrie (vingerafdrukken en gezichtsherkenning) om fraude tegen te gaan. Deze software wordt binnenkort ingezet bij de kiezerregistratie voor een referendum in Kenia.</p>
<p>BeeWorks werkte in onderaanneming aan dit project. Jurgen tekende de globale architectuur en nam een groot deel van de ontwikkeling voor zijn rekening.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.beeworks.be/cds/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>From Maven to Gradle &#8211; part 3</title>
		<link>http://www.beeworks.be/maven-to-gradle-part-3/</link>
		<comments>http://www.beeworks.be/maven-to-gradle-part-3/#comments</comments>
		<pubDate>Thu, 19 Nov 2009 12:48:31 +0000</pubDate>
		<dc:creator>Jurgen</dc:creator>
				<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.beeworks.be/?p=362</guid>
		<description><![CDATA[In the first 2 parts of this series on Gradle, we have migrated a simple project from Maven to Gradle, and written a custom task and plugin for use in our future builds. Today, we are going to deploy the plugin to a repository, and then add the other parts of the MoneyPile project to a multimodule build. At the end of this post, our build will create a war-file and we will be able to run the webapplication from the build file, using an embedded Jetty application server.]]></description>
			<content:encoded><![CDATA[<p>In the <a href="http://www.beeworks.be/maven-to-gradle-part-1/" title="part 1">first</a> <a href="http://www.beeworks.be/maven-to-gradle-part-2/" title="part 2">2</a> parts of this series on Gradle, we have migrated a simple project from Maven to Gradle, and written a custom task and plugin for use in our future builds. Today, we are going to deploy the plugin to a repository, and then add the other parts of the MoneyPile project to a multimodule build. At the end of this post, our build will create a war-file and we will be able to run the webapplication from the build file, using an embedded Jetty application server.</p>
<h4>Deploying the plugin</h4>
<p>The files that are generated by a project, be it a jar, a war or anything else, are called artifacts. The build file for our Hibernate Tools plugin creates a jar-file, which is the default for the Java plugin. Because other projects should be able to use this plugin, we will deploy it to an online repository. Now, Gradle can deploy the jar-file with an ivy.xml descriptor, or with a Maven POM file. For this experiment, we will use the Maven POM.</p>
<p>The project will be hosted on Google Code, so let&#8217;s use the google code subversion repository for uploading artifacts. The protocol we&#8217;ll use is WebDAV, as described here.</p>
<p>First of all, we need to add the plugin &#8216;maven&#8217;.</p>
<pre class="brush: groovy">
usePlugin 'maven'
</pre>
<p>This plugin adds an install task to the build, so running &#8216;gradle install&#8217; puts the jar-file and the generated POM in the local Maven repository. Note that you should specify the group in the build file:</p>
<pre class="brush: groovy">
group = "org.meijiframework.gradle"
</pre>
<p>After verifying that the POM is in fact generated, and the artifact is properly installed in the local Maven repository, we can continue with the WebDAV repository upload. First, we add a dependency on the WebDAV wagon jar:</p>
<pre class="brush: groovy">
dependencies {
    archives "org.apache.maven.wagon:wagon-webdav:1.0-beta-2"
}
</pre>
<p>The archives configuration is the default dependency configuration for the artifact management tasks.<br />
Now we can configure the maven deployer:</p>
<pre class="brush: groovy">
uploadArchives {
    repositories.mavenDeployer {
        name = 'googleCodeDeployer'
        repository(url: "dav:https://bzb-framework.googlecode.com/svn/maven-repository/") {
            authentication(userName: "Your.Name", password: "yourPassword")
        }
    }
}
</pre>
<p>This should be sufficient, and running &#8216;gradle upload&#8217; should upload the snapshot of the Hibernate plugin to the maven repository on Google Code. With gradle 0.8 however, I got an exception. You can read all about it on the Gradle Jira, where I reported the bug (<a href="http://jira.codehaus.org/browse/GRADLE-729" title="bug report on Gradle JIRA" rel="nofollow">http://jira.codehaus.org/browse/GRADLE-729</a>). Apparently there is a jar versioning problem, which can easily be solved by removing the file webdavlib-2.0.jar from $GRADLE_HOME/lib and replacing commons-httpclient-3.0.jar with commons-httpclient-2.0.2.</p>
<p>It&#8217;s not a good idea to put your username and password in the build file, so let&#8217;s try to externalize this. With Maven you would do this with the settings.xml file in the ~/.m2 folder, with gradle the solution is similar, but more concise: create a properties file gradle.properties in the ~/.gradle folder and add the googleCodeUser and googleCodePass properties. Then in the uploadArchives section of your build file, replace the authentication line with this:</p>
<pre class="brush: groovy">
            authentication(userName: googleCodeUser, password: googleCodePass)
</pre>
<h4>Using the Hibernate plugin revisited</h4>
<p>Remember in part 2 of this series, after we created the Hibernate Tools plugin for Gradle, we needed to add 2 dependencies to our model project: one for the plugin itself, with a file dependency and one for Hibernate EntityManager. Now that we have deployed the plugin on a Maven repository, we can simplify this. First we need to add a reference to our Maven repo to the build script, and then we can replace the file dependency with an artifact dependency and remove the Hibernate EntityManager dependency altogether, because now the transitive dependency mechanism is working. So the buildScript section now looks like this (supposing we deployed version 1.0.0 of our plugin):</p>
<pre class="brush: groovy">
buildscript {
    repositories {
        mavenCentral()
        mavenRepo urls: "http://repository.jboss.com/maven2"
       mavenRepo urls: "http://bzb-framework.googlecode.com/svn/maven-repository"
    }
    dependencies {
        classpath group: 'org.meijiframework.gradle', name: 'gradle-hibernate-tools', version: '1.0.0'
     }
}

usePlugin(org.meijiframework.gradle.plugins.HibernateToolsPlugin)
</pre>
<h4>Multimodule build</h4>
<p>First thing we need to do, is pull some build logic that could be useful in the other modules (midtier, ui, &#8230;) to the root build file of the MoneyPile project. This is where Gradle is very different from Maven: whereas Maven (2.x) uses inheritance for sharing common build logic, Gradle uses <em>configuration injection</em>. This is much more flexible. So, let&#8217;s see how we can make the MoneyPile build a multimodule build.</p>
<p>First we need to create a <em>settings.gradle</em> file in the root directory of our project. In this file, we specify which modules our project contains. At this point, there is only one module: model. So our settings.gradle file should currently look like this:</p>
<pre class="brush: groovy">
include "model"
</pre>
<p>Now we can create the root build.gradle file, in the same directory as the settings.gradle file. For multimodule builds, there are 2 very important clauses in Gradle: <em>allprojects</em> and <em>subprojects</em>. The allprojects clause will be executed for all modules, including the root, and the subprojects clause will only be executed for the submodules.</p>
<p>In the <em>allprojects</em> clause of MoneyPile, we can put the version and the Maven repository configuration.</p>
<pre class="brush: groovy">
allprojects {
    version = '1.0.0-SNAPSHOT'

    repositories {
        mavenCentral()
        mavenRepo urls: "http://repository.jboss.com/maven2"
    }
}
</pre>
<p>In the <em>subprojects</em> clause, we put the common stuff for all Java builds:</p>
<pre class="brush: groovy">
subprojects {
    usePlugin 'java'
    usePlugin 'project-reports'
    usePlugin 'eclipse'
    sourceCompatibility = 1.6

    manifest.mainAttributes(
        'Implementation-Title': 'BeeWorks MoneyPile',
        'Implementation-Version': version
    )

    task copyRuntimeDependencies(dependsOn: configurations.runtime.buildArtifacts, type: Copy) {
        into('build/output/lib')
        from configurations.runtime
        from configurations.runtime.allArtifacts*.file
    }
}
</pre>
<p>Now that this is in the root build file, we can clean up the build file of the model module. The only thing we need there is the name of the resulting jar-file, the dependencies and the Hibernate plugin configuration:</p>
<pre class="brush: groovy">
buildscript {
    repositories {
        mavenCentral()
        mavenRepo urls: "http://repository.jboss.com/maven2"
        mavenRepo urls: "http://bzb-framework.googlecode.com/svn/maven-repository"
    }
    dependencies {
        classpath group: 'org.meijiframework.gradle', name: 'gradle-hibernate-tools', version: '1.0.0'
    }
}

usePlugin(org.meijiframework.gradle.plugins.HibernateToolsPlugin)

schemaExport.dialects = 'org.hibernate.dialect.Oracle10gDialect, org.hibernate.dialect.MySQL5Dialect, org.hibernate.dialect.PostgreSQLDialect, org.hibernate.dialect.HSQLDialect'

jar.baseName = 'moneypile-model'

dependencies {
    compile group: 'org.slf4j', name: 'slf4j-log4j12', version: '1.5.2'
    compile group: 'log4j', name: 'log4j', version: '1.2.14'
    compile group: 'commons-logging', name: 'commons-logging', version: '1.1.1'
    compile group: 'org.hibernate', name: 'ejb3-persistence', version: '1.0.2.GA'
    compile group: 'org.hibernate', name: 'hibernate-annotations', version: '3.4.0.GA'
    compile group: 'org.hibernate', name: 'hibernate-commons-annotations', version: '3.3.0.ga'
    compile group: 'javax.validation', name: 'validation-api', version: '1.0.CR5'
    compile group: 'org.hibernate', name: 'hibernate-search', version: '3.1.0.GA'
    testCompile group: 'junit', name: 'junit', version: '4.4'
    testCompile group: 'org.hibernate', name: 'hibernate-validator', version: '4.0.0.CR1'
}
</pre>
<p>And that&#8217;s our multimodule build with 1 module! Now we can create the next module: <em>midtier</em>. This will contain the DAOs and services of the MoneyPile application. This is a very simple module, so all we have to add here are the dependencies and the name of the jar-file. We also want to specify that this module depends on the model module:</p>
<pre class="brush: groovy">
jar.baseName = 'moneypile-midtier'

dependencies {
     compile project(':model')
}
</pre>
<p>The webapp module has some more requirements: we would like to be able to run the webapp using a Jetty plugin. Just like Maven, Gradle has a plugin for this:</p>
<pre class="brush: groovy">
     usePlugin 'war'
     usePlugin 'jetty'
</pre>
<p>Now, we can run our webapp with the command &#8216;gradle jettyRun&#8217;.</p>
<h4>Closing thoughts</h4>
<p>Today, we learned how to deploy a custom gradle plugin to a repository, we touched the subject of multimodule builds, and added the Jetty plugin to our build, so we can run our webapp from the command line.</p>
<p>Note that Gradle offers a number of ways to handle multimodule builds. Coming from Maven, I&#8217;m used to using a build file for every module, but you can just as well put everything in the root build file. You can read all about this in the <a href="http://www.gradle.org/0.8/docs/userguide/multi_project_builds.html" title="multi-project builds in the Gradle manual" rel="nofollow">Gradle manual</a> of course.</p>
<p>I&#8217;m still not 100% sure the configuration injection approach is the best one though. With Maven, I was able to create a company-wide parent pom that was inherited by all projects. That pom contained the locations of the Subversion repository, CI, Jira etc. With Gradle there does not seem to be an easy way to accomplish the same thing easily, unless you write a plugin. On the other hand, Gradle plugins are quite easy to write and much more powerful than their Maven counterparts. Still, composition of build files would be nice.</p>
<p>So, will I ditch Maven in favor of Gradle? For existing Maven projects, no. They work fine for now, and I don&#8217;t like fixing what isn&#8217;t broken. For future projects, I think I might. Unless Maven 3.0 completely blows me away <img src='http://www.beeworks.be/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  Now that I&#8217;m hooked on Groovy and Grails, I might even try to contribute a Gradle plugin for Grails&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.beeworks.be/maven-to-gradle-part-3/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>LaTeX-friendly Strings with Groovy regexp</title>
		<link>http://www.beeworks.be/groovy-latex/</link>
		<comments>http://www.beeworks.be/groovy-latex/#comments</comments>
		<pubDate>Fri, 13 Nov 2009 10:04:35 +0000</pubDate>
		<dc:creator>Jurgen</dc:creator>
				<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.beeworks.be/?p=355</guid>
		<description><![CDATA[I might very well be the only person in the world who wants to generate LaTeX documents from a Java or Groovy application, but just in case there's someone else out there who's trying to do the same, here's a Groovy method that replaces special characters with their LaTeX codes.]]></description>
			<content:encoded><![CDATA[<p>I might very well be the only person in the world who wants to generate LaTeX documents from a Java or Groovy application, but just in case there&#8217;s someone else out there who&#8217;s trying to do the same, here&#8217;s a Groovy method that replaces special characters with their LaTeX codes:</p>
<pre class="brush: groovy">
    def texify(String input) {
        return input.
            //replace all \ with {\textbackslash}
            replaceAll("\\\\" , "{\\\\textbackslash}").
            //put backslash before {, } $, %, _, &#038; and #
            replaceAll('([{}\$%_&#])', '\\\\$1').
            //undo { and } for the {\textbackslash} occurrences
            replaceAll("\\\\\\{\\\\textbackslash\\\\\\}", "{\\\\textbackslash}").
            //replace ~ with \~{}
            replaceAll("~", "\\\\~{}").
            //put math mode around <, > and |
            replaceAll("([<>|])", '\\$$1\\$').
            //replace all ... with \ldots
            replaceAll("(^|[^.])\\.\\.\\.([^.])", '$1\\\\ldots$2').
            //fix double quotes
            replaceAll("(^|\\s)\\\"", '$1``').
            replaceAll("\\\"(\\W|\$)", '\'\'$1').
            //fix single quotes
            replaceAll("(^|\\s)'", '$1`').
            replaceAll("'(\\W|\$)", '\'$1')
    }
</pre>
<p>I based the regular expressions on <a href="http://tug.ctan.org/tex-archive/support/txt2latex/txt2latex" rel="nofollow" title="txt2latex perl script">this Perl script</a> by Tristan Miller, and on the excellent LaTeX manual at the <a href="http://latex.ugent.be" rel="nofollow" title="Ghent University LaTeX user group">Ghent University LaTeX user group</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.beeworks.be/groovy-latex/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Universiteit Gent: Edo Framework</title>
		<link>http://www.beeworks.be/edo-framework/</link>
		<comments>http://www.beeworks.be/edo-framework/#comments</comments>
		<pubDate>Tue, 03 Nov 2009 13:28:52 +0000</pubDate>
		<dc:creator>Jurgen</dc:creator>
				<category><![CDATA[Portfolio]]></category>

		<guid isPermaLink="false">http://www.beeworks.be/?p=341</guid>
		<description><![CDATA[Jurgen stelde dit framework samen in een poging om de ontwikkeling van administratieve toepassingen binnen de UGent zoveel mogelijk te stroomlijnen en om de onderhoudbaarheid van de software te garanderen. Met succes: sinds enkele jaren wordt alle nieuwe software aan de UGent met dit framework ontwikkeld.]]></description>
			<content:encoded><![CDATA[<p>Het doel van het Edo framework is tweeledig. Het legt best practices voor softwareontwikkeling vast en het biedt een technologisch kader waarbinnen de ontwikkelaars van de Directie ICT zo productief mogelijk kunnen werken. Jurgen stelde dit framework samen in een poging om de ontwikkeling van administratieve toepassingen binnen de UGent zoveel mogelijk te stroomlijnen en om de onderhoudbaarheid van de software te garanderen. Met succes: sinds enkele jaren wordt alle nieuwe software aan de UGent met dit framework ontwikkeld. Sinds begin 2009 wordt het framework verder onderhouden in samenwerking met RealDolmen.</p>
<p>Het Edo Framework verwijst naar de Edo-periode (1603-1867) in de geschiedenis van Japan. Gedurende deze periode regeerde het Tokugawa shogunaat, dat in 1603 officieel werd gevestigd door Tokugawa Ieyasu. De naam Edo-periode wordt gebruikt omdat het shogunaat, en dus de macht, in Edo (het huidige Tokyo) gezeteld was. De Edo-periode bracht rust en stabiliteit in Japan, onder andere vanwege de strenge regels die werden opgesteld.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.beeworks.be/edo-framework/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>From Maven to Gradle &#8211; part 2</title>
		<link>http://www.beeworks.be/maven-to-gradle-part-2/</link>
		<comments>http://www.beeworks.be/maven-to-gradle-part-2/#comments</comments>
		<pubDate>Mon, 12 Oct 2009 13:25:01 +0000</pubDate>
		<dc:creator>Jurgen</dc:creator>
				<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.beeworks.be/?p=304</guid>
		<description><![CDATA[In the <a href="http://www.beeworks.be/maven-to-gradle-part-1/" title="From Maven to Gradle - part 1">first part</a> of this series, we discovered Gradle and tried to convert a simple Maven project, the domain model of my BeeWorks MoneyPile application. Be sure to <a href="http://www.beeworks.be/maven-to-gradle-part-1/" title="From Maven to Gradle - part 1">read it</a> if you haven't already. In this second post, we will complete the domain model project by adding a custom plugin that generates DDL files for several databases.
]]></description>
			<content:encoded><![CDATA[<p>In the <a href="http://www.beeworks.be/maven-to-gradle-part-1/" title="From Maven to Gradle - part 1">first part</a> of this series, we discovered Gradle and tried to convert a simple Maven project, the domain model of my BeeWorks MoneyPile application. Be sure to <a href="http://www.beeworks.be/maven-to-gradle-part-1/" title="From Maven to Gradle - part 1">read it</a> if you haven&#8217;t already. In this second post, we will complete the domain model project by adding a custom plugin that generates DDL files for several databases.</p>
<h4>Our goal for today</h4>
<p>For my old/current Java development framework, I have written a Maven plugin that takes the META-INF/persistence.xml of a JPA project, and uses Hibernate SchemaExport to generate 3 ddl-files for every database dialect you specify: drop-create, create and drop. By default, this is done for Oracle, MySQL, PostgreSQL and HSQL, but you can choose any of the dialects Hibernate offers. I know what you&#8217;re thinking: why didn&#8217;t you just use the <a href="http://mojo.codehaus.org/maven-hibernate3/hibernate3-maven-plugin/" title="Maven Hibernate3 plugin" rel="external nofollow">hibernate3 plugin</a> that&#8217;s available on Codehaus? Well, I haven&#8217;t checked lately, but when I created my framework, this plugin didn&#8217;t do what I wanted and it was still in the sandbox. Plus, I liked the challenge.</p>
<p>Now, how will we do this with Gradle? As far as I can tell, there are several options: Since Gradle offers first-class support for Ant build files and Ant tasks, we could use the Ant tasks that come with Hibernate Tools. But again, they don&#8217;t really do what I want: for one, you need to set the dialect in the persistence.xml file, and I don&#8217;t want that. All I want to put in there are the class names of my entities.</p>
<p>I&#8217;ve chosen to dive into the Gradle API and write a Gradle <a href="http://www.gradle.org/0.8/docs/userguide/custom_tasks.html" rel="external nofollow">Task</a> and a <a href="http://www.gradle.org/0.8/docs/userguide/custom_plugins.html" rel="external nofollow">Plugin</a> for this purpose. My knowledge of Groovy is still too limited, so I&#8217;ll write them in Java.</p>
<p>So let&#8217;s create a new project, called &#8216;gradle-hibernate-tools&#8217;. The Gradle build file looks a lot like the one we created yesterday:</p>
<pre class="brush: groovy">
usePlugin 'java'
usePlugin 'project-reports'
usePlugin 'eclipse'

defaultTasks 'clean', 'build'

sourceCompatibility = 1.6
version = '1.0.0-SNAPSHOT'
manifest.mainAttributes(
     'Implementation-Title': 'Hibernate tools plugin for Gradle',
     'Implementation-Version': version
)
jar.baseName = 'gradle-hibernate-tools'

repositories {
     mavenCentral()
     mavenRepo urls: "http://repository.jboss.com/maven2";
}

dependencies {
     compile group: 'org.slf4j', name: 'slf4j-api', version: '1.5.2'
     compile group: 'org.slf4j', name: 'slf4j-log4j12', version: '1.5.2'
     compile group: 'org.hibernate', name: 'ejb3-persistence', version: '1.0.2.GA'
     compile group: 'org.hibernate', name: 'hibernate-annotations', version: '3.4.0.GA'
     compile group: 'org.hibernate', name: 'hibernate', version: '3.2.1.ga'
     compile group: 'org.hibernate', name: 'hibernate-entitymanager', version: '3.4.0.GA'
     compile group: 'org.hibernate', name: 'hibernate-commons-annotations', version: '3.3.0.ga'
     compile group: 'org.hibernate', name: 'hibernate-tools', version: '3.2.4.GA'
     compile group: 'dom4j', name: 'dom4j', version: '1.6.1'
     compile group: 'org.codehaus.groovy', name: 'groovy-all', version: '1.6.4'
     compile files('lib/gradle-core-0.8.jar', 'lib/gradle-open-api-0.8.jar')
}
</pre>
<p>The only difference here is the manifest section, and a number of dependencies, specifically Groovy, Gradle and Hibernate Tools. You&#8217;ll notice that the gradle dependency is a file dependency to a jar-file I put in the project lib directory. The Gradle artifacts are not yet available on any Maven repository. This is something that should be fixed as soon as possible.</p>
<h4>The Task</h4>
<p>The next step is writing the Task that will perform the database schema export. Now, in the Gradle manual, there are chapters on writing <a href="http://www.gradle.org/0.8/docs/userguide/custom_tasks.html" rel="external nofollow">custom tasks</a> and <a href="http://www.gradle.org/0.8/docs/userguide/custom_plugins.html" rel="external nofollow">custom plugins</a>, but they don&#8217;t go into a lot of detail. The best way for now is diving into the Gradle <a href="http://www.gradle.org/source-repository.html" rel="external nofollow">source code</a>, which is exactly what I did. Let&#8217;s take a look at the Task.</p>
<pre class="brush: java">
public class SchemaExportTask extends ConventionTask {
	private Boolean format = Boolean.TRUE;
	private Boolean comments = Boolean.TRUE;
	private String dialects = "org.hibernate.dialect.MySQL5Dialect";
	private String persistenceUnitName = "default";
	private String delimiter = ";";
	private String targetDirectory = "build/ddl";
</pre>
<p>Our Task extends the ConventionTask class. This will allow us to configure the task from the project build file, using the Gradle Convention mechanism.</p>
<p>First we define some properties to control the output of the task. The dialects property for example is a comma separated list of Hibernate dialects we want to create DDL for. All these properties will be configurable in the build file later on.</p>
<pre class="brush: java">
	private FileCollection classpath;

	/**
	 * Returns the classpath for the Hibernate Tools
	 */
	@InputFiles
	public FileCollection getClasspath() {
		return classpath;
	}

	/**
	 * Set the classpath for the web application
	 */
	public void setClasspath(FileCollection classpath) {
		this.classpath = classpath;
	}
</pre>
<p>The classpath property will allow us to specify the classpath that should be used by the task when trying to generate the schema. This is important because we will need the runtime classpath of the project containing the persistent entities. We&#8217;ll see how this property gets configured when we create the plugin later on. Not the @InputFiles annotation on the getter.</p>
<p>Next is the main method of the task.</p>
<pre class="brush: java">
@org.gradle.api.tasks.TaskAction
protected void start() {
	ClassLoader originalClassloader = this.getClass().getClassLoader();
	try {
		List<URL> classpath = setUpClassPath();
		URLClassLoader hibernateToolsClassloader = new URLClassLoader(
			classpath.toArray(new URL[classpath.size()]),
			originalClassloader);
		Thread.currentThread().setContextClassLoader(
			hibernateToolsClassloader);
		exportSchema();
	} catch (MalformedURLException e) {
		logger.error("Error trying to set the Hibernate Tools classpath");
	} finally {
		Thread.currentThread().setContextClassLoader(
			originalClassloader
		);
	}
}
</pre>
<p>This method is annotated with the TaskAction annotation. Note that there are 2 TaskAction classes in the Gradle API, in different packages. Only the one in the tasks package is an annotation. TaskAction indicates that the annotated method will be called when Gradle starts the task. This method creates a new classloader, containing the classpath we specified above and puts that classloader in the current thread. Then it calls the exportSchema method, which will do the actual work. Afterwards, it resets the current thread contextClassLoader to the original one. This reason for all this classloader stuff is because Hibernate uses the contextClassLoader of the current thread when instantiating a JpaConfiguration.</p>
<pre class="brush: java">
private void exportSchema() {
	Ejb3Configuration configuration = new Ejb3Configuration();
	Map properties = new HashMap();
	properties.put("hibernate.format_sql", format);
	properties.put("hibernate.use_sql_comments", comments);
	configuration = configuration
		.configure(persistenceUnitName, properties);

	if (configuration == null) {
		logger.error("Error: Unable to export schema");
		return;
	}

	for (final String dialect : getDialectList()) {
		try {
			export(configuration, dialect);
		} catch (final Exception e) {
			logger.error("Error exporting DDL for dialect " + dialect, e);
		}
	}
}
</pre>
<p>The exportSchema() method creates a new JPA configuration, using the persistenceUnit we configured. It looks for the configuration of this persistenceUnit in the classpath resource META-INF/persistence.xml. If the persistence.xml file can&#8217;t be found, an error is logged and the task ends. If the JPA configuration is created succesfully, an export is performed for every dialect we specified in the task properties.</p>
<p>That completes the hardest part. Now we&#8217;ll write a plugin so we can easily reuse this functionality in all our JPA projects. You can download the <a href="http://code.google.com/p/meiji-framework/source/browse/trunk/gradle/hibernate-tools/src/main/java/org/meijiframework/gradle/tasks/SchemaExportTask.java" rel="external nofollow" title="SchemaExportTask source code on Google Code">full source code of this task</a> here.</p>
<h4>Tasks vs. Plugins</h4>
<p>As you have seen in the previous section, a task delivers some extra functionality to a build, in our case generating DDL. Some readily available tasks in Gradle are the Java compile and jar tasks.</p>
<p>A plugin is used to alter the build script, for example adding tasks, dependency configuration or conventions to the script. In other words, they are used to plug the functionality provided by the task in the build. So tasks and plugins complement each other nicely in Gradle.</p>
<h4>The plugin</h4>
<p>The easiest way to write a Gradle plugin seems to be in Groovy, in the build file itself. I&#8217;ll use java for this too however, for 2 reasons. First, I don&#8217;t know Groovy well enough. Second, I want to reuse my plugin in other projects, and I don&#8217;t know if that&#8217;s possible when writing it in the build file, the manual doesn&#8217;t mention this. When using good old Java, I can create a jar and put it in a repository somewhere.</p>
<p>What does our plugin need to do? It has to add the SchemaExport task to the project build. We would like to be able to configure the task with some properties, so the plugin will have to register a convention for it. And finally, the plugin has to pass the runtime classpath of the project to the task, so the Hibernate configuration can load our persistent classes.</p>
<pre class="brush: java">
public class HibernateToolsPlugin implements Plugin {

	public static final String SCHEMA_EXPORT = "schemaExport";

	@Override
	public void use(Project project, ProjectPluginsContainer container) {
		System.out.println("Using Hibernate Tools Plugin");
		container.usePlugin(JavaPlugin.class, project);

		HibernateToolsConvention hibernateToolsConvention = new HibernateToolsConvention();
		Convention convention = project.getConvention();
		convention.getPlugins().put("hibernateTools", hibernateToolsConvention);

		configureSchemaExport(project, hibernateToolsConvention);
	}
</pre>
<p>A plugin needs to implement the Plugin interface. This interface has only 1 method: use. This method is called when we add the method usePlugin() to a build file.</p>
<p>Our use() method does 3 things:</p>
<ol>
<li>Make sure the build also uses the Java plugin. Not much use for Hibernate without Java.</li>
<li>Add a convention to the build, which will allow us to configure the schemaExport task. We will look at the HibernateToolsConvention class later.</li>
<li>Configure and register the schemaExport task.</li>
</ol>
<pre class="brush: java">
private void configureSchemaExport(final Project project, final HibernateToolsConvention hibernateToolsConvention) {
	project.getTasks().withType(SchemaExportTask.class).whenTaskAdded(new Action<SchemaExportTask>() {
		public void execute(SchemaExportTask schemaExport) {
			schemaExport.getConventionMapping().map("classpath", new ConventionValue() {
				public Object getValue(Convention convention, IConventionAware conventionAwareObject) {
					return getJavaConvention(project).getSourceSets().
						getByName(SourceSet.MAIN_SOURCE_SET_NAME).
						getRuntimeClasspath();
				}
			});
			schemaExport.getConventionMapping().map("format", new ConventionValue() {
				public Object getValue(Convention convention, IConventionAware conventionAwareObject) {
					return hibernateToolsConvention.getFormat();
				}
			});
			schemaExport.getConventionMapping().map("comments", new ConventionValue() {
				public Object getValue(Convention convention, IConventionAware conventionAwareObject) {
					return hibernateToolsConvention.getComments();
				}
			});
			schemaExport.getConventionMapping().map("dialects", new ConventionValue() {
				public Object getValue(Convention convention, IConventionAware conventionAwareObject) {
					return hibernateToolsConvention.getDialects();
				}
			});
			schemaExport.getConventionMapping().map("persistenceUnitName", new ConventionValue() {
				public Object getValue(Convention convention, IConventionAware conventionAwareObject) {
					return hibernateToolsConvention.getPersistenceUnitName();
				}
			});
			schemaExport.getConventionMapping().map("delimiter", new ConventionValue() {
				public Object getValue(Convention convention, IConventionAware conventionAwareObject) {
					return hibernateToolsConvention.getDelimiter();
				}
			});
			schemaExport.getConventionMapping().map("targetDirectory", new ConventionValue() {
				public Object getValue(Convention convention, IConventionAware conventionAwareObject) {
					return hibernateToolsConvention.getTargetDirectory();
				}
			});

		}
	});

	SchemaExportTask schemaExport = project.getTasks().add(SCHEMA_EXPORT, SchemaExportTask.class);
	schemaExport.setDescription("Generates DDL scripts for your database from your JPA persistent classes.");
}
</pre>
<p>What&#8217;s going on here? The first thing we do is registering a listener that fires an action when the SchemaExport task is added to the project. This action injects the runtime classpath of the project in our SchemaExport task. Remember we need this to run the schema export. Notice how convenient Gradle makes it to retrieve that classpath from the project. The rest of this action takes the properties from the schemaExport convention and injects them in the task.</p>
<p>After registering this listener, the task itself is added to the project, as well as a description.</p>
<p>So that was the plugin. The only thing we need to take a look at now is the convention object, but there is really is nothing much to say about it. It&#8217;s just a simple bean with a number of properties.</p>
<p>You can download the source code of <a href="http://code.google.com/p/meiji-framework/source/browse/trunk/gradle/hibernate-tools/src/main/java/org/meijiframework/gradle/plugins/HibernateToolsPlugin.java" title="HibernateToolsPlugin source code on Google Code" rel="external nofollow">the plugin</a> as well as the <a href="http://code.google.com/p/meiji-framework/source/browse/trunk/gradle/hibernate-tools/src/main/java/org/meijiframework/gradle/plugins/HibernateToolsConvention.java" title="HibernateToolsConvention source code on Google Code" rel="external nofollow">convention object</a> here.</p>
<h4>Using the plugin</h4>
<p>In order to use this plugin in our domain model project, we will need to add it as a dependency to our build script. According to the manual, you do this using the buildscript() method, passing in a closure which declares the dependencies.</p>
<pre class="brush: groovy">
buildscript {
        dependencies {
                classpath fileTree(dir: "D:/meiji-framework/gradle/hibernate-tools/build/libs", includes: ['*.jar'])
        }
}
</pre>
<p>This adds the jar-file of the plugin to the build classpath. That&#8217;s not enough however. Since we are using a file dependency at the moment, there are no transitive dependencies. But we also need hibernate. The hibernate dependencies are on the Maven central repository. So we need to add these lines as well. The complete buildscript method now looks like this:</p>
<pre class="brush: groovy">
buildscript {
        repositories {
                mavenCentral()
                mavenRepo urls: "http://repository.jboss.com/maven2"
        }

        dependencies {
                classpath group: 'org.hibernate', name: 'hibernate-entitymanager', version: '3.4.0.GA'
                classpath fileTree(dir: "D:/meiji-framework/gradle/hibernate-tools/build/libs", includes: ['*.jar'])
        }
}
</pre>
<p>Now we can add the plugin itself. This is easy:</p>
<pre class="brush: groovy">
usePlugin(org.meijiframework.gradle.plugins.HibernateToolsPlugin)
</pre>
<p>Configuring the plugin is easy as well. Let&#8217;s say we want DDL files for 4 databases: Oracle, MySQL, PostgreSQL and HSQL:</p>
<pre class="brush: groovy">
schemaExport.dialects = 'org.hibernate.dialect.Oracle10gDialect, org.hibernate.dialect.MySQL5Dialect, org.hibernate.dialect.PostgreSQLDialect, org.hibernate.dialect.HSQLDialect'
</pre>
<p>That&#8217;s it! Now when we start the command &#8216;gradle schemaExport&#8217;, we get 4 directories in build/ddl: hsql, mysql5, oracle10g and postgresql. Each of these contains 3 files: create.sql, drop.sql and drop_create.sql.</p>
<h4>Day 2 conclusion</h4>
<p>This is all very nice, but it&#8217;s not perfect yet. For one, having to specify all transitive dependencies for the plugin is not acceptable. Luckily, that should be easily fixed once I deploy the plugin to a repository, along with a descriptor. That&#8217;s for the next blog post though.</p>
<p>What would be really great, is if you could use the dependency notation with the usePlugin() method, like this:</p>
<pre class="brush: groovy">
usePlugin('org.meijiframework:gradle-hibernate-tools:1.0')
</pre>
<p>I don&#8217;t think this would be very hard to implement, so who knows, maybe it will be added before they reach version 1.0.</p>
<h4>A slight concern</h4>
<p>As I&#8217;m getting more acquainted with Gradle, I do have a slight concern. One of the great things about Maven is the rather strict convention. I mean, if you download a project with a POM, you know for sure that an &#8216;mvn clean install&#8217; will build, test and package the project, and all plugins the developer added to each phase will be executed.</p>
<p>Gradle also has conventions to a certain level, but they are not enforced and I have a feeling that the philosophy is more like Ant. You create your own tasks (or targets, in Ant terms), mark some of them as default, but there is no guarantee that &#8216;gradle build&#8217; will even work or that every plugin in the buildfile is used when you run a task. In short, I&#8217;m afraid that in the end, you will have to investigate the build file of project when you download it, just like you did in the Ant days. With Maven, you don&#8217;t have to worry about it.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.beeworks.be/maven-to-gradle-part-2/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>From Maven to Gradle &#8211; part 1</title>
		<link>http://www.beeworks.be/maven-to-gradle-part-1/</link>
		<comments>http://www.beeworks.be/maven-to-gradle-part-1/#comments</comments>
		<pubDate>Wed, 07 Oct 2009 23:37:00 +0000</pubDate>
		<dc:creator>Jurgen</dc:creator>
				<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.beeworks.be/?p=285</guid>
		<description><![CDATA[Everytime I have to do something with <a href="http://maven.apache.org/" title="Maven home page" target="_blank">Maven</a>, I get frustrated. Especially POM inheritance and dependency management have frequently given me the urge to throw my computer out the window. And then I'm not even talking about the hundreds and hundreds of lines of XML you need to write for even the simplest projects. 

At the 2008 <a href="http://devoxx.com/" title="Devoxx home page" target="_blank">Devoxx </a>conference, I attended a talk about <a href="http://www.gradle.org/" title="Gradle home page" target="_blank">Gradle</a>, which looked promising, so I made up my mind to investigate it in the near future. Due to lots of work and tight deadlines, that near future became a year later, so here we are.]]></description>
			<content:encoded><![CDATA[<p>Everytime I have to do something with <a href="http://maven.apache.org/" title="Maven home page" rel="external nofollow">Maven</a>, I get frustrated. Especially POM inheritance and dependency management have frequently given me the urge to throw my computer out the window. And then I&#8217;m not even talking about the hundreds and hundreds of lines of XML you need to write for even the simplest projects. Unfortunately, for a long time it was the lesser of all evils. I do not want to go back to writing build files in Ant, and besides, once you can get a parent pom up and running, you don&#8217;t have to deal with the Maven intricacies all that much anymore.</p>
<p>At the 2008 <a href="http://devoxx.com/" title="Devoxx home page" rel="external nofollow">Devoxx </a>conference, I attended a talk about <a href="http://www.gradle.org/" title="Gradle home page" rel="external nofollow">Gradle</a>, which looked promising, so I made up my mind to investigate it in the near future. Due to lots of work and tight deadlines, that near future became a year later, so here we are.</p>
<h4>What is Gradle?</h4>
<p>Gradle is a build system, based on <a href="http://groovy.codehaus.org/" title="Groovy home page" rel="external nofollow">Groovy</a>. Its developers promise that it gives you the best of both worlds between Ant and Maven, and then some. You get the build-by-convention, dependency management and multi-project support from Maven, the flexibility of Ant and the power of Groovy. It is now at version 0.8 and has a very nice <a href="http://www.gradle.org/0.8/docs/userguide/userguide.html" title="Gradle user guide" rel="external nofollow">user guide</a>, which is already more than 200 pages long. It took Maven years to get that kind of coverage!</p>
<h4>The experiment</h4>
<p>I am currently working on a completely new version of my <a href="http://code.google.com/p/bzb-framework/" title="BZB Framework home page" rel="external nofollow">Java development framework</a>, so I decided the time was right to try and ditch Maven.</p>
<p>As I&#8217;m building the new framework, I&#8217;m testing it with an example project called BeeWorks MoneyPile, a simple accounting program I use for creating invoices, tracking expenses and handling contacts. BeeWorks MoneyPile is a multi-project erm&#8230; project, consisting of a domain model, a middle tier and a web application. Every one of those projects has specific build system requirements. These requirements are, in broad strokes:</p>
<ul>
<li>dependency management</li>
<li>build profiles (development, production)</li>
<li>custom plugins (hibernate tools, embedded Tomcat or Jetty)</li>
<li>compilation</li>
<li>unit tests</li>
<li>keyword substitution in resource files</li>
<li>release management</li>
<li>javadocs and documentation</li>
<li>packaging</li>
</ul>
<p>The first part of MoneyPile I will try to switch to Gradle while writing the next 2 blog posts is the domain model, together with the MoneyPile parent build of course. This should be fairly straightforward, since all I&#8217;m doing here is compiling, running unit tests, packaging and generating DDL files using Hibernate tools. Oh, and generating Eclipse project files would be nice too. So let&#8217;s get to it.</p>
<h4>Installing Gradle</h4>
<p>Installing Gradle is quite simple, much like Ant or Maven. Just download the distribution from the <a href="http://www.gradle.org/" title="Gradle website" rel="external nofollow">Gradle website</a> and unzip it. Then add an environment variable called GRADLE_HOME pointing to the Gradle installation directory (in my case c:/java/gradle-0.8), and add %GRADLE_HOME%/bin to your PATH environment variable (on Linux this would be $GRADLE_HOME/bin). Then fire up a command prompt, and run &#8216;<em>gradle -v</em>&#8216;. If installed correctly you should get some information about Groovy, Ant and Java versions.</p>
<p><a href="http://www.beeworks.be/wp-content/uploads/2009/10/gradle-command-1.png" rel="nofollow"><img src="http://www.beeworks.be/wp-content/uploads/2009/10/gradle-command-1.png" alt="gradle command prompt 1" title="gradle command prompt 1" width="590" height="175" class="alignnone size-full wp-image-287" /></a></p>
<p>By the way: if you&#8217;re on Mac OS X, you can use <a href="http://www.macports.org/" title="MacPorts home page" title="_blank">MacPorts</a> to install gradle. You still need to set the environment variables though: </p>
<pre class="brush: bash">
export GRADLE_HOME=/opt/local/share/java/gradle
export PATH=$PATH:$GRADLE_HOME/bin
</pre>
<p>After installing on Mac OS X, my first build failed, because of a permissions problem on the ~/.gradle directory. The simplest solution is to just delete ~/.gradle first:</p>
<pre class="brush: bash">
sudo rm -rf ~/.gradle
</pre>
<h4>First things first</h4>
<p>The first thing to do is to create the Gradle build file, in the project folder. The name of this file is <em>build.gradle</em>. The file can remain empty for now.</p>
<h4>Dependencies</h4>
<p>The domain model of MoneyPile consists of a number of POJOs, annotated with JPA, Bean Validation (<a href="http://jcp.org/en/jsr/detail?id=303" title="JSR 303 on the JCP website">JSR 303</a>) and Hibernate Search annotations. In the unit tests, I use the Bean Validation framework for testing valid and invalid instances of model classes.</p>
<p>This means we will need to specify a number of dependencies before considering compilation. These are the compile scope dependencies:</p>
<ul>
<li>ejb3 persistence</li>
<li>hibernate annotations</li>
<li>hibernate commons annotations</li>
<li>validation api</li>
<li>hibernate search</li>
<li>log4j</li>
<li>slf4j</li>
<li>slf4j log4j12</li>
<li>commons logging</li>
</ul>
<p>The test scope needs some more dependencies:</p>
<ul>
<li>junit 4</li>
<li>hibernate validator 4</li>
</ul>
<p>The good thing about Gradle dependency management is that you can use the familiar Maven repositories. Adding the Maven central repository to your build is as simple as this:</p>
<pre class="brush: groovy">
repositories {
  mavenCentral()
}
</pre>
<p>I&#8217;m using some dependencies that are not yet available in the central repository however, so let&#8217;s take a look how we can add the JBoss repository to our build as well. According to the manual, adding this line to the repositories section should do the trick:</p>
<pre class="brush: groovy">
mavenRepo urls: "http://repository.jboss.com/maven2"
</pre>
<p>That was simple. Now let&#8217;s add the dependencies:</p>
<pre class="brush: groovy">
dependencies {
  compile group: 'org.slf4j', name: 'slf4j-log4j12', version: '1.5.2'
  compile group: 'log4j', name: 'log4j', version: '1.2.14'
  compile group: 'commons-logging', name: 'commons-logging', version: '1.1.1'
  compile group: 'org.hibernate', name: 'ejb3-persistence', version: '1.0.2.GA'
  compile group: 'org.hibernate', name: 'hibernate-annotations', version: '3.4.0.GA'
  compile group: 'org.hibernate', name: 'hibernate-commons-annotations', version: '3.3.0.ga'
  compile group: 'javax.validation', name: 'validation-api', version: '1.0.CR5'
  compile group: 'org.hibernate', name: 'hibernate-search', version: '3.1.0.GA'
  testCompile group: 'junit', name: 'junit', version: '4.4'
  testCompile group: 'org.hibernate', name: 'hibernate-validator', version: '4.0.0.CR1'
}
</pre>
<p>Nice and concise isn&#8217;t it? Each line corresponds to a &lt;dependency&gt; tag in a Maven POM. &#8216;compile&#8217; and &#8216;testCompile&#8217; are the dependency scope, &#8216;group&#8217; is the groupId, &#8216;name&#8217; is the artifactId and &#8216;version&#8217; is the version.</p>
<h4>Building</h4>
<p>We should now be able to compile the project. The project source tree follows the Maven convention, so building it takes only one line in the build file:</p>
<pre class="brush: groovy">
usePlugin 'java'
</pre>
<p>Now, when running the command &#8216;gradle build&#8217;, we see that Gradle does about the same as a Maven build: compile sources, process resources, process classes, compile test sources, process test resources, process test classes, run unit tests, package a jar and assemble a project archive.</p>
<p><a href="http://www.beeworks.be/wp-content/uploads/2009/10/gradle-command-2.png" rel="nofollow"><img src="http://www.beeworks.be/wp-content/uploads/2009/10/gradle-command-2.png" alt="gradle command output 2" title="gradle command output 2" width="590" height="219" class="alignnone size-full wp-image-294" /></a></p>
<p>Our build still needs some finetuning however. The jar file that was generated is called model-unspecified.jar because we didn&#8217;t specify a project name or version. Also, we want to be sure we&#8217;re compiling for java 1.6. Finally, we want to specify some default build tasks. To do all this, we add the following to the top of our build file, right below the usePlugin line:</p>
<pre class="brush: groovy">
defaultTasks 'clean', 'build'

sourceCompatibility = 1.6
version = '1.0.0-SNAPSHOT'
jar.baseName = 'moneypile-model'
manifest.mainAttributes(
   'Implementation-Title': 'BeeWorks MoneyPile - Domain Model',
   'Implementation-Version': version
)
</pre>
<p>Thanks to the default tasks, we can now just run the command &#8216;gradle&#8217;, which will perform both the clean and build tasks. The resulting jar-file will be named &#8216;moneypile-model-1.0.0-SNAPSHOT&#8217;.</p>
<h4>Dependencies again</h4>
<p>So far so good. Now let&#8217;s look in a little more detail at what gradle does with the project dependencies. Transitive dependencies are nice, but you often end up downloading jar-files you don&#8217;t really want.</p>
<p>The compile and testCompile classifiers you see on each line of the dependency section above are actually artifact configurations, used to group the dependencies in what Maven calls scopes. You can define scopes yourself, but the java plugin already defines some typical ones: <em>compile</em>, <em>runtime</em>, <em>testCompile</em>, <em>testRuntime</em>, <em>archives</em> and <em>default</em>. Check the <a href="http://www.gradle.org/0.8/docs/userguide/java_plugin.html#sec:java_plugin_and_dependency_management" title="Gradle manual" rel="external nofollow">Gradle manual</a> for details on all of those. The ones we are interested in right now are <em>compile</em>, <em>testCompile</em>, <em>runtime</em> and <em>testRuntime</em>. Note that by default, the compile (and testCompile) configuration does not use transitive dependencies.</p>
<p>When using Maven, one of the most useful plugins is the dependency plugin, which can generate a dependency tree for your project. Luckily, Gradle has this as well:</p>
<pre class="brush: bash">
gradle -q --dependencies
</pre>
<p>This spits out the dependency tree in the console, but on Windows that&#8217;s rather useless, so I prefer to have a report. To get this, add this line to the top of the build file:</p>
<pre class="brush: groovy">
usePlugin 'project-reports'
</pre>
<p>Then, using the command &#8216;gradle dependencyReport&#8217;, you get a file <em>dependencies.txt</em> in the folder build/reports/project, which contains the dependency tree. Looking at the runtime dependencies of the domain model project, you&#8217;ll notice that there is more than one version of hibernate-core in the tree. Gradle determines which version to use in a very simple way: it just takes the newest version. In this case, this is just fine. If you want to fine-tune your dependencies, Gradles offers a lot of options: you can work with excludes, you can turn off transitive dependencies for certain modules, or you can put your dependencies in a Subversion repository. Whichever way you choose, it&#8217;s certain to be more concise than using excludes in a Maven POM.</p>
<p>To really be sure which jar-files gradle will put in your runtime classpath, the <a href="http://docs.codehaus.org/display/GRADLE/Cookbook" title="Gradle Cookbook" rel="external nofollow">Gradle Cookbook</a> offers a nice trick: just copy all artifacts from the runtime configuration in a special build folder using this task:</p>
<pre class="brush: groovy">
task copyRuntimeDependencies(dependsOn: configurations.runtime.buildArtifacts, type: Copy) {
    into('build/output/lib')
    from configurations.runtime
    from configurations.runtime.allArtifacts*.file
}
</pre>
<p>For the MoneyPile domain model project, this results in the following files:</p>
<pre>
antlr-2.7.6.jar
asm-1.5.3.jar
asm-attrs-1.5.3.jar
cglib-2.1_3.jar
commons-collections-3.1.jar
commons-logging-1.1.1.jar
dom4j-1.6.1.jar
ehcache-1.2.3.jar
ejb3-persistence-1.0.2.GA.jar
hibernate-3.2.1.ga.jar
hibernate-annotations-3.4.0.GA.jar
hibernate-commons-annotations-3.3.0.ga.jar
hibernate-core-3.3.1.GA.jar
hibernate-search-3.1.0.GA.jar
jta-1.1.jar
log4j-1.2.14.jar
lucene-core-2.4.0.jar
persistence-api-1.0.jar
slf4j-api-1.5.2.jar
slf4j-log4j12-1.5.2.jar
validation-api-1.0.CR5.jar
xml-apis-1.0.b2.jar</pre>
<p>That looks about right for now. I&#8217;m sure I&#8217;ll need more control over the dependencies further down the line, but for now, let&#8217;s consider the dependency management of MoneyPile as done.</p>
<p>OK, so what&#8217;s next? We have compiling, unit tests and packaging covered. That leaves us with generating Eclipse project files and DDL files using Hibernate Tools.</p>
<h4>Eclipse support</h4>
<p>Generating Eclipse project files is very easy: add the eclipse plugin to the build file:</p>
<pre class="brush: groovy">
usePlugin('eclipse')
</pre>
<p>Then run &#8216;gradle eclipse&#8217;, and you&#8217;re ready to import your project in Eclipse. There is no such support for NetBeans yet, but apparently <a href="http://blogs.jetbrains.com/idea/2009/08/gradle-support/" title="IntelliJ IDEA 9 on JetBrains Blogs" rel="external nofollow">IntelliJ IDEA 9.0 will have native Gradle support</a>.</p>
<h4>Hibernate DDL generation</h4>
<p>I saved the hardest part for last of course. For my Maven builds, I wrote a custom plugin that uses Hibernate Tools to generate DDL files for a number of databases, configurable with a plugin property. As far as I can see, there are several options for doing this with Gradle, but I&#8217;ll explore those in <a href="http://www.beeworks.be/maven-to-gradle-part-2/">the next part of this series</a>.</p>
<p>You can download the <a href='http://www.beeworks.be/wp-content/uploads/2009/10/build.gradle'>build file for this post</a> here. It&#8217;s only 37 lines. Just to give you an idea: The POM file for this project was about 350 lines of XML.</p>
<h4>Day 1 conclusion</h4>
<p>My first experience with Gradle was surprisingly pleasant. The manual is very good, and everything I tried worked as advertised. The biggest advantage Gradle has is obviously its use of Groovy, rather than XML. This makes build files much more concise and easier to read, while being extremely powerful. The architecture its creators built on top of that seems well thought out. I can&#8217;t wait to start with <a href="http://www.beeworks.be/maven-to-gradle-part-2/">the next part of my quest</a>!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.beeworks.be/maven-to-gradle-part-1/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>BeeWorks ontwikkelt software voor geotechniek</title>
		<link>http://www.beeworks.be/geotechniek-aankondiging/</link>
		<comments>http://www.beeworks.be/geotechniek-aankondiging/#comments</comments>
		<pubDate>Sat, 03 Oct 2009 23:07:21 +0000</pubDate>
		<dc:creator>Jurgen</dc:creator>
				<category><![CDATA[Aankondiging]]></category>

		<guid isPermaLink="false">http://www.beeworks.be/?p=271</guid>
		<description><![CDATA[BeeWorks zal de komende maanden samen met <a href="http://www.age-be.net/" target="_blank" title="AGE website">AGE</a> een aantal toepassingen ontwikkelen voor geotechniek.

De wereldvermaarde experts van AGE, prof. dr. ir. William F. Van Impe en dr. ir. Peter O. Van Impe, zorgen voor de theorie en de implementatie van de geotechnische berekeningen. BeeWorks bouwt daar een gebruiksvriendelijke user interface rond en zal instaan voor de verdeling van de software.

In eerste instantie wordt er gedacht aan een viertal applicaties, waarvan een eerste al wordt verwacht in december.]]></description>
			<content:encoded><![CDATA[<p>BeeWorks zal de komende maanden samen met <a href="http://www.age-be.net/" target="_blank" title="AGE website">AGE</a> een aantal toepassingen ontwikkelen voor geotechniek.</p>
<p>De wereldvermaarde experts van AGE, prof. dr. ir. William F. Van Impe en dr. ir. Peter O. Van Impe, zorgen voor de theorie en de implementatie van de geotechnische berekeningen. BeeWorks bouwt daar een gebruiksvriendelijke user interface rond en zal instaan voor de verdeling van de software.</p>
<p>In eerste instantie wordt er gedacht aan een viertal applicaties, waarvan een eerste al wordt verwacht in december.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.beeworks.be/geotechniek-aankondiging/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Nieuwe BeeWorks website</title>
		<link>http://www.beeworks.be/nieuwe-beeworks-website/</link>
		<comments>http://www.beeworks.be/nieuwe-beeworks-website/#comments</comments>
		<pubDate>Mon, 28 Sep 2009 00:13:22 +0000</pubDate>
		<dc:creator>Jurgen</dc:creator>
				<category><![CDATA[Algemeen]]></category>

		<guid isPermaLink="false">http://www.beeworks.be/?p=230</guid>
		<description><![CDATA[Ik heb vandaag de nieuwe website van BeeWorks gepubliceerd. Er wordt nu veel meer nadruk gelegd op mijn portfolio en op de informatie voor potentiële klanten. Ik ben ook overgeschakeld op Nederlands, aangezien ik mij toch vooral op de Belgische markt richt. Later komt er ook een Engelse versie bij.]]></description>
			<content:encoded><![CDATA[<p>Ik heb vandaag de nieuwe website van BeeWorks gepubliceerd. Er wordt nu veel meer nadruk gelegd op mijn portfolio en op de informatie voor potentiële klanten. Ik ben ook overgeschakeld op Nederlands, aangezien ik mij toch vooral op de Belgische markt richt. Later komt er ook een Engelse versie bij.</p>
<p>Voorlopig staan er nog maar 3 projecten in de portfolio. Dit wordt de komende weken uitgebreid.</p>
<p>Wat denk je ervan? Elke feedback is welkom!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.beeworks.be/nieuwe-beeworks-website/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Universiteit Gent: Centraal Auditoriumbeheer</title>
		<link>http://www.beeworks.be/auditoriumbeheer/</link>
		<comments>http://www.beeworks.be/auditoriumbeheer/#comments</comments>
		<pubDate>Thu, 10 Sep 2009 11:48:47 +0000</pubDate>
		<dc:creator>Jurgen</dc:creator>
				<category><![CDATA[Portfolio]]></category>

		<guid isPermaLink="false">http://www.beeworks.be/?p=347</guid>
		<description><![CDATA[Het Centraal Auditoriumbeheer van Universiteit Gent staat in voor de reservatie en verhuur van lokalen en auditoria en voor het opstellen van lesroosters. Het werd oorspronkelijk opgezet door een professor van de faculteit Wetenschappen, met als bedoeling het voor de hele universiteit toe te passen.

Jurgen kreeg de opdracht om de overschakeling op het systeem van de vaste lesblokken te coördineren en om een nieuw softwarepakket voor auditoriumbeheer te ontwikkelen. Het doel was om alle leslokalen en alle lesroosters van de UGent centraal te beheren.]]></description>
			<content:encoded><![CDATA[<p>Het Centraal Auditoriumbeheer van Universiteit Gent staat in voor de reservatie en verhuur van lokalen en auditoria en voor het opstellen van lesroosters. Het werd oorspronkelijk opgezet door een professor van de faculteit Wetenschappen, met als bedoeling het voor de hele universiteit toe te passen. In 2002 drong een vernieuwing van de software zich op om 2 redenen. Ten eerste was de bestaande software niet betrouwbaar en niet gebruiksvriendelijk genoeg, waardoor een aantal faculteiten aan een eigen systeem begonnen waren. De tweede reden was de beslissing van het bestuurscollege om vanaf 2003 het systeem van vaste lesblokken van anderhalf uur in te voeren.</p>
<p>Ik kreeg de opdracht om de overschakeling op het systeem van de vaste lesblokken te coördineren en om een nieuw softwarepakket voor auditoriumbeheer te ontwikkelen. Het doel was om alle leslokalen en alle lesroosters van de UGent weer centraal te beheren.</p>
<h4>Field study</h4>
<p>Ik begon het project met de overschakeling op de vaste lesblokken. Wegens de deadline was het onmogelijk om eerst de nieuwe software te ontwikkelen: ik had nog 3 maanden. Bovendien gaf deze fase mij de kans om een grondige field study te doen en een goed beeld te krijgen hoe de gebruikers de bestaande applicatie gebruikten, en wat er verwacht werd van de nieuwe toepassing.</p>
<h4>Requirements</h4>
<p>Behalve het systeem van de vaste lesblokken waren dit de belangrijkste requirements:</p>
<p><em>geen academische reservaties die eeuwig geldig blijven</em>: lesroosters moesten vanaf nu elk jaar opnieuw aangemaakt worden, om te vermijden dat het systeem vol zat met ongebruikte reservaties.</p>
<p><em>gedetailleerd toegangsbeheer</em>: Universiteit Gent bestaat uit 11 min of meer autonome faculteiten, elk met hun eigen infrastructuur. Sommige auditoria worden gedeeld, andere behoren exclusief tot een of meerdere vakgroepen, en de faculteiten willen over het algemeen de volledige controle houden over wie welk lokaal kan gebruiken. Dit was dus een belangrijke voorwaarde om alle faculteiten weer te overhalen om met het nieuwe systeem te werken.</p>
<p><em>gebruiksvriendelijkheid</em>: Het aanmaken van reservaties moest gemakkelijk zijn, zowel voor lesroosters als voor eenmalige reservaties, met duidelijke feedback over eventuele conflicten. Voor de student was het belangrijk om een handig overzicht te hebben van haar lesroosters, bij voorkeur aangepast aan het persoonlijke curriculum.</p>
<p><em>schaalbaarheid</em>: De universiteit heeft meer dan 30000 studenten en 6000 personeelsleden. Op piekmomenten vragen al die studenten vrijwel tegelijk hun lesrooster op. Performantie was dus heel belangrijk.</p>
<p><em>integratie</em>: De nieuwe toepassing moest kunnen communiceren met onder andere SAP, LDAP, D-ISAM en een aantal Oracle databases.</p>
<h4>Visie</h4>
<p>Tijdens mijn field study ontwikkelde ik de visie dat de centrale administratie van de universiteit eigenlijk een software platform nodig had met een soort van Service Oriented Architecture aan de serverzijde (hoewel ik toen de term <a href="http://nl.wikipedia.org/wiki/Service-oriëntatie" rel="nofollow" title="Service Oriented Architecture">SOA</a> nog niet kende), een rijke gebruikersinterface voor personeel, en een webgebaseerde, gepersonaliseerde interface voor studenten en docenten. Het auditoriumbeheer kon dienen als een perfecte proof of concept hiervoor.</p>
<p>De applicatie was verdeeld in modules, zowel op de server als in de gebruikersinterface. Elke module bestond uit een aantal services, waarop telkens een gedetailleerde toegangscontrole toegepast kon worden. Zo kreeg een medewerker van de centrale administratie bij het opvragen van een lijst van lokalen bijvoorbeeld de volledige lijst, terwijl een medewerker van een faculteit een veel beperktere lijst kon zien.</p>
<p><a href="http://www.beeworks.be/wp-content/uploads/2009/09/cab-client-1.png"><img src="http://www.beeworks.be/wp-content/uploads/2009/09/cab-client-1.png" alt="auditoriumbeheer client" title="auditoriumbeheer client" width="588" height="360" class="alignnone size-full wp-image-144" /></a></p>
<p>De <a href="http://www.cab.ugent.be">web applicatie</a> liet studenten en docenten toe om hun persoonlijke kalender te bekijken en te beheren, met een interface die veel weg had van <a href="http://www.google.com/calendar/" rel="nofollow" title="Google Calendar">Google Calendar</a> (wat toen nog niet bestond).</p>
<p><a href="http://www.beeworks.be/wp-content/uploads/2009/09/cab-web-2.png"><img src="http://www.beeworks.be/wp-content/uploads/2009/09/cab-web-2.png" alt="auditoriumbeheer web applicatie" title="auditoriumbeheer web applicatie" width="588" height="410" class="alignnone size-full wp-image-145" /></a></p>
<p>Deze visie bleek een schot in de roos maar kwam enkele jaren te vroeg: 5 jaar later, in 2008, werd het grootste softwareontwikkelingsproject in de geschiedenis van de UGent, <a href="http://www.oasis.ugent.be/" rel="nofollow" title="OASIS">OASIS</a>, er volledig op gebaseerd.</p>
<h4>Technologie</h4>
<p>De applicatie werd volledig gebouwd op J2EE, met EJBs. De centrale databank is PostgreSQL, maar er worden ook gegevens gelezen uit Oracle (JDBC), LDAP (JNDI) en D-ISAM (RMI-IIOP en session beans). Dit alles draait op een JBoss applicatieserver. De toegangscontrole werd gerealiseerd met JAAS en AOP.</p>
<p>De gebruikersinterface voor personeel werd ontwikkeld met Java Swing, met behulp van een groot aantal eigen componenten en een eigen look and feel. De communicatie tussen client en server gebeurt via RMI-IIOP over SSL. Beveiliging werd ook hier met JAAS gedaan, met een op maat gemaakt authenticatiemechanisme.</p>
<p>De web applicatie voor studenten en docenten werd gebouwd met Struts, JSP en XSL transformaties. Een van de JSP tags die hiervoor ontwikkeld werden vormde de basis voor de <a href="http://www.beeworks.be/myfaces-schedule/" title="Schedule JSF component">Schedule JSF component in Apache MyFaces</a>.</p>
<h4>Resultaat</h4>
<p>De ontwikkeling van deze toepassing duurde ongeveer 6 maanden, net op tijd om er de lesroosters voor het academiejaar 2003-2004 mee op te stellen. Daarna introduceerde ik het nieuwe pakket in elke faculteit, leidde de gebruikers op en stond nog een klein jaar in voor bug fixes en change requests, tot ik een <a href="http://www.beeworks.be/eid-inschrijvingen/">nieuwe uitdaging</a> aangeboden kreeg. Intussen worden alle auditoria en de meeste leslokalen van de 11 faculteiten met deze toepassing beheerd en worden de lesroosters voor alle opleidingen van de UGent ermee aangemaakt.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.beeworks.be/auditoriumbeheer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>TC Sportina</title>
		<link>http://www.beeworks.be/sportina/</link>
		<comments>http://www.beeworks.be/sportina/#comments</comments>
		<pubDate>Tue, 08 Sep 2009 23:55:02 +0000</pubDate>
		<dc:creator>Jurgen</dc:creator>
				<category><![CDATA[Portfolio]]></category>

		<guid isPermaLink="false">http://www.beeworks.be/?p=225</guid>
		<description><![CDATA[Wij bouwden de website van Tennisclub Sportina in Erpe-Mere.

De site bevat onder andere nieuwsberichten, aankondigingen van activiteiten en berichten van sponsors. De verantwoordelijken van de club hebben de volledige controle over de inhoud van de site. Leden van de club kunnen ook zelf bepaalde berichten toevoegen.

Voor de look and feel werd gebruik gemaakt van een bestaande WordPress theme. Die werd aangepast en vertaald naar het Nederlands. Op die manier realiseerden we een professioneel ogende website voor een bijzonder laag budget.
]]></description>
			<content:encoded><![CDATA[<p>Wij bouwden de website van Tennisclub Sportina in Erpe-Mere. De site bevat onder andere nieuwsberichten, aankondigingen van activiteiten en berichten van sponsors. De verantwoordelijken van de club hebben de volledige controle over de inhoud van de site. Leden van de club kunnen ook zelf bepaalde berichten toevoegen.</p>
<p>Voor de look and feel werd gebruik gemaakt van een bestaande WordPress theme. Die werd aangepast en vertaald naar het Nederlands. Op die manier realiseerden we een professioneel ogende website voor een bijzonder laag budget.</p>
<p><a href="http://www.tcsportina.be/" title="Bezoek de website van TC Sportina" target="_blank">bezoek de website</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.beeworks.be/sportina/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
