Dynamic Reloading of Vaadin Multi-Module Applications With Maven and Eclipse, Pt. II

In the first part of this article, we explored how a Maven project for Vaadin could be configured such that the application will be dynamically redeployed during runtime after changes have been made to the application code in Eclipse.

In this first part we focused on simple single-module Maven projects. It gets a bit more interesting when we’re working on a multi-module project. In that case, we don’t want to have to run mvn package each time we change some code in a sub-module. We’d want an immediate redeployment even if we’re changing the code of some sub-module. The configuration tricks we applied for single-module projects won’t be enough in this case. So, what do we have to do to enable dynamic reloading even for multi-module projects? We’ll find that out in this article.

Let’s first take a look at what makes multi-module projects special compared with single-module projects. A Vaadin multi-module project consists of at least one module with packaging war and one or more sub-modules with jar packaging. The war sub-module contains our Vaadin application including the web.xml, themes, widget sets, and all the Vaadin fun stuff we all know and appreciate. The jar sub-modules provide additional functionality, such as our data access layer, services, and so on. When we build this project with Maven, the build process will create war and jar artifacts for each sub-module, respectively. Since the war sub-module includes the other modules as dependencies (either directly or transitively), the artifacts for these modules end up in the final war’s WEB-INF/lib folder.

That’s where dynamically reloading multi-module Vaadin apps becomes interesting. If the sub-modules which our Vaadin war module depends on are deployed from jar artifacts, there’s no way we can reload them dynamically when we make changes to the module code. We’d have to rebuild the modules each time we change their code and redeploy our application. Let us remedy that.

As an example, we’ll take a multi-module project consisting of two modules. There’s our Vaadin war module, named vaadin-ui and an additional module backend-api providing the API of the backend. What we want to achieve is that we are able to make changes to any of these modules and get an instant reloading of the running web application. When working with Eclipse we want to have the running web application reloaded each time we save the Java files we’re currently working on.

Again, we need to make some adaptions to our pom.xml (in the case of multi-module projects there is more than one pom.xml we have to adjust). In our example, we have a total of three pom.xml files. There’s one for the parent module in the root folder of the project and one for every sub-module.

Let’s go through each of the pom files and see what we have to do there. The first pom.xml is located in the root folder of our project. It defines the packaging type pom. This is our parent pom. In it, we apply the same configuration we’ve already seen in the first part of this article. That is, we define a property target.dir and redefine the output directory using this property (see below for the full pom.xml).

The next pom file we’re looking at is the least spectacular. It’s the pom of the backend-api. Here we don’t have to configure anything special. Especially the output directory for this sub-module has to remain the default target/classes. We must not redirect the compiler output to the WEB-INF/classes folder in the war module since this would not be accepted by Eclipse.

Finally, there is the pom.xml of vaadin-ui which will receive most of our attention. First of all, we need to declare the dependencies to all of our sub-modules. In our example, this is one dependency pointing to backend-api.

<dependencies>
	...
	<dependency>
		<groupId>de.oio.vaadin.mavenmultimodule</groupId>
		<artifactId>backend-api</artifactId>
		<version>${project.version}</version>
	</dependency>
	...
</dependencies>

Maven’s build process will add this dependency as a jar file to vaadin-ui’s WEB-INF/lib folder. This is something we don’t want to have when we’re developing our application. If the Jetty container deploys this dependency as a jar, it will not notice when the sub-module’s code has been changed. So we need to tweak this dependency a bit in our development profile.

<profiles>
	<profile>
		<id>development</id>
		<properties>
			<target.dir>target/${project.build.finalName}/WEB-INF</target.dir>
		</properties>
		<dependencies>
			<dependency>
				<groupId>de.oio.vaadin.mavenmultimodule</groupId>
				<artifactId>backend-api</artifactId>
				<version>${project.version}</version>
				<scope>provided</scope>
			</dependency>
		</dependencies>
	</profile>
</profiles>

We define our profile development including the redirect of the output directory as shown in the first part of this article. Then we redefine the dependency to our sub-module and set the dependency’s scope to provided. This will instruct Maven to use the dependency only for the compilation process but tells it to not put the dependency’s jar file to the WEB-INF/lib folder.

Next we will have to tell Jetty where it can find the class files of the sub-module. This is done in the configuration section of the Maven Jetty plugin.

<plugin>
	<groupId>org.mortbay.jetty</groupId>
	<artifactId>maven-jetty-plugin</artifactId>
	<version>6.1.24</version>
	<configuration>
		<stopPort>9966</stopPort>
		<stopKey>MavenMultiModule</stopKey>
		<scanIntervalSeconds>1</scanIntervalSeconds>
		<webAppConfig>
			<contextPath>/MavenMultiModule</contextPath>
			<baseResource implementation="org.mortbay.resource.ResourceCollection">
				<resourcesAsCSV>src/main/webapp,${project.build.directory}/${project.build.finalName}</resourcesAsCSV>
			</baseResource>
			<extraClasspath>../backend-api/target/classes</extraClasspath>
		</webAppConfig>
		<scanTargets>
			<scanTarget>../backend-api/target/classes</scanTarget>
		</scanTargets>
	</configuration>
</plugin>

You can pass an extra classpath to Jetty which will additionally be used for the deployment. So with

<extraClasspath>../backend-api/target/classes</extraClasspath>

we tell Jetty where it can find the classes of our sub-module.

As we want Jetty to reload our application even when we make changes to our sub-modules, we have to tell Jetty that it should also scan the classes of these sub-modules for changes. This is done with

<scanTargets>
	<scanTarget>../backend-api/target/classes</scanTarget>
</scanTargets>

Jetty will now load our sub-module’s classes directly from its output directory and scan this directory for changes. That’s all we need to do on the configuration side.

Starting the application

Starting this application is done a bit different than in the single-module example. First, we need to compile the whole project. Go to the project’s root and run mvn package. After that you can start up the web application. This has to be done in the war module’s folder. Change into directory vaadin-ui/ and start Jetty with Maven:

$ cd vaadin-ui
$ mvn jetty:run -Pdevelopment

Note that we cannot use jetty:run-exploded here, since in this mode, Jetty will not scan the directories we defined as extra scan targets. In addition to the single-module example, we need to activate the development profile so that the dependency on our sub-module has scope provided.

With the Vaadin web application up and running, we can now make changes to both vaadin-ui and backend-api modules while the Jetty container will reload the application each time we save our changes.

Importing into Eclipse

Importing this project in Eclipse is done exactly the same way as in the single-module example. Import all three pom.xml files as Maven projects into Eclipse using the development profile in the Advanced section of the import dialog. Importing a Maven multi-module project in Eclipse is done the same way as single-module projects. In the import dialog, select the root folder of your project. You will then get one Eclipse project for each pom.xml file available in that directory.

Example Project

You find a working example for this article on GitHub in project DynamicReloadingMultiModuleProjectsWithMavenAndEclipse.

Appendix

For reference, find below the full Maven pom.xml files for the example described in this article.

The parent pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>de.oio.vaadin.mavenmultimodule</groupId>
	<artifactId>MavenMultiModule</artifactId>
	<packaging>pom</packaging>
	<version>1.0</version>
	<name>Vaadin Web Application - Parent</name>

	<!-- Define the two sub-modules of this project. -->
	<modules>
	  <!-- The backend code -->
		<module>backend-api</module>
	  <!-- The Vaadin application -->
		<module>vaadin-ui</module>
	</modules>

	<properties>
		<target.dir>target</target.dir>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<vaadin.version>7.0.0.alpha3</vaadin.version>
		<webapp.project.name>vaadin-ui</webapp.project.name>
	</properties>

	<build>
		<outputDirectory>${basedir}/${target.dir}/classes</outputDirectory>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.5.1</version>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
				</configuration>
			</plugin>
		</plugins>
	</build>

	<profiles>
		<profile>
			<id>development</id>
		</profile>
	</profiles>

	<repositories>
		<repository>
			<id>vaadin-snapshots</id>
			<url>http://oss.sonatype.org/content/repositories/vaadin-snapshots/</url>
			<releases>
				<enabled>false</enabled>
			</releases>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
		</repository>
		<repository>
			<id>vaadin-addons</id>
			<url>http://maven.vaadin.com/vaadin-addons</url>
		</repository>
	</repositories>

</project>

pom.xml for the backend API sub-module

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<artifactId>backend-api</artifactId>
	<name>Vaadin Web Application - Backend API</name>

	<!-- In the backend API sub-module nothing special has to be configured.
		We're only defining the module's parent relationship, but this is not strictly
		necessary. -->

	<parent>
		<groupId>de.oio.vaadin.mavenmultimodule</groupId>
		<artifactId>MavenMultiModule</artifactId>
		<version>1.0</version>
	</parent>

</project>

pom.xml for the Vaadin application sub-module

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<artifactId>vaadin-ui</artifactId>
	<packaging>war</packaging>
	<name>Vaadin Web Application</name>

	<parent>
		<groupId>de.oio.vaadin.mavenmultimodule</groupId>
		<artifactId>MavenMultiModule</artifactId>
		<version>1.0</version>
	</parent>

	<build>
		<plugins>
			<plugin>
				<groupId>org.mortbay.jetty</groupId>
				<artifactId>maven-jetty-plugin</artifactId>
				<version>6.1.24</version>
				<configuration>
					<stopPort>9966</stopPort>
					<stopKey>MavenMultiModule</stopKey>
					<!-- Redeploy every second if changes are detected -->
					<scanIntervalSeconds>1</scanIntervalSeconds>

					<!-- We could also activate manual redeployment where we'd have to hit
						enter in the console where Jetty is running to redeploy. -->
					<!-- <reload>manual</reload> -->
					<webAppConfig>
						<contextPath>/MavenMultiModule</contextPath>
						<baseResource implementation="org.mortbay.resource.ResourceCollection">
						<resourcesAsCSV>
						src/main/webapp,${project.build.directory}/${project.build.finalName}
						</resourcesAsCSV>
						</baseResource>
						<!-- Add the backend API's classes to Jetty's classpath so that the
							server will be able to load the class files. -->
						<extraClasspath>../backend-api/target/classes</extraClasspath>
					</webAppConfig>

					<!-- Add the backend API's classes as an additional scan target so that
						Jetty will realize when these classes have changed. -->
					<scanTargets>
						<scanTarget>../backend-api/target/classes</scanTarget>
					</scanTargets>
				</configuration>
			</plugin>

		</plugins>
	</build>

	<!-- Define the 'development' profile. -->
	<profiles>
		<profile>
			<id>development</id>
			<properties>
				<!-- Redirect the compiler output to the WEB-INF folder for this profile
					where Jetty can scan it for changes. -->
				<target.dir>target/${project.build.finalName}/WEB-INF</target.dir>
			</properties>
			<dependencies>
				<!-- Redefine the dependency on the sub-module with the scope set to
					'provided'. The dependency does not have to be copied to WEB-INF/lib in the
					development profile as we already have added this dependency to Jetty's classpath
					in the Jetty configuration section. -->
				<dependency>
					<groupId>de.oio.vaadin.mavenmultimodule</groupId>
					<artifactId>backend-api</artifactId>
					<version>${project.version}</version>
					<scope>provided</scope>
				</dependency>
			</dependencies>
		</profile>
	</profiles>

	<dependencies>
		<dependency>
			<groupId>com.vaadin</groupId>
			<artifactId>vaadin</artifactId>
			<version>${vaadin.version}</version>
		</dependency>
		<!-- For normal (non-development) builds define the dependency on the sub-module as usual. -->
		<dependency>
			<groupId>de.oio.vaadin.mavenmultimodule</groupId>
			<artifactId>backend-api</artifactId>
			<version>${project.version}</version>
		</dependency>
	</dependencies>

</project>
Short URL for this post: http://wp.me/p4nxik-14A
Roland Krüger

About Roland Krüger

Software Engineer at Orientation in Objects GmbH. Find me on Google+, follow me on Twitter.
This entry was posted in Build, config and deploy, Did you know?, Java Web Frameworks and tagged , , , , , . Bookmark the permalink.

2 Responses to Dynamic Reloading of Vaadin Multi-Module Applications With Maven and Eclipse, Pt. II

  1. Pingback: Dynamic Reloading of Vaadin Applications With Maven and Eclipse, Pt. I | techscouting through the java news

  2. Risto Oikarinen says:

    I had some trouble with this example project, namely jetty:run on vaadin-ui resulted in problems (see http://stackoverflow.com/questions/3636493/multi-module-maven-project-and-jettyrun).

    First running “mvn install” on the parent project fixed this issue.

    Thanks for a good post about a complex issue!

Leave a Reply