Wednesday, July 15, 2009

Web resources filtering with Maven 2

Here is a simple solution for filtering web resources in your maven-based web application. Assume, that you have some jsp files and you want to add some maven or user-defined property. For example I want to include current build number as a root virtual directory for some javascript included (it's one of the strategies for versioning web resources and useful as a caching strategy).

Here is excerpt from jsp file (src/main/webapp/pages/index.jsp):

<script src="<s:url value="/build-${BUILD_NUMBER}/js/yui/yahoo-dom-event/yahoo-dom-event.js"/>" type="text/javascript"></script>

${BUILD_NUMBER} - is just simple placeholder, you can have any property here. (BUILD_NUMBER - it's a Hudson variable, which is very useful as unique identifier, and QA members could always say to you what was wrong and which version of some script wasn't working)


Assume you have standard maven layout for your web project:



So, I need placeholder ${BUILD_NUMBER} replaced by actual value. This is just simple filtering for web application. I want to see something like:

<script src="<s:url value="/build-1231312/js/yui/yahoo-dom-event/yahoo-dom-event.js"/>" type="text/javascript"></script>

But as you know standard filtering, require us to copy some resource from one directory to another. So standard maven filtering is no longer works here, because I don't want to move my jsp files anywhere just for filtering. I found solution in maven war plugin, but solution was only applied to external web resources. I was thinking, can we apply same technique for local resources as for external resources . And the answer is - yes!
Here is example of maven plugin configuration:

<build>
...
<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-war-plugin</artifactId>

<version>2.0.2</version>

<configuration>

<webResources>

<resource>

<directory>src/main/webapp/pages</directory>

<includes>

<include>**/*.jsp</include>

</includes>

<filtering>true</filtering>

<targetPath>pages</targetPath>

</resource>

</webResources>

</configuration>

</plugin>

...
</build>

So, there is nothing tricky with this configuration: directory is what we want to filter and targetPath just dir, related to build directory. Source and destination directories should have the same structure. If you'll mistype directory name, you would see duplicates of your filtered files, which is not what we wanted.

Conclusion: you could use any file types - css, js, jsp or something else, not binaries of course :) . Web resources filtering helps you when you need some externally configured strings at build time, not at runtime. Such filtering decouples your application from particular environment.

4 comments:

tvik said...

I guess if official Maven docs would be as clear and comprehensible as this post, many developers would like Maven much more.
Thanks for the post, it was useful.

Scott said...

Is exactly what i need - BUT - do you have any idea why this approach would not pull in environment properties, such as: ${project.version}? Or must you supply config properties?

When i use this approach for external resources, the filtering works fine, but when placed in (webResources), the file is copied, but NOT filtered, using (ANY help appreciated!) - mm, no tags in comments!...

Scott said...

Ah, discovered there was bug with maven-war-plugin v2.0 (re: filtering webResources). Updating to v.2.0.2 solved my problems!

Anonymous said...

Awesome! Although this is an old entry, it helped me a lot! Cheers to the gurus :)