Tuesday, December 04, 2007

Branding a Wicket application with Maven 2

This is a follow up to my post on how to brand a Wicket application using Ant filtering. This is an update on how to do the same thing with Maven. It's a repeat of that post, but with the Ant section changed to use Maven instead.


The Style feature in Wicket is for skinning your application, which for a corporate site is another way of saying branding. Having set the style property in the session, it is then available to you anywhere in the application where you need to use it. In addition, the property file resolver automatically takes style into account. There is also some support built into ResourceReference to enable resolution of resources other than property files.


First some examples of how to use this solution, then how to implement it.


Simplest Example


Index.java


add(new Label("page.title", getString("page.title")));

Index.html


<span wicket:id="page.title">Page Title Goes Here</span>

Index_companya.properties


page.title=Welcome to Company A!

Index_companyb.properties


page.title=Welcome to Company B!

There are two properties files, distinguished by "_brand", and Wicket automatically resolves them.



An alternative to the above, showing how to do the same thing with one properties file:


This is an alternative to creating separate properties files for each brand. The style property in the session gives you the flexibility to put all the branding strings in one property file. This can be useful if you have complex strings containing lots of variable interpolations, or if you want to minimize the number of properties files that need to be sent to a translator.


Index.properties


page.title=Welcome to ${pageTitleBrand}!
page.title.companya=Company A
page.title.companyb=Company B

Index.java


...
add(new Label("page.title", new StringResourceModel("page.title", this, new Model(this))));
...
public String getPageTitleBrand()
{
return getString("page.title."+this.getSession().getStyle());
}


Example of branding CSS (style sheets)


Index.css


/* Image supplied by branded CSS */
#top-section {
position: relative;
left: 0;
top: 0;
}

Index._companya.css


#top-section {
background-image: url("/app/images/banner_companya.gif");
}

Index._companyb.css


#top-section {
background-image: url("/app/images/banner_companyb.gif");
}

Index.java


/* All CSS styles except for those that are branded */
add(HeaderContributor.forCss(Index.class, "Index.css"));
/* Branded CSS */
add(HeaderContributor.forCss(new ResourceReference(Index.class,
"Index.css", null, this.getSession().getStyle())));

Here we make use of Wicket's support for styles in ResourceReference. Of course, it would be nicer if Wicket's support for the resolution of CSS (and other resource file types) was as automatic as for property files. That is, if you use the constructor ResourceReference(Index.class, "Index.css") it should automatically look for Index_brand.css.



Branding Images


FaviconLink.java


public class FaviconLink extends ExternalLink
{
public FaviconLink()
{
super("favicon", "/app/images/favicon_"+Session.get().getStyle()+".ico");
}
}

Note that in this case we use Session.get().getStyle() because ExternalLink does not have instance access to the session. Fortunately, it's easy enough to get at it.



How it works


A convenient way to initialize the the session with the brand is to set it in web.xml:


web.xml


...
<filter>
<filter-name>myapp</filter-name>
<filter-class>
org.apache.wicket.protocol.http.WicketFilter
</filter-class>
<init-param>
<param-name>applicationClassName</param-name>
<param-value>wicket.quickstart.QuickStartApplication</param-value>
</init-param>
<init-param>
<param-name>brand</param-name>
<param-value>companya</param-value>
</init-param>
</filter>
...

QuickStartSession.java


...
protected QuickStartSession(final WebApplication application)
{
super(application);
// Read brand from web.xml
String brand = ((WebApplication) Application.get()).getWicketFilter()
.getFilterConfig().getInitParameter("brand");
if (brand == null)
{
brand = "companya";
}
this.setStyle(brand);
}
...

Now to use Maven filtering to set the brand. Put your pre-filtered web.xml in src/main/resources (or wherever you like, actually):


web.xml


...
<init-param>
<param-name>brand</param-name>
<param-value>${brand}</param-value>
</init-param>
...

pom.xml


...
<build>
<resources>
<resource>
<!-- Copies web.xml to target/classes and filters ${brand} in the process -->
<filtering>true</filtering>
<directory>src/main/resources</directory>
<includes>
<include>**/web.xml</include>
</includes>
</resource>
</resources>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<!-- Gets the filtered web.xml from target/classes -->
<webXml>target/classes/web.xml</webXml>
</configuration>
</plugin>
</build>
...

This will copy web.xml from src/main/resources to the location target/classes and in the process replace the branding token. Then the war target builds the WAR using the filtered web.xml.

1 comment:

truecube said...

thank you for mentioning about the copying of web.xml from target/classes - the maven docs on filtering resources doesn't mention that