Friday, September 16, 2011

Inheritance in Maven based web projects

Sometimes you want to define a base web project and reuse all web based stuff in all other web projects. This is not rare in big projects. The first thought coming in mind is inheritance. Is there any inheritance between web projects at all? Yes, in a manner of speaking. In Maven based projects there is a nice "overlay" feature for maven-war-plugin. You can point to the base WAR project in the overlay tag and the base project gets extracted bevor it's stuff will be extended or overwritten by inherited project. An example:
<plugin>
    <artifactId>maven-war-plugin</artifactId>
    ...
    <configuration>
        <overlays>
            <overlay>
                <groupId>ip.client</groupId>
                <artifactId>ip-theme-framework</artifactId>
                <classifier>webapp</classifier>
                <excludes>
                    <exclude>META-INF/**</exclude>
                    <exclude>WEB-INF/web.xml</exclude>
                    <exclude>WEB-INF/lib/**</exclude>
                    <exclude>WEB-INF/classes/**</exclude>
                </excludes>
            </overlay>
        </overlays>
    </configuration>
</plugin>
You have also to add a dependency in your inherited project for the base project, of course. Well, this feature works fine, but there is a problem with transitive dependencies. Dependencies defined in the base project are "invisible" for inherited projects. You can not use transitive dependencies, they aren't going to be inherited. And adding of all dependencies again in inherited projects is error-prone and causes some issues during release management. To solve this problem, we can set packaging of all web projects as jar. That's what we do in my company.
<packaging>jar</packaging>
With packaging jar you have still a WAR archive at the end, but Java sources are packed to one jar file which is placed by Maven below WEB-INF/lib inside of the WAR. WEB-INF/classes stays empty. Dependencies get now accepted. One thing to keep in mind: WAR projects with packaging jar should be specified twice as dependencies. Once without <type> and once with <type>war</type>. An example:
<dependency>
    <groupId>ip.client</groupId>
    <artifactId>ip-theme-framework</artifactId>
</dependency>
<dependency>
    <groupId>ip.client</groupId>
    <artifactId>ip-theme-framework</artifactId>
    <classifier>webapp</classifier>
    <type>war</type>
    <scope>runtime</scope>
</dependency>
The last be not least is the support in IDEs. JAR projects are not recognized as web projects in Eclipse, IntelliJ or somewhere else and you lose all goodies from your preferred IDE. A solution is simple and uses profiles. Define a property ${packaging.war} for a special profile (see my last post).
<profile>
    <id>ide</id>
    <properties>
        <packaging.war>war</packaging.war>
    </properties>
</profile>
write variable packaging.war in the packaging tag of your project
<packaging>${packaging.war}</packaging>
and let Maven run with this profile when creating IDE specific files:
mvn -Pide eclipse:eclipse
mvn -Pide idea:idea
...
Summary: Overlays help to reuse web projects. They also help to customize web projects by having one big core project and many small custom specific projects which only have specific CSS, Images (logos, ect.) and messages in property files. Custom specific Maven projects don't have Java classes - the aim is to overwrite / extend resources of core project and achieve a custom Look-&-Feel.

Wednesday, September 14, 2011

Filter web.xml with Maven

Maven (build manager for Java projects) has a feature called "filtering". As is generally known you can replace with Maven any variables defined with placeholders like ${my.variable}. Such variables can be placed in property files or any other resource files like CSS, JavaScript, (X)HTML. I normally place placeholders in web.xml and replace them by real values while Maven runs with a certain profile. My default Maven profile is e.g. "development". Another profile is "release". To build artefacts with "release" profile I run
mvn -Prelease clean install
Option -P is for profile you want to build software with. How to set up filtering of web.xml exactly? At first we need to create a directory "filter" under "src/main" and place two (or more) property files under "src/main/filter". In order to demonstrate filtering for two profiles I'm going to create development.properties and release.properties. So, our structure looks now as follows:


Let us define the content of development.properties as
jsf.faceletsRefreshPeriod=2
jsf.resourceUpdateCheckPeriod=2
and the content of release.properties as
jsf.faceletsRefreshPeriod=-1
jsf.resourceUpdateCheckPeriod=-1
The next step is to modify web.xml. web.xml gets two placeholders:
...
<context-param>
    <param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name>
    <param-value>${jsf.faceletsRefreshPeriod}</param-value>
</context-param>
<context-param>
    <param-name>com.sun.faces.resourceUpdateCheckPeriod</param-name>
    <param-value>${jsf.resourceUpdateCheckPeriod}</param-value>
</context-param>
...
The last step is to modify pom.xml. Actually we don't need two profiles. Let us only define the "release" profile and assume default case without any profiles as "development".
<profiles>
    <profile>
        <id>release</id>
        <properties>
            <webapp.filter>release</webapp.filter>
        </properties>
    </profile>
</profiles>
Important thing is to define a property "webapp.filter" for "release" profile. For default case we have also to add this line to pom.xml (somewhere at the end):
<properties>
    <webapp.filter>development</webapp.filter>
</properties>
To make it working together with maven-war plugin (in this case) we need to activate filtering feature. That means, before WAR archive gets packed, placeholders in web.xml should be already replaced by real values from property files. This task is simple:
<plugin>
    <artifactId>maven-war-plugin</artifactId>
    <executions>
        <execution>
            <id>war</id>
            <phase>package</phase>
            <goals>
                <goal>war</goal>
            </goals>
            <configuration>
                ...
                <filteringDeploymentDescriptors>true</filteringDeploymentDescriptors>
                <filters>
                    <filter>${basedir}/src/main/filter/${webapp.filter}.properties</filter>
                </filters>
            </configuration>
        </execution>
    </executions>
</plugin>
We leverages here the variable ${webapp.filter} which points to file name depends on currently active profile. That's all. You can now run builds with
// build for development
mvn clean install

// build for release
mvn -Prelease clean install
There is only one issue when using Jetty Maven plugin and let it runs with
mvn jetty:run
Jetty looks as default under source directory and scans src/main/webapp/WEB-INF/web.xml. But located there web.xml has placeholders. How to solve that? A solution is easy. This is a bonus part of this post. We can leverages overrideDescriptor tag and specify a XML file with our own parts of web.xml which overwrite the same parts in src/main/webapp/WEB-INF/web.xml when Jetty running.
<plugin>
    <groupId>org.mortbay.jetty</groupId>
    <artifactId>maven-jetty-plugin</artifactId>
    <configuration>
        <webAppConfig>
            ...
            <overrideDescriptor>src/main/resources/overrideweb.xml</overrideDescriptor>
        </webAppConfig>
    </configuration>
</plugin>
The content of overrideweb.xml is (we normally need settings for default "development" profile when Jetty running)
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <context-param>
        <param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name>
        <param-value>2</param-value>
    </context-param>
    <context-param>
        <param-name>com.sun.faces.resourceUpdateCheckPeriod</param-name>
        <param-value>2</param-value>
    </context-param>
    <context-param>
        <param-name>com.sun.faces.injectionProvider</param-name>
        <param-value>com.sun.faces.vendor.WebContainerInjectionProvider</param-value>
    </context-param>
    <context-param>
        <param-name>com.sun.faces.spi.AnnotationProvider</param-name>
        <param-value>com.sun.faces.config.AnnotationScanner</param-value>
    </context-param>
    
    <listener>
        <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
    </listener>
</web-app>
Happy filtering!

Wednesday, September 7, 2011

Useful Maven commandos

Everybody who uses Maven from console / terminal knows how sometimes difficult to remember all handy commandos using in day job. A small reference list should help.

Skip running tests for a particular project.
mvn clean install -Dmaven.test.skip=true
Continue build if it has been failed at certain point. Maybe you have many sub-projects and build your entire project from top to down. "-rf" parameters allow to continue maven running where you want after any build errors. Assume my current top directory where I let Maven run is D:\SVN and the build was broken at D:\SVN\eIP\CoreServer\DatastoreConnector. Following command let go on with the build and skip this not compilable or not testable sub-project.
mvn clean install -rf eIP\CoreServer\DatastoreConnector
Get source jar files (e.g. for Eclipse projects). Having source files in local repository allow to jump into this directly from your preferred IDE.
mvn eclipse:eclipse -DdownloadSources=true
or run
mvn dependency:sources
to download all source jars for a given project into local repository. The same for JavaDoc (if it's available).
mvn eclipse:eclipse -DdownloadJavadocs=true
Output project's dependency tree. I like that! You can see versions of all used artefacts.
mvn dependency:tree
Output is like this one
[INFO] ip.client:ip-jsftoolkit:jar:3.4.1-SNAPSHOT
[INFO] +- ip.client:ip-filter-security:jar:3.4.0:compile
[INFO] |  +- com.scalaris.commons:scalaris-commons-enterprise:jar:2.3.1-SNAPSHOT:compile
[INFO] |  |  +- com.scalaris.commons:scalaris-commons-lang:jar:2.3.0:compile
[INFO] |  |  +- org.apache.commons:commons-lang3:jar:3.0:compile
[INFO] |  |  \- commons-lang:commons-lang:jar:2.6:compile
[INFO] |  +- ip.client:ip-client-commons:jar:3.4.0:compile
[INFO] |  |  +- ip.services:ip-core-services:jar:3.4.0:compile
[INFO] |  |  |  \- ip.datatransfer:ip-datatransfer-commons:jar:3.4.0:compile
..................................................
[INFO] |  +- commons-httpclient:commons-httpclient:jar:3.0.1:compile
[INFO] |  +- org.apache.commons:commons-jexl:jar:2.0:compile
[INFO] |  \- joda-time:joda-time:jar:1.6.2:compile
[INFO] +- javax.ejb:ejb:jar:3.0:provided
[INFO] +- javax.servlet:servlet-api:jar:2.5:provided
[INFO] \- com.scalaris.commons:scalaris-commons-test:jar:2.2.8-SNAPSHOT:test
[INFO]    +- jmock:jmock:jar:1.2.0:test
[INFO]    +- junit:junit:jar:3.8.2:test
Filter project's dependency tree in order to see only a specified dependency. The syntax for filter patterns is as follows: [groupId]:[artifactId]:[type]:[version]
mvn dependency:tree -Dincludes=com.sun.faces:jsf-impl
Display the effective pom of a project. The effective pom represents the current pom state for a project (incl. maven super pom and active profiles).
mvn help:effective-pom
Generate files needed for an IntelliJ IDEA project setup.
mvn idea:idea
This plugin has no way to determine the name of the JDK you are using. It uses by default the same JDK as output java -version. Using with defined JDK:
mvn idea:idea -DjdkName=1.5
Create a web project from scratch.
mvn archetype:create 
 -DarchetypeGroupId=org.apache.maven.archetypes 
 -DarchetypeArtifactId=maven-archetype-webapp 
 -DarchetypeVersion=1.0 
 -DgroupId=com.maventest 
 -DartifactId=mywebtest 
 -Dversion=1.0-SNAPSHOT
Deploy artefact in global repository (located e.g. in file://///xyz.abc.com/maven/repo-m2).
mvn deploy:deploy-file
 -DgroupId=com.maventest
 -DartifactId=mywebtest
 -Dversion=1.0-SNAPSHOT
 -Dpackaging=war
 -Dfile=mywebapp.jar
 -DrepositoryId=xyz-release 
 -Durl=file://///xyz.abc.com/maven/repo-m2
Check all the dependencies used in your project and display a list of those dependencies with newer versions available.
mvn versions:display-dependency-updates

...
[INFO] The following dependency updates are available:
[INFO]   org.apache.maven:maven-artifact ........................ 2.0 -> 2.0.9
[INFO]   org.apache.maven:maven-plugin-api ...................... 2.0 -> 2.0.9
[INFO]   org.apache.maven:maven-project ....................... 2.0.2 -> 2.0.9
[INFO]   org.codehaus.plexus:plexus-utils ....................... 1.1 -> 1.5.6
Check all the plugins and reports used in your project and display a list of those plugins with newer versions available.
mvn versions:display-plugin-updates

...
[INFO] The following plugin updates are available:
[INFO]   maven-deploy-plugin ...................................... 2.5 -> 2.7
[INFO]   maven-jar-plugin ..................................... 2.3.1 -> 2.3.2
[INFO]   maven-plugin-plugin ...................................... 2.7 -> 2.9
[INFO]   maven-resources-plugin ................................. 2.4.3 -> 2.5
Decompile Java classes in the maven central repository :-). Useful if source code isn't available. The trick is here.

Thursday, August 25, 2011

Combine jQuery Datepicker and Spinner for fast day incrementation / decrementation

Is it possible to add + / - buttons to jQuery UI Datepicker in order to increment / decrement days in a comfortable way? Yes, it's possible. I have done this task - see screenshot.


This is an extended PrimeFaces Calendar with added "dateSpinner" mode. I would like to omit JSF part and only show HTML / CSS / JavaScript part of such combined calendar. All what you need is to wrap the datepicker markup with a span element, add themable up / down arrows and use datepicker utility functions $.datepicker.formatDate(format, date, settings) and $.datepicker.parseDate(format, value, settings).

HTML
Original HTML with a calendar icon (called icon trigger in jQuery Datepicker) looks very simple
 
<input id="datepicker" class="hasDatepicker" type="text">
<img class="ui-datepicker-trigger" src="images/calendar.gif" alt="..." title="...">
 
You have to extend this as follows
<span id="datepickerWrapper" class="ui-ccalendar ui-widget ui-corner-all">
	<input id="datepicker" class="hasDatepicker" type="text">
	<img class="ui-datepicker-trigger" src="images/calendar.gif" alt="..." title="...">
	<a class="ui-ccalendar-button ui-ccalendar-up ui-corner-tr ui-button ui-widget ui-state-default ui-button-text-only">
		<span class="ui-button-text">
			<span class="ui-icon ui-icon-triangle-1-n"></span>
		</span>
	</a>
	<a class="ui-ccalendar-button ui-ccalendar-down ui-corner-br ui-button ui-widget ui-state-default ui-button-text-only">
		<span class="ui-button-text">
			<span class="ui-icon ui-icon-triangle-1-s"></span>
		</span>
	</a>
</span>

CSS
The most CSS classes above are jQuery UI classes. I marked own classes with ui-ccalendar. In the CSS part is very important to shift spinner's arrow buttons to left. I have shifted absolute positioned buttons with CSS statement right: 17px;. We achieve with this displacement that the calendar icon is visible.
.ui-ccalendar {
    display: inline-block;
    overflow: visible;
    padding: 0;
    position: relative;
    vertical-align: middle;
}

.ui-ccalendar-button {
    cursor: default;
    display: block;
    font-size: 0.5em;
    height: 50%;
    margin: 0;
    overflow: hidden;
    padding: 0;
    position: absolute;
    right: 17px;
    text-align: center;
    vertical-align: middle;
    width: 16px;
    z-index: 100;
}

.ui-ccalendar .ui-icon {
    left: 0;
    margin-top: -8px;
    position: absolute;
    top: 50%;
}

.ui-ccalendar-up {
    top: 0;
}

.ui-ccalendar-down {
    bottom: 0;
}

.ui-ccalendar .ui-icon-triangle-1-s {
    background-position: -65px -16px;
}

.ui-ccalendar .ui-icon-triangle-1-n {
    margin-top: -9px;
}

JavaScript
In this part I use the mentioned above utility functions formatDate() / parseDate() and setDate() / getDate() API of Date object to increment / decrement a single day. Month and year boundaries are considered automatically and in- / decremented if necessary. In- / decrementation logic is bound to mousedown event on spinner buttons.
var datepickerInput = $('#datepicker');
datepickerInput.datepicker({dateFormat: 'yy-mm-dd', ... other configuration if needed ...});

$('#datepickerWrapper').children('.ui-ccalendar-button').mouseover(function() {
	$(this).addClass('ui-state-hover');
}).mouseout(function() {
	$(this).removeClass('ui-state-hover');
}).mouseup(function() {
	$(this).removeClass('ui-state-active');
}).mousedown(function() {
	var el = $(this);
	el.addClass('ui-state-active');
	try {
		// get configured date format
		var dateFormat = datepickerInput.datepicker("option", "dateFormat");

		// extract a date from a string value with a specified format
		var date = $.datepicker.parseDate(dateFormat, datepickerInput.val());
		if (el.hasClass('ui-ccalendar-up')) {
			// increment day
			date.setDate(date.getDate() + 1);
		} else {
			// decrement day
			date.setDate(date.getDate() - 1);
		}

		// format a date into a string value with a specified format
		var strDate = $.datepicker.formatDate(dateFormat, date);
		datepickerInput.val(strDate);
	} catch (err) {
		// ignore and nothing to do
	}
});
Important is here "dateFormat" option. Date format normally depends on user locale and should be passed from outside.

P.S. Just now I found a desktop example of such combined calendar too. So, you see, it's an useful and established widget :-).

Monday, August 22, 2011

GWT composite widgets vs. JSF composite components

I have started to learn GWT (Google Web Toolkit). I don't want to compare all features of both frameworks. I would like to pick just one feature. In GWT you can write autonomous and reusable composite widgets and apply them many times on one or several pages. GWT following say that's not really possible in JSF 2 because one composite component is normally linked with a managed bean. If you use the same composite component twice and change value(s) in one composite component, changed value(s) will be propogated through the bean to another component too. Is it really true?

Take an example. Assume, we have to write a composite widget / component consist of a label, an input field and a button which are aligned horizontally. The GWT solution could be looked like this one
public class CompositeExample implements EntryPoint
{
	private static class LabeledInput extends Composite {
		private Label label = new Label();
		private TextBox textBox = new TextBox();
		private Button button = new Button("Jump!", new ClickHandler() {
			public void onClick(ClickEvent event) {
				// do something
			}
		});

		public LabeledInput() {
			HorizontalPanel panel = new HorizontalPanel();
			panel.add(label);
			panel.add(textBox);
			panel.add(button);

			initWidget(panel);
		}
	}

	public void onModuleLoad() {
		LabeledInput labeledInput = new LabeledInput();
		RootPanel.get().add(labeledInput);
	}
}
I defined a class named LabeledInput which extends the class com.google.gwt.user.client.ui.Composite. The new composite widget LabeledInput is well reusable many times on any pages. No problems here. A corresponding JSF solution could be implemented in a file labeledInput.xhtml as follows
<html xmlns="http://www.w3.org/1999/xhtml"
	  xmlns:h="http://java.sun.com/jsf/html"
	  xmlns:cc="http://java.sun.com/jsf/composite">
<cc:interface>
	<cc:attribute name="model" required="true">
		<cc:attribute name="labelValue" required="true"/>
		<cc:attribute name="inputValue" required="true"/>
		<cc:attribute name="jump" required="true" method-signature="void f(javax.faces.event.ActionEvent)"/>
	</cc:attribute>
	<cc:actionSource name="jump"/>
</cc:interface>
<cc:implementation>
	<h:panelGrid columns="3">
		<h:outputLabel for="#{cc.clientId}:input" value="#{cc.attrs.model.labelValue}"/>
		<h:inputText id="input" value="#{cc.attrs.model.inputValue}"/>
		<h:commandButton value="Jump!" actionListener="#{cc.attrs.model.jump}"/>
	</h:panelGrid>
</cc:implementation>
</html>
cc:attribute "model" should point to a managed bean having attributes "labelValue", "inputValue" and method (actionListener) "jump". Using of this custom component is simple
<h:form>
	...
	<custom:labeledInput id="cli1" model="#{someBean}">
	...
</h:form>

<h:form>
	...
	<custom:labeledInput id="cli2" model="#{someBean}">
	...
</h:form>
There is a problem with this JSF solution. If you change the input value (field h:inputText) in the first component and submit the surrounding form, the new value is going to set into the bean "someBean". This bean is also used by the second component. That means, the second component gets the changed value what is not a desired behavior of course. But JSF is powerful enough to solve this problem. There is a possibility to mix JSF components written in Java with declarative code written in XHTML. We can write a class LabeledInput extending UINamingContainer (according to specification) for our composite component. This class encapsulates then all attributes and has the mentioned above actionListener method.
@FacesComponent("mypackage.LabeledInput")
public class LabeledInput extends UINamingContainer
{
	enum PropertyKeys {labelValue, inputValue, jump;}

    public Object getLabelValue() {
		return getStateHelper().eval(PropertyKeys.labelValue);
    }

    public void setLabelValue(Object labelValue) {
		getStateHelper().put(PropertyKeys.labelValue, labelValue);
    }

    public Object getInputValue() {
		return getStateHelper().eval(PropertyKeys.inputValue);
    }

    public void setInputValue(Object inputValue) {
		getStateHelper().put(PropertyKeys.inputValue, inputValue);
    }

	public void jump(ActionEvent e) {
		// do something
	}
}
Component class can be linked now with the XHTML part via "componentType" attribute in cc:interface. Important part to be changed looks then as follows
<cc:interface componentType="mypackage.LabeledInput">
	<cc:attribute name="labelValue"/>
	<cc:attribute name="inputValue"/>
	<cc:actionSource name="jump"/>
</cc:interface>
<cc:implementation>
	<h:panelGrid columns="3">
		<h:outputLabel for="#{cc.clientId}:input" value="#{cc.labelValue}"/>
		<h:inputText id="input" value="#{cc.inputValue}"/>
		<h:commandButton value="Jump!" actionListener="#{cc.jump}"/>
	</h:panelGrid>
</cc:implementation>
Managed bean is not needed to be passed by this way. Now we can speak about an autonomous and reusable composite component and write <custom:labeledInput> on a page as much as we want without any collisions.