Archive for ◊ August, 2009 ◊

Author:
Wednesday, August 26th, 2009

Introduction

This document, as the title suggests describes the best practices of Apache Maven tool.

About Apache Maven

Maven is a software tool for Java project management and build automation created by Sonatype’s Jason van Zyl in 2002. It is similar in functionality to the Apache Ant tool, but has a simpler build configuration model, based on an XML format. Maven is hosted by the Apache Software Foundation.

Maven uses a construct known as a Project Object Model (POM) to describe the software project being built, its dependencies on other external modules and components, and the build order. It comes with pre-defined targets for performing certain well defined tasks such as compilation of code and its packaging.

A key feature of Maven is that it is network-ready. The core engine can dynamically download plug-ins from a repository, the same repository that provides access to many versions of different Open Source Java projects, from Apache and other organizations and developers. Maven provides built in support not just for retrieving files from this repository, but to upload artifacts at the end of the build.

Maven is built using a plugin-based architecture that allows it to make use of any application controllable through standard input.

It is gaining widespread acceptance as well as adoption in large enterprises and organizations as a successor of Ant. For more details visit – http://en.wikipedia.org/wiki/Apache_Maven

Scope

This document is primarily targeted to developers and technical leads working with Apache Maven on Java EE projects. This document captures the best practices of using Maven for Java EE projects and acts as a guideline for new projects migrating to Maven. The reader of this document is assumed to have a basic knowledge of key Maven features, POM fundamentals and Maven goals. Others please start with the External documentation section which points to various Maven articles, primer articles, faqs on the web.

This document is divided in four parts:

  • Migrating to Maven
  • Maven best practices
  • External Documentation
  • Maven FAQ


Migrating to Maven

The first step would be download an eBook €œBetter Builds with Maven€ and follow the guidelines given in the book. This is one of the most comprehensive books available on Maven. This book is available at this location: www.topazproject.org/trac/attachment/wiki/MavenInfo/BetterBuildsWithMaven.pdf?format=raw

Note: If link is broken in future, googling the book name should help. This book is available free on many sites

Maven Best practices

This section explains how to organize Maven and use in a very effective way

Project Dependencies Management

Maven supports transitive dependencies. But using this feature leads to complexity and unforeseen errors. Managing the project dependencies explicitly is always recommended. This ensures that there will be no room for ambiguity. The side effect of this is that the artifacts list can be come very lengthy.  Below are the guidelines on how to organize this in an effective manner.

  1. Define artifact’s version as property. Example:

<properties>

<commons-collections.version>3.2</commons-collections.version>

<commons-logging.version>1.0.4</commons-logging.version>

<freemarker.version>2.3.8</freemarker.version>

<junit.version>3.8.1</junit.version>

<ognl.version>2.6.9</ognl.version>

<servlet.version>2.3</servlet.version>

<spring.version>2.0</spring.version>

<webwork.version>2.2.4</webwork.version>

<xwork.version>1.2.1</xwork.version>

</properties>

  1. Organize dependencies as list, sorted in alphabetical, ordered and grouped by scope. Example:

<dependencies>

<!– explicit compile dependencies –>

<dependency>

<groupId>freemarker</groupId>

<artifactId>freemarker</artifactId>

<version>${freemarker.version}</version>

</dependency>

<dependency>

<groupId>ognl</groupId>

<artifactId>ognl</artifactId>

<version>${ognl.version}</version>

</dependency>

<!– implicit compile dependencies –>

<dependency><!– webwork dep –>

<groupId>com.opensymphony.oscore</groupId>

<artifactId>oscore</artifactId>

<version>${webwork.version}</version>

</dependency>

<!– explicit test dependencies –>

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>$ {junit.version}</version>

<scope>test</scope>

</dependency>

<dependency>

<!– provided dependencies –>

<dependency>

<groupId>javax.servlet</groupId>

<artifactId>servlet-api</artifactId>

<version>$ {servlet.version}</version>

<scope>provided</scope>

</dependency>

</dependencies>

Managing Profiles

Profiles allow changing build process for different target environments. As a general rule, try to make one profile per environment. Profile name should be self-describing. Example:

env-dev – for build deployed on dev machine

env-uat – for build deployed on test machine (for User Acceptance Tests)

env-prod – for build deployed on prod machine

integration-test – for integration testing purposes

continuous-integration – for continuous integration purposes

Profiles can extend default (top level) properties. Example:

<profiles>

<profile>

<id>env-dev</id>

<properties>

<application.database.url>

<![CDATA[jdbc:oracle:thin:1521:007:ABCD]]>

</application.database.url>

<jdbc.groupId>oracle</jdbc.groupId>

<jdbc.artifactId>ojdbc14</jdbc.artifactId>

<jdbc.version>10.2.0.3.0</jdbc.version>

</properties>

<profile>

</profiles>

<!– default properties (for local developer environment) –>

<properties>

<application.database.url>

<![CDATA[jdbc:mysql://localhost/application]]>

</application.database.url>

<jdbc.groupId>mysql</jdbc.groupId>

<jdbc.artifactId>mysql-connector-java</jdbc.artifactId>

<jdbc.version>5.0.5</jdbc.version>

</properties>

The resources to be filtered are defined by the “resources” build element. Example, all environment specific settings are stored in application.properties file:

<resources>

<resource>

<directory>src/main/resources</directory>

</resource>

<resource>

<directory>src/main/resources</directory>

<filtering>true</filtering>

<includes>

<include>application.properties</include>

</includes>

</resource>

</resources>

<resources>

The desired profile can be activated via the -P argument on the command line:

mvn -P env-dev package

Integrating with Eclipse

Some useful information at this site – http://docs.codehaus.org/display/MAVENUSER/Eclipse+Integration

Execute the following command to set M2_REPO classpath variable:

mvn -Declipse.workspace=<path-to-eclipse-workspace> eclipse:add-maven-repo

Execute the following command to create Eclipse project:

mvn eclipse:eclipse

Additional eclipse plug-in properties can be added the pom.xml as shown below

<plugin>

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

<artifactId>maven-eclipse-plugin</artifactId>

<configuration>

<additionalProjectnatures>

<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>

</additionalProjectnatures>

<additionalBuildcommands>

<buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>

</additionalBuildcommands>

<downloadSources>true</downloadSources>

<downloadJavadocs>true</downloadJavadocs>

<wtpversion>1.5</wtpversion>

</configuration>

</plugin>


Integrating with NetBeans IDE

NetBeans Wiki maintains an updated wiki on everything related to NetBeans & Maven integration.

The wiki is accessible at: http://wiki.netbeans.org/MavenBestPractices

Generating project site

Execute the following command to generate project site:

mvn site

You can customize generated site content by editing src/site/site.xml file.

<project name=”Project Name”>

<skin>

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

<artifactId>maven-default-skin</artifactId>

<version>1.0</version>

</skin>

<body>

${reports}

</body>

</project>

Additional reports to project site can be added. Example:

<reporting>

<plugins>

<plugin>

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

<artifactId>maven-surefire-report-plugin</artifactId>

</plugin>

<plugin>

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

<artifactId>maven-javadoc-plugin</artifactId>

</plugin>

<plugin>

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

<artifactId>maven-jxr-plugin</artifactId>

</plugin>

<plugin>

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

<artifactId>maven-checkstyle-plugin</artifactId>

</plugin>

<plugin>

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

<artifactId>maven-pmd-plugin</artifactId>

</plugin>

<!– Clover coverage

<plugin>

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

<artifactId>maven-clover-plugin</artifactId>

</plugin>

–>

<!– Cubertura coverage –>

<plugin>

<groupId>org.codehaus.mojo</groupId>

<artifactId>cobertura-maven-plugin</artifactId>

</plugin>

</plugins>

</reporting>

Adding additional meta information about project. Example:

<developers>

<developer>

<id>venkat</id>

<name>Venkat Thota</name>

<email>vthota@indiaosl.nl</email>

<timezone>+5:30</timezone>

</developer>

<developer>

<id>prasanna</id>

<name>Prasanna</name>

<email>p.padmanabhan@indiaosl.nl</email>

<timezone>+5:30</timezone>

</developer>

<developer>

<id>prabhu</id>

<name>Prabhu</name>

<email>p.santana@indiaosl.nl</email>

<timezone>+5:30</timezone>

</developer>

</developers>

<issueManagement>

<system>jira</system>

<url>http://jira.intranet.isense.com/jira/browse/projectname</url>

</issueManagement>

<ciManagement>

<system>continuum</system>

<url>http://continuum.isense.com</url>

<notifiers>

<notifier>

<type>mail</type>

<sendOnError>true</sendOnError>

<sendOnFailure>true</sendOnFailure>

<sendOnSuccess>false</sendOnSuccess>

<sendOnWarning>false</sendOnWarning>

</notifier>

</notifiers>

</ciManagement>

Generating project sources and javadocs

Execute the following command to generate jar file with project sources:

mvn source:jar

Execute the following command to generate jar file with project javadocs:

mvn javadoc:jar

Webdeveloping with jetty

Execute the following command to start jetty with application in place. This means any changes made to the ftl/jsp files are visible after page refresh.

mvn jetty:run

Config example:

<plugin>

<groupId>org.mortbay.jetty</groupId>

<artifactId>maven-jetty-plugin</artifactId>

<version>6.1.4</version>

<configuration>

<scanIntervalSeconds>5</scanIntervalSeconds>

<connectors>

<connector implementation=”org.mortbay.jetty.nio.SelectChannelConnector”>

<port>${jetty.port}</port>

</connector>

</connectors>

<webDefaultXml>src/main/webapp/WEB-INF/jetty.xml</webDefaultXml>

</configuration>

<dependencies>

<dependency>

<groupId>org.mortbay.jetty</groupId>

<artifactId>jetty-nologger</artifactId>

<version>1.0</version>

</dependency>

</dependencies>

</plugin>

Jetty buffers static content for webapps such as html files, css files, images etc and uses memory mapped files to do this if the NIO connectors are being used. The problem is that on Windows, memory mapping a file causes the file to be locked, so that the file cannot be updated or replaced. The provided jetty.xml (Jetty default web application descriptor) solves the problem with locked files.

There is also a Maven property ${jetty.port}. It allows developer to change default Jetty port number (in case of conflict with another service).


Integration testing

Execute the following command to execute integration tests:

mvn -P integration-test integration-test

First, you have to install container as runtime environment (For e.g. Tomcat container) for integration testing and configure Cargo maven plugin to use it. Below is an example with Cargo (container management), Selenium (web tests) and DBUnit (import initial data):

<profile>

<id>integration-test</id>

<build>

<plugins>

<plugin>

<groupId>org.codehaus.cargo</groupId>

<artifactId>cargo-maven2-plugin</artifactId>

<configuration>

<wait>${cargo.wait}</wait>

<container>

<containerId>tomcat5x</containerId>

<home>${cargo.container.home}</home>

</container>

<configuration>

<home>${project.build.directory}/${cargo.container}/container</home>

<properties>

<cargo.hostname>${cargo.host}</cargo.hostname>

<cargo.servlet.port>${cargo.port}</cargo.servlet.port>

</properties>

</configuration>

</configuration>

<executions>

<execution>

<id>start-container</id>

<phase>pre-integration-test</phase>

<goals>

<goal>start</goal>

</goals>

</execution>

<execution>

<id>stop-container</id>

<phase>post-integration-test</phase>

<goals>

<goal>stop</goal>

</goals>

</execution>

</executions>

</plugin>

<plugin>

<groupId>org.codehaus.mojo</groupId>

<artifactId>selenium-maven-plugin</artifactId>

<version>1.0-beta-2-SNAPSHOT</version>

<configuration>

<port>${selenium.port}</port>

<background>${selenium.background}</background>

<multiWindow>true</multiWindow>

</configuration>

<executions>

<execution>

<id>start-selenium</id>

<phase>pre-integration-test</phase>

<goals>

<goal>start-server</goal>

</goals>

</execution>

<execution>

<id>stop-selenium</id>

<phase>post-integration-test</phase>

<goals>

<goal>stop-server</goal>

</goals>

</execution>

</executions>

</plugin>

<plugin>

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

<artifactId>maven-surefire-plugin</artifactId>

<version>2.3</version>

<configuration>

<skip>true</skip>

</configuration>

<executions>

<execution>

<id>surefire-it</id>

<phase>integration-test</phase>

<goals>

<goal>test</goal>

</goals>

<configuration>

<skip>false</skip>

<excludes>

<exclude>none</exclude>

</excludes>

<includes>

<include>**/integration/IntegrationTestSuite.java</include>

</includes>

</configuration>

/execution>

</executions>

</plugin>

<plugin>

<groupId>org.codehaus.mojo</groupId>

<artifactId>dbunit-maven-plugin</artifactId>

<version>1.0-beta-1</version>

<configuration>

<skip>true</skip>

</configuration>

</plugin>

</plugins>

</build>

<properties>

<!– properties specific to integration tests environment e.g database

connection parameters –>

</properties>

</profile>

Next, configure surefire plugin to prevent executing integration tests in regular test phase.

<plugin>

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

<artifactId>maven-surefire-plugin</artifactId>

<version>2.3</version>

<configuration>

<excludes>

<exclude>**/integration/*Test.java</exclude>

<exclude>**/integration/*TestSuite.java</exclude>

</excludes>

</configuration>

</plugin>

Continuous Integration

The following command line is recommended as a goal in the builder configuration:

mvn –batch-mode –fail-at-end -P continuous-integration clean package site site:deploy

External documentation

Internet URL

http://maven.apache.org/

Maven FAQ

http://maven.apache.org/general.html

http://docs.codehaus.org/display/MAVENUSER/FAQs-1

Maven Issue Tracking

http://maven.apache.org/issue-tracking.html

Mailing Lists / User Forum

http://maven.apache.org/mail-lists.html

Books

Better Builds with Maven

Maven, The definitive guide

Articles

Keep Your Maven Projects Portable throughout the Build Cycle (http://www.devx.com/Java/Article/32386)

The Maven 2 POM demystified

(http://www.javaworld.com/javaworld/jw-05-2006/jw-0529-maven.html)

http://maven.apache.org/articles.html

Learn by example

AppFuse

http://appfuse.org/display/APF/Development+Environment

http://appfuse.org/display/APF/Maven+2

FAQ

How do I enable debugging on Maven Jetty?

Use mvnDebug command instead of mvn.

mvnDebug jetty:run

How can I get help about maven plugins?

You can search for plugin documentation on the web, or use mvn command.

For getting help about eclipse plugin execute the following command:

mvn help:describe -Dplugin=eclipse €€œDmedium

If you need more information about particular goal, please execute:

mvn help:describe -Dplugin=eclipse -Dmojo=eclipse €€œDfull

Debugging with the Maven Jetty Plugin in Eclipse

Please refer this link for the details – http://docs.codehaus.org/display/JETTY/Debugging+with+the+Maven+Jetty+Plugin+inside+Eclipse

Category: Java  | Leave a Comment
Author:
Tuesday, August 04th, 2009

As the name of my post suggests, I have tried to make a dissection of this event:

€˜What happens when you right click on Silverlight’.

There have been a few workarounds for implementing (any custom action like say context-menu, on) right-click in Silverlight. In this post, I’ve tried to compare 2 methods. So with this understanding, you can choose the best solution for your right-click scenario.

Sample CODE: I have a sample which shows the 2 methods, the SL2 code (Silverlight 2) for which can available:here. (You can also find the SL3 version here).

Especially, I’ll try to address right-click problems/issues, firefox users have reported.

 

Method 1

We can identify the sequence of the various events that happen in the case of each mouse button click €€œ this will be a closer look at the sub events.

Let’s use the HtmlPage.Document.AttachEvent() from SL for wiring up mouse-events. We’ll use these events:

  • HtmlPage.Document.AttachEvent(“oncontextmenu”, this.OnContextMenu);
  • HtmlPage.Document.AttachEvent(“mousedown”, this.MouseDownEvent);
  • HtmlPage.Document.AttachEvent(“mouseup”, this.MouseUpEvent);
  • I shall also include the MouseLeftButtonDown=”Canvas_MouseLeftButtonDown” in the Canvas of the Silverlight page.

And, on each of the 4 events above, I’ll just append a char to a TextBlock, to display, what’s happening:

  • myTextBlock.Text += “D”; // in the MouseDownEvent, and so on
  • Additionally, in the OnContextMenu, I shall also do:
    • e.PreventDefault();//to prevent “Silverlight” context menu
    • e.StopPropagation();

Now, observe what’s happening when you click in different browsers:

(Here I’ll focus mostly on the right-click. You can play around with the sample to see what happens on middle/left clicks).

IE:

Right click and hold the button: you’ll see . And when you release the mouse button, we see the remaining events also occur:

Just to cross check, comment the lines //e.PreventDefault(); and //e.StopPropagation();

Now, you’ll see the default €˜Silverlight’ menu comes back, but after the DUR is printed€¦IE-DUR

 

What this means: in IE, the oncontextmenu event is triggered, and then

 the €˜Silverlight’ menu is popped out. So, in IE you could block the SL-Menu, using PreventDefault() and the StopPropagation().

Firefox:

But in Firefox: things will be the same till you press right-click and hold. Release the click and you’ll see the SL-menu is popped up even before you see the €˜U’ and €˜R’:

Firefox-SL Menu

So it means even though you have the e.PreventDefault(); and e.StopPropagation(); in your oncontextmenu the SL menu comes before that. That’s why the Firefox users have complaints like €˜I have to either press escape’ or €˜have to click outside the browser’. It’s because the default SL context menu, is waiting for the user’s action, it won’t go ahead without user’s input.

 Solution:

All that said. Now to solve, the issue for IE and Firefox, look at another way for implementing the right-click…

Method 2

Another method for implementing right-click: we can register the Silverlight plug-in as scriptable object, and we can access it from JavaScript using:

  • HtmlPage.RegisterScriptableObject(“SilverlightControl”, this);

Maybe you’ll find posts that describe this method, but I’ll just iterate over the key things that you need to get this things running:

  • Since we registered the SL object with the name SilverlightControl we can do this:

Say your Silverlight tag is like this: <asp:Silverlight ID=”SilverlightControl” and so on, then you can do this:

var silverlightControl = document.getElementById(“SilverlightControl”);

silverlightControl.Content.SilverlightControl.ProcessMouseEvent(buttonCode);

 

  • Note that ProcessMouseEvent is a method in the Silverlight object. (And it has to be marked with the attribute [ScriptableMember]).

Here let’s say if I go on appending a line of text:

myTextBlock.Text += “\n” + “Event from ” + buttonCode;

We should see this and so on:

Method2 output

  • Hook up the right-click from JavaScript itself: on the <div> tag which contains the Silverlight control: onmousedown=”ReactOnClickEvent(event);”. So this will ensure your mouse events are first processed in the script environment at the client itself.
  • To prevent the default Silverlight context menu, use this attribute oncontextmenu=”return false;” on the <body> tag.

(But I must admit that this still works only for IE. In Firefox, you will still see the default SL-menu. The only good thing is that, it occurs after the right click is already propagated to the SL control). So you can still have your custom action done. You’ll see that the Silverlight menu comes, but after your code has been executed for the right-click action, something like this:

Firefox - after releasing right click

  • And don’t forget to add the Windowless=”true” in either of the 2 methods.
  • The only extra thing here is that you have to find out the exact event-code for right click for different browsers.
    1. Firefox: (0=L, 1=M, 2=R).
    2. IE: (1=L, 4=M, 2=R)

That’s it. And you’ve got 2 methods to implement the right-click in Silverlight. One last thing you can do before you right-click again, is to do a €˜right-thing’: please leave your comment. :)

Thanks!