Using Maven overlays to build customized applications
Posted by Paolo Predonzani
on April 9, 2009
Introduction
In this tutorial we'll see two things.
First we'll do a very simple customization of Portofino: changing the logo and css stylesheet.
Second we'll use Maven to create a new mywebapp.war which bundles, in a single .war, the standard Portofino distribution, the customizations and the portofino-custom.properties configuration.
In this way, the mywebapp.war that contains the customized application will be self-contained, professional and easy to deploy.
Contents
- 1 Introduction
- 2 The problem
- 3 Maven overlays
- 4 Installing Maven
- 5 Installing Portofino in the local repository
- 6 Creating the maven overlay project
- 7 Cleaning up some files we don't need
- 8 Adding the portofino-custom.properties
- 9 Adding a custom logo
- 10 Adding a custom stylesheet
- 11 Building the .war file
- 12 Where to go next
The problem
If I had to create and distribute an application based on Portofino I would:
- Download the standard Portofino distribution
- Unpack the war file
- Add a portofino-custom.properties configuration file
- Customize or add any other resources, e.g., css files, images, jars or class files
- Repackage the war file as mywebapp.war
- Distribute to my clients (who will deploy myapp.war to their app servers)
In a simplistic approach, I would do these steps manually. However this brings the following problems:
- If many files need to be changed/added, the technique becomes error prone.
- If a new version of Portofino comes out, I have to repeat all the steps manually again.
- I have to document the customizations that I've applied, or I'm going to forget them.
- If I distribute the source code rather than the .war package, I have to teach my users how to repeat the process.
For a one-off exercise this might be fine, but if I want to develop and maintain a serious application based on Portofino I would need a better process.
Maven overlays
All the manual steps mentioned above can be automated using Maven overlays. The process becomes repeatable, less error-prone, and overall simpler.
Maven is a build/dependency/project management tool. For an overview, see the Maven in 5 minutes guide.
Overlays are a specific, advanced use of Maven. Fundamentally they allow you to build a target war (mywebapp.war) as a "merge" between an original war (the Portofino standard distribution) and other code/files that you develop. To visualize how this "merge" works, see Manipulating WAR Overlays.
Installing Maven
From a shell/command line, check if Maven is already installed on your system:
$ mvn -version Maven version: 2.0.10
Any version of Maven since 2.0.6 is suitable for our purposes.
To download and install Maven, follow the instructions here: http://maven.apache.org/download.html.
Installing Portofino in the local repository
This is a preliminary step that you need to do once on your system. Repeat it only when a new version of Portofino becomes available.
Download Portofino. Expand the archive and check that the file "portofino-war-3.1.0.war" is present. Then type the following command:
mvn install:install-file -DgroupId=com.manydesigns \ -DartifactId=portofino-war -Dversion=3.1.0 -Dpackaging=war \ -Dfile=/path/to/portofino-war-3.1.0.war
Notice that you must change "/path/to/portofino-war-3.1.0.war
" to the location where you've actually downloaded Portofino.
Creating the maven overlay project
To kick-start the new maven project we'll use an archetype, a kind of template for various types of project. We choose the "maven-archetype-webapp", which is an archetype suitable for any war-based applications.
Before you start, you need to decide the groupId and artifactId for the customized application, roughly equivalent to an identifier of your organization and an identified of your webapp. We'll use:
- groupId: com.mycompany.app
- artifactId: mywebapp
Now we can run:
mvn archetype:create -DgroupId=com.mycompany.app -DartifactId=mywebapp \ -DarchetypeArtifactId=maven-archetype-webapp
Maven will run and log several messages. Make sure the last few lines look like this:
[INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------ [INFO] Total time: 4 seconds [INFO] Finished at: Mon Apr 06 14:56:39 CEST 2009 [INFO] Final Memory: 8M/14M
A new directory called "my-webapp" has been created. Let's have a look at it.
$ cd mywebapp $ find . . ./pom.xml ./src ./src/main ./src/main/resources ./src/main/webapp ./src/main/webapp/index.jsp ./src/main/webapp/WEB-INF ./src/main/webapp/WEB-INF/web.xml
As you can see, a standard directory structure has been created (for more information on this, see the Introduction to the standard directory layout).
Now edit the pom.xml file and add the section in bold:
<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>com.mycompany.app</groupId> <artifactId>mywebapp</artifactId> <packaging>war</packaging> <version>1.0-SNAPSHOT</version> <name>mywebapp Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>com.manydesigns</groupId> <artifactId>portofino-war</artifactId> <version>3.1.0</version> <type>war</type> <scope>compile</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> <build> <finalName>mywebapp</finalName> </build> </project>
Now we're ready to run our first build. Type:
mvn package
And make sure you get the BUILD SUCCESSFUL message.
Have a look at a folder called "target", which has just been created. It should contain a file called "mywebapp.war" as well as an expanded version of it in the "mywebapp" directory.
Well, that is the overlaid war target. It still doesn't do what we want, but we're getting closer.
Cleaning up some files we don't need
Before proceeding, make sure you delete two files that were automatically created by the archetype:
-
src/main/webapp/index.jsp
-
src/main/webapp/WEB-INF/web.xml
Unless you really want to customize Portofino's index.jsp and web.xml files, those two files must not be left around.
Adding the portofino-custom.properties
The portofino-custom.properties can be easily bundled inside mywebapp.war. Create the file:
src/main/resources/portofino-custom.properties
And copy the following content:
database.jdbc.driverClass=oracle.jdbc.driver.OracleDriver database.jdbc.connectionURL=jdbc:oracle:thin:@127.0.0.1:1521:XE database.jdbc.username=myusername database.jdbc.password=mypassword model.application.name=MyWebApp model.stylesheet=/mywebapp.css
Of course customize the database connection details. If you do not want to hardwire this information in the configuration file, you may use the following content instead:
database.configurationType=jndi database.jndi.name=jdbc/portofinodb model.application.name=MyWebApp model.stylesheet=/mywebapp.css
...which refers to a JNDI data source called jdbc/portofinodb
that you'll have to set up on the deployment server.
Adding a custom logo
Create or choose a logo image and save it as
src/main/webapp/mylogo.png
Adding a custom stylesheet
Our custom stylesheet will be just sufficient to display the custom logo. Create this file:
src/main/webapp/mywebapp.css
And copy the following content:
@import url("default.css"); div#logo a { display: block; position: absolute; top: 14px; /* distance from top margin */ left: 20px; /* distance from left margin */ text-decoration: none; color: black; font-weight: bold; font-size: 2em; background: url('mylogo.png') no-repeat 0px 0px; padding-top: 60px; /* the logo's height */ height: 0px; width: 200px; /* the logo's width */ overflow: hidden; }
Notice the structure. The @import
statement at the first line ensures that the standard Portofino css is still used, while the lines that follow override only the part that takes case of the title/logo display.
The size and position of the logo on the screen will depend on the values shown in bold. Make sure you customize them to your needs.
Building the .war file
Let's check we have all the files in place.
$ find . . ./pom.xml ./src ./src/main ./src/main/resources ./src/main/resources/portofino-custom.properties ./src/main/webapp ./src/main/webapp/mylogo.png ./src/main/webapp/mywebapp.css ./src/main/webapp/WEB-INF
Now run:
mvn package
Maven will run for a few seconds. At the end you should have a file in:
target/mywebapp.war
That's the final .war, containing all the customizations/configurations, that you can deploy or distribute.
Where to go next
No discussion of war overlays is complete without talking about profiles and filtering: this is the subject of the Using Maven profiles and resource filtering tutorial.
Maven can be employed in many useful situations. For a real life application see our tutorial Integrating Portofino with Alfresco.
The technique we've seen lays the basis for more serious customizations where you can extend the functionality of Portofino. This will be the subject of other tutorials. For now you can have a preview from the reference manual: