Showing posts with label Maven. Show all posts
Showing posts with label Maven. Show all posts

Sunday, 24 March 2013

Java TestNG Example

This post illustrates some of the feature of TestNG. The code example is available at GitHub in the Java-TestNG directory. We use maven. Therefore, the configuration will located in the pom.xml.

Source Code

We use a very simple class returning integers for testing purposes:
public class Generate {

    private Generate() { }

    public static int aOne() {
        return 1;
    }

    public static int aTwo() {
        return 2;
    }

    ...

}

Test Code

The test code for the above class is the following:
public class GenerateNGTest {

    public GenerateNGTest() { }

    @Test(groups = {"testGroupA"})
    public void testAOne() {
        assertEquals(1,Generate.aOne());
    }

    @Test(groups = {"testGroupA", "testGroupB", "windows.QTests"})
    public void testATwo() {
        assertEquals(2,Generate.aTwo());
    }

    @Test(groups = {"testGroupA", "testGroupC", "windows.PTests"})
    public void testAThree() {
        assertEquals(3,Generate.aThree());
    }

    @Parameters({ "testNgParam" })
    @Test(groups = {"testGroupA"})
    public void testAFour(@Optional("4") String testNgParam) {
        assertEquals(Integer.parseInt(testNgParam),Generate.aFour());
    }

    @Parameters({ "testNgParam2" })
    @Test(groups = {"testGroupA"})
    public void testASix(String testNgParam2) {
        assertEquals(Integer.parseInt(testNgParam2),Generate.aSix());
    }

    public class DataForTests {

        @DataProvider(name = "forTestAFive")
        public Object[][] forTestAFive() {
            return new Object[][] {
                { new Integer(5) },
                { new Integer(6) }
            };
        }

    }

    @Test(dataProvider = "forTestAFive", dataProviderClass = DataForTests.class)
    public void testAFive(int param) {
        assertEquals(param,Generate.aFive());
    }

    @Test(dependsOnGroups = { "windows.*" })
    public void testASeven() {
        assertEquals(7,Generate.aSeven());
    }

}
  • Some test groups are defined for test methods. These can be activated in the configuration described further.
  • The testAFour() method takes in a parameter and defaults to 4 if none is provided.
  • Rather than setting parameters in the configuration, one can define a DataForTests class and use it to pass parameters as in the testAFive() method.
In this example, we do not cover factories and automatic test generation, programmatic executions of tests and test methods interceptors.    

Configuration

In the pom.xml:
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.14</version>
  <configuration>
    <groups>testGroupA</groups>
    <systemPropertyVariables>
      <testNgParam>4</testNgParam>
      <testNgParam2>6</testNgParam2>
    </systemPropertyVariables>
    <parallel>methods</parallel>
    <threadCount>2</threadCount>
  </configuration>
</plugin>
We activate tests belonging to testGroupA and we pass parameter values for testNgParam and testNgParam2. We also let TestNG run each test method in parallel using 2 threads. This can significantly accelerate the testing phase when compiling the project.

Wednesday, 20 March 2013

'package javax.servlet.http does not exist' Solution

This is a common error which occurs when trying to compile a web project. This package is usually provided by the container. However, it is not (always) available at compile time and one should not include it in the final .war too.

If you are using Maven, the solution is simple. Add the following dependency with the provided scope:
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.5</version>
    <scope>provided</scope>
</dependency>
Your IDE will be able to compile your project and won't include the library in your .war.

You can also use the following dependency:
<dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-api</artifactId>
    <version>6.0</version>
    <type>jar</type>
    <scope>provided</scope>
</dependency>

Wednesday, 7 November 2012

Failed to execute goal org.apache.maven.plugins:maven-install-plugin:... (Access is denied)

This is the backporting of a question I asked on StackOverflow. I also provided the solution/workaround to it.

Issue

I was getting the following error when compiling a maven project with NetBeans:
[ERROR] Failed to execute goal
org.apache.maven.plugins:maven-install-plugin:2.3.1:install
(default-install) on project Plasma:
Failed to install artifact
net.dwst:Plasma:jar:1.0.0:
C:\...\.m2\repository\net\dwst\Plasma\1.0.0\Plasma-1.0.0.jar
(Access is denied) -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException:
Failed to execute goal
org.apache.maven.plugins:maven-install-plugin:2.3.1:install
(default-install) on project Plasma:
Failed to install artifact
net.dwst:Plasma:jar:1.0.0:
C:\...\.m2\repository\net\dwst\Plasma\1.0.0\Plasma-1.0.0.jar
(Access is denied)
  at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:203)
  at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:148)
  at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:140)
  at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:84)
  at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:59)
  at org.apache.maven.lifecycle.internal.LifecycleStarter.singleThreadedBuild(LifecycleStarter.java:183)
  at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:161)
  at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:316)
  at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:153)
  at org.apache.maven.cli.MavenCli.execute(MavenCli.java:451)
  at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:188)
  at org.apache.maven.cli.MavenCli.main(MavenCli.java:134)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
  at java.lang.reflect.Method.invoke(Method.java:597)
  at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:290)
  at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:230)
  at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:409)
  at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:352)
Caused by:
org.apache.maven.plugin.MojoExecutionException:
Failed to install artifact
net.dwst:Plasma:jar:1.0.0:
C:\...\.m2\repository\net\dwst\Plasma\1.0.0\Plasma-1.0.0.jar
(Access is denied)
  at org.apache.maven.plugin.install.InstallMojo.execute(InstallMojo.java:139)
  at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:107)
  at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:195)
... 19 more Caused by:
  org.apache.maven.artifact.installer.ArtifactInstallationException:
Failed to install artifact
net.dwst:Plasma:jar:1.0.0:
C:\...\.m2\repository\net\dwst\Plasma\1.0.0\Plasma-1.0.0.jar
(Access is denied)
  at org.apache.maven.artifact.installer.DefaultArtifactInstaller.install(DefaultArtifactInstaller.java:110)
  at org.apache.maven.plugin.install.InstallMojo.execute(InstallMojo.java:103)
... 21 more Caused by:
  org.sonatype.aether.installation.InstallationException:
Failed to install artifact
net.dwst:Plasma:jar:1.0.0:
C:\...\.m2\repository\net\dwst\Plasma\1.0.0\Plasma-1.0.0.jar
(Access is denied)
  at org.sonatype.aether.impl.internal.DefaultInstaller.install(DefaultInstaller.java:279)
  at org.sonatype.aether.impl.internal.DefaultInstaller.install(DefaultInstaller.java:190)
  at org.sonatype.aether.impl.internal.DefaultRepositorySystem.install(DefaultRepositorySystem.java:322)
  at org.apache.maven.artifact.installer.DefaultArtifactInstaller.install(DefaultArtifactInstaller.java:106)
... 22 more Caused by:
  java.io.FileNotFoundException:
C:\...\.m2\repository\net\dwst\Plasma\1.0.0\Plasma-1.0.0.jar
(Access is denied)
  at java.io.FileOutputStream.open(Native Method)
  at java.io.FileOutputStream.<init>(FileOutputStream.java:179
  at java.io.FileOutputStream.<init>(FileOutputStream.java:131)
  at org.sonatype.aether.impl.internal.DefaultFileProcessor.copy(DefaultFileProcessor.java:120)
  at org.sonatype.aether.impl.internal.DefaultInstaller.install(DefaultInstaller.java:255)
... 25 more [ERROR]  [ERROR]  [ERROR]
For more information about the errors and possible solutions, please read
the following articles: [ERROR] [Help 1]
http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
A workaround was to delete the .m2 content, but the issue would come back from time to time.

Solution

To solve the issue once for all, one has to delete the content of .m2 and re-install NetBeans from scratch.

Monday, 22 October 2012

Setting Logging Dependencies In Spring

This post describes how to set-up logging dependencies in Spring. It is based on information available in a post by Dave Syer. A reminder on Java logging frameworks is available here. The code example is available at GitHub in the Spring-Logging-Dependencies directory.

Spring uses Jakarta Commons Logging API (JCL). Unfortunately, many people do not like its runtime discovery algorithm. We can disactivate it and use SLF4J with Logback instead. We will use a variation of the Spring MVC with Annotations example to do so.

Here is the modified controller:
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class MyController {

    private static final Logger LOG
        = LoggerFactory.getLogger(MyController.class);

    @RequestMapping(value = "/")
    public String home(Model model) {

        String s = "Logging at: " + System.currentTimeMillis();
        LOG.info(s);

        model.addAttribute("LogMsg", s);

        return "index";

    }

}
We create a SFL4J logger and log some information with current time in milliseconds.

The maven dependencies are:
<properties>
    ...
    <spring.version>3.1.2.RELEASE</spring.version>
    <slf4j.version>1.7.1</slf4j.version>
    <logback.version>0.9.30</logback.version>
</properties>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${spring.version}</version>
    <exclusions>
        <exclusion>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
        </exclusion>
    </exclusions>
    <type>jar</type>
</dependency>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>${slf4j.version}</version>
    <scope>runtime</scope>
</dependency>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>${slf4j.version}</version>
    <type>jar</type>
</dependency>

<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>${logback.version}</version>
</dependency>

Once built, one can start the example by browsing: http://localhost:9393/spring-logging-dependencies/. It will display the following:

Spring Logging Configuration

In the logs, you will find the logged statement:

Spring Logging Statement

More Spring posts here.

Friday, 7 September 2012

What The !@"#[: Are Maven Parent Projects?

All Maven projects have a parent project. If not declared explicitly, a project will automatically inherit from the super pom.xml. All projects inherit from the configuration of their parent project. It is possible to create relationships between parent and child projects.

Maven Project Inheritance

Assuming a project is divided in several modules, each module is a maven project in itself. The parent's pom.xml would be like:
<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mygroupid</groupId>
    <artifactId>myprojectparent</artifactId>
    <version>1.0.0</version>
</project>
This parent project inherits of the super pom.xml. A child module project would declare its parent relationship like this:
<project>
    <parent>
        <groupId>com.mygroupid</groupId>
        <artifactId>myprojectparent</artifactId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>mymoduleproject</artifactId>
</project>
The child module project does not inherit of the super pom.xml. By not specifying a group id or a version, it inherits these from its parent. The parent's pom.xml must be located in the directory above this module project. Else, the location must be specified relative to this module's pom.xml file. For example:
    <relativePath>.../parentDir/pom.xml</relativePath>

Maven Project Aggregation

There is another way to establish a relationship between a parent project and child projects: project aggregation. Instead of declaring a parent project in the child project, the parent project declares modules:
<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mygroupid</groupId>
    <artifactId>myprojectparent</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging>
    <modules>
        <module>mymoduleproject</module>
    </modules>
</project>
The parent project's packaging must be set to pom and the pom.xml of child module projects must be located in directories bearing the module's name. Else, the module path must be specified relative to the
parent's pom.xml:
    <module>../myModuleDir/mymoduleproject</module>
If one compiles the parent project (or performs any other action on it), all its modules are compiled too.

REM: In this configuration, there is no inheritance between child projects and the parent project (only aggregation). Hence, child projects do not inherit of the parent's configuration. All projects of this aggregation inherit of the super pom.xml. They each have a life of their own.

Thursday, 6 September 2012

How To Add An External Repository In A Maven pom.xml?

By default, a maven project has access to the local repository and the central repository (see here for an introduction to maven concepts). It is possible to reference additional external repositories in the pom.xml to have access to its artifacts.
For example, it is currently not possible to access the following artifact from the central repository:
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test-mvc</artifactId>
    <version>1.0.0.M1</version>
    <scope>test</scope>
</dependency>
One should access it from: http://repo.springsource.org/libs-milestone. This can be achieved by adding the following to your pom.xml:
<project>
    ...
    <repositories>
        <repository>
            <id>spring.test-mvc</id>
            <url>http://repo.springsource.org/libs-milestone</url>
        </repository>
    </repositories>
</project>

Sunday, 26 August 2012

Simple Spring Web MVC Application (using Maven)

Spring Web MVC Application Example
This example is nothing more than the implementation of the Green Beans: Getting Started with Spring MVC example.

It is available from Github in the Simple-Spring-Web-Application directory.

This example can be started with the maven tomcat:run goal.

Then open http://localhost:8282/baremvc/.

For the compare example: http://localhost:8282/baremvc/compare?input1=Pit&input2=pat.

Spring MVC Features Showcase

For a demonstration of the Spring 3+ MVC features, there is a complete project described here.

It can be started with tomcat:run too.


Sunday, 19 August 2012

Conditional Javadoc Generation in Maven

Generating Javadoc at each build process can be very time consuming and pretty unnecessary. One can tackle this issue by moving Javadoc generation in a profile in the pom.xml:
<profiles>
  <profile>
    <id>JavadocGeneration</id>
    <build>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-javadoc-plugin</artifactId>
          <version>2.8.1</version>
          <executions>
            <execution>
              <id>attach-javadocs</id>
              <goals>
                <goal>jar</goal>
              </goals>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </build>
  </profile>
</profiles>
The above create a profile called JavadocGeneration. The Javadoc will be generated if and only if it is invoked:
mvn groupId:artifactId:goal -P JavadocGeneration

Monday, 13 August 2012

How to Include a Jar in a Maven Project?

This post is related to an answer I provided on Stackoverflow.com. It also contains a solution by Ryan Stewart.

There are situations when a .jar is required by a maven project, but it is not available in any repository. One needs a solution to make it a dependency in one's project. There are two solutions: including the .jar manually in your local repository and declare a systemPath.

Manual Inclusion in Local Repository

This requires a separate maven project based on the following pom.xml:
<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/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>net.mypackage</groupId>
    <artifactId>MavenMissingJars</artifactId>
    <version>1.0</version>
    <packaging>jar</packaging>
    <name>Maven Missing Jars</name>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-install-plugin</artifactId>
                <version>2.3</version>
                <executions>
                    <execution>
                        <id>dProguard-4.6</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>install-file</goal>
                        </goals>
                        <inherited>false</inherited>
                        <configuration>
                            <file>toinstall/4.6/proguard.jar</file>
                            <groupId>net.sf.proguard</groupId>
                            <artifactId>proguard</artifactId>
                            <version>4.6</version>
                            <packaging>jar</packaging>
                            <generatePom>true</generatePom>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
The configuration section is where one can indicate the location of the .jar to include and the maven coordinates to use, together with the packaging. This is a one time operation.

Use a System Path

Another solution is to to declare the following dependency in your projects' pom.xml:
<dependency>
    <groupId>net.sf.proguard</groupId><
    <artifactId>proguard</artifactId>
    <version>4.6</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/4.6/proguard.jar</systemPath>
</dependency>
The first solution can be used to include the .jar in a private or public repository and let all developers use it. The second solution is less hassle if you are working alone on your project.

Sunday, 12 August 2012

How to Use Sonar from Maven for Code Quality?

Sonar is by far the best open source tool to perform code quality checks. Not only it is free, it is also very easy to learn and to use. A true blessing.

Installation & Start

  1. Download the .zip file.
  2. Unzip in a local directory (for example: C:\Temp\Sonar)
  3. Go in the \bin directory and select the subdirectory corresponding to your operating system (for example: C:\Temp\Sonar\bin\windows-x86-32)
  4. Double-click on StartSonar.

Configuration

  1. Open http://localhost:9000
  2. Login as administrator (login: admin, password: admin)
  3. Click on Configuration
  4. Select Sonar way with Findbugs as default
Sonar Configuration

Usage

The following code sample is available on Github, in the Sonar-Example directory:
public class Sonar {

    public static class A {
        public void print() {
            System.out.println("Hello Word !");
        }
    }

    public static void main(String[] args) throws IOException {

        printMessage(null);

    }

    public static void printMessage(A a) {

        // Not testing for nullity
        a.print();

    }

}
We explicity create some silly code not testing for nullity. To enable Sonar in Maven, we include the following pom.xml dependency:
<dependency>
    <groupId>org.codehaus.sonar</groupId>
    <artifactId>sonar</artifactId>
    <version>3.1.1</version>
    <type>pom</type>
</dependency>
Next:
  1. Run the sonar:sonar maven goal on the project.
  2. Go back to http://localhost:9000
  3. Click on Home.
  4. Select Sonar-Example. Notice the errors and warnings reported by Sonar.
  5. Click on Critical.
  6. Click on the Sonar link (with a text icon)

Sonar has detected the suspicious null method call. This is a tiny example of what Sonar can do for you. You can configure it to use FindBugs and PMD too. Sonar is also an excellent opportunity to learn about your coding errors. It improves your style.

Monday, 6 August 2012

Code Coverage with Maven (One Pass)

Probably not the only solution to generate a code coverage HMTL report during the maven build process, but the Emma plugin does the job. In one pass. The code is available from Github in the Code-Coverage-One-Pass directory.

Assuming the following class:
public class ClassToTest {

    public static int coveredMethod(int i) {
        return i + 2;
    }

    public static int uncoveredMethod(int i) {
        return i + 3;
    }

}
with the following JUnit test:
public class ClassToTestTest {

    public ClassToTestTest() {
    }

    @Test
    public void testCoveredMethod() {
        assertEquals(4,ClassToTest.coveredMethod(2));
    }

}
one can configure the pom.xml as following:
    <build>

        <plugins>

            <plugin>
                <groupId>org.sonatype.maven.plugin</groupId>
                <artifactId>emma-maven-plugin</artifactId>
                <version>1.2</version>
                <executions>
                    <execution>
                    <phase>process-classes</phase>
                    <goals>
                        <goal>instrument</goal>
                    </goals>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.12</version>
                <configuration>
                    <classesDirectory>${project.build.directory}/generated-classes/emma/classes</classesDirectory>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <configuration>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.target}</target>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.sonatype.maven.plugin</groupId>
                <artifactId>emma4it-maven-plugin</artifactId>
                <version>1.3</version>
                <executions>
                    <execution>
                        <id>instrument</id>
                        <goals>
                            <goal>instrument-project-artifact</goal>
                        </goals>
                        <configuration>
                            <appendEmma>true</appendEmma>
                        </configuration>
                    </execution>
                    <execution>
                        <id>report</id>
                        <phase>post-integration-test</phase>
                        <goals>
                            <goal>report</goal>
                        </goals>
                        <configuration>
                        <sourceSets>
                            <sourceSet>
                            <directory>${project.build.sourceDirectory}</directory>
                            </sourceSet>
                        </sourceSets>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

        </plugins>

    </build>

    <dependencies>

        <dependency>
            <groupId>org.sonatype.maven.plugin</groupId>
            <artifactId>emma-maven-plugin</artifactId>
            <version>1.2</version>
        </dependency>

        ...

    </dependencies>

It will produce an index.html file in /target/site/emma/ (always the same location, so you can keep you browser open and refresh the after each build process):

Thursday, 2 August 2012

How to Add License Headers to Code Files via Maven?

This post explains how to automate the inclusion of headers in code files via Maven. We will add the following header (the code sample is available on GitHub) :
/**
 * Copyright (C) 2010-2012 MyCompany - All rights reserved.
 */
This header is based on a template located in src/main/resources/fileHeader.txt:
Copyright (C) ${h_inceptionYear}-${h_currentYear} ${h_copyrightOwner} - All rights reserved.
It contains three ${parameters} which are configured in the pom.xml. Two are defined in the properties:
<properties>
  ...
  <inceptionYear>2010</inceptionYear>
  <copyrightOwner>MyCompany</copyrightOwner>
</properties>
One is computed via a plugin (the current year):
<!-- Creating current year element -->
<plugin>
  <groupId>org.codehaus.groovy.maven</groupId>
  <artifactId>gmaven-plugin</artifactId>
  <version>1.0</version>
  <executions>
    <execution>
      <phase>validate</phase>
      <goals>
        <goal>execute</goal>
      </goals>
      <configuration>
        <source>
          import java.util.Date
          import java.text.MessageFormat
          def vartimestamp = MessageFormat.format("{0,date,yyyy}", new Date())
          project.properties['currentYear'] = vartimestamp
        </source>
      </configuration>
    </execution>
  </executions>
</plugin>
The template location, together with the parameters mapping and the types of files to ignore, is configured here:
  <!-- Adding header to file -->
  <plugin>
    <groupId>com.mycila.maven-license-plugin</groupId>
    <artifactId>maven-license-plugin</artifactId>
    <version>1.8.0</version>
    <configuration>
      <!-- Template location -->
      <header>src/main/resources/fileHeader.txt</header>
      <properties>
        <!-- Values to be substituted in template -->
        <h_inceptionYear>${inceptionYear}</h_inceptionYear>
        <h_currentYear>${currentYear}</h_currentYear>
        <h_copyrightOwner>${copyrightOwner}</h_copyrightOwner>
      </properties>
      <strictCheck>true</strictCheck>
      <excludes>
        <exclude>**/*.html</exclude>
        <exclude>**/*.xml</exclude>
        <exclude>**/*.txt</exclude>
        <exclude>**/*.ec</exclude>
        <exclude>**/*.log</exclude>
        <exclude>**/*.css</exclude>
        <exclude>**/*.js</exclude>
        <exclude>**/*.jsp</exclude>
        <exclude>**/*.md</exclude>
      </excludes>
    </configuration>
    <executions>
      <execution>
        <phase>validate</phase>
        <goals>
          <goal>format</goal>
        </goals>
      </execution>
    </executions>
  </plugin>

During the build process, proper headers are added (or updated) in code files:
/**
 * Copyright (C) 2010-2012 MyCompany - All rights reserved.
 */

package com.mypackage;

public class MyClass {

  // ...

}

Friday, 27 July 2012

How to Deploy a .war to Tomcat 7 via Maven?

In order to deploy a .war to Tomcat 7 during a maven build process, the cargo plugin is very useful.

One should add the following plugin in your pom.xml:
  <plugin>
    <groupId>org.codehaus.cargo</groupId>
    <artifactId>cargo-maven2-plugin</artifactId>
    <version>1.1.2</version>
    <configuration>
      <container>
        <containerId>tomcat7x</containerId>
        <type>remote</type>
      </container>
      <configuration>
        <type>runtime</type>
        <properties>
          <cargo.remote.uri>
            http://localhost:8080/manager/text
          </cargo.remote.uri>
          <cargo.remote.username>admin</cargo.remote.username>
          <cargo.remote.password>admin</cargo.remote.password>
        </properties>
      </configuration>
      <deployer>
        <type>remote</type>
        <deployables>
          <deployable>
            <groupId>com.my-group-id</groupId>
            <artifactId>my-artifact</artifactId>
            <type>war</type>
          </deployable>
        </deployables>
      </deployer>
    </configuration>
  </plugin>

The remote URI is configured to deploy the .war on a local Tomcat 7 installation listening to port 8080. The host could be a remote host too (one should use https instead for security).

The profile used to connect to maven must be configured with proper roles in the /conf/tomcat-users.xml file where Tomcat is installed, as following:
  <tomcat-users>
    <user name="admin" password="admin"
       roles="admin-gui,manager-gui,manager-script" />
    ...
  </tomcat-users>

Then you can use the following maven goals to deploy or redeploy your application:
  cargo:deployer-deploy
  cargo:deployer-redeploy
More Maven tips & tricks here.

How to Add JSLT Taglibs in a Maven Project?

Here are the dependencies you need to add to your pom.xml, to include JSLT 1.1.2 taglibs in your maven project, for Tomcat:
  <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <!-- Apache Taglibs does not implement version 1.2 -->
    <version>1.1.2</version>
  </dependency>

  <dependency>
    <groupId>taglibs</groupId>
    <artifactId>standard</artifactId>
    <version>1.1.2</version>
  </dependency>

  <dependency>
    <groupId>taglibs</groupId>
    <artifactId>c</artifactId>
    <version>1.1.2</version>
    <type>tld</type>
  </dependency>

  <dependency>
    <groupId>taglibs</groupId>
    <artifactId>fmt</artifactId>
    <version>1.1.2</version>
    <type>tld</type>
  </dependency>
If you want to use JSLT version 1.2 with Tomcat, set the following dependencies:
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>jstl</artifactId>
  <version>1.2</version>
</dependency>

<dependency>
  <groupId>org.glassfish.web</groupId>
  <artifactId>jstl-impl</artifactId>
  <version>1.2</version>
  <exclusions>
    <exclusion>
      <artifactId>servlet-api</artifactId>
      <groupId>javax.servlet</groupId>
    </exclusion>
    <exclusion>
      <artifactId>jsp-api</artifactId>
      <groupId>javax.servlet.jsp</groupId>
    </exclusion>
    <exclusion>
      <artifactId>jstl-api</artifactId>
      <groupId>javax.servlet.jsp.jstl</groupId>
    </exclusion>
  </exclusions>
</dependency>

For GlassFish:
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>jstl</artifactId>
  <version>1.2</version>
</dependency>

What Is The Difference Between  JSTL 1.1.2 and 1.2?

For more information about the difference between JSTL version 1.1.2 and 1.2, see the answer to this StackOverflow question.

JSTL Documentation

JSLT (the Java Server Page (JSP) tag library) is a core element of web applications. It is not easy to find documentation about tags, but some useful one is still available here and here.

More Maven tips & tricks here.

Maven: How to Refresh Dependencies in a Project?

There are situations where a simple mvn clean will not be enough to get rid of corrupted files or dependencies in a maven project. This can happen when a PC crashes during a compilation process or when the Internet connection is lost.

For example, one can encounter the following error message:
Build errors for XXX;
  org.apache.maven.lifecycle.LifecycleExecutionException:
Failed to execute goal on project YYY:
Could not resolve dependencies for project ZZZ:
The following artifacts could not be resolved: 
...
mvn clean will only clean the target (build) directory.

In order to force dependencies updates, one can use:
mvn clean install -U

How to Process LessCss .less Files into .css Files in a Maven Build Process?

Sample Maven LessCss Project
Thanks to Marcel Overdijk's plugin, it is now possible to process .less LessCss files into .css file during the maven build process.

Let's consider a maven web project, one can create a /css and a /less directory. The latter contains the source .less files, and the former will contain the processed .css files.

One should add the following plugin and dependency in pom.xml:
  <dependency>
    <groupId>org.lesscss</groupId>
    <artifactId>
      lesscss-maven-plugin
    </artifactId>
    <version>1.3.0</version>
  </dependency>

  <plugin>
    <groupId>org.lesscss</groupId>
    <artifactId>lesscss-maven-plugin</artifactId>
    <version>1.3.0</version>
    <configuration>
      <sourceDirectory>
        ${project.basedir}/src/main/webapp/less
      </sourceDirectory>
      <outputDirectory>
        ${project.basedir}/src/main/webapp/css
      </outputDirectory>
      <compress>false</compress>
      <includes>
        <include>example.less</include>
      </includes>
      </configuration>
    <executions>
      <execution>
        <goals>
          <goal>compile</goal>
        </goals>
      </execution>
    </executions>
  </plugin>

This configuration will convert the example.less file into a example.css file during the maven build process. Any existing .css file is overwritten at each build process.

A Maven project sample is available from Git.

How to Access Files/Data in the Resource Directory at Runtime?

A common concern of developers using Maven for the first time is how to access a file (binary or text) declared as a resource in Maven. Contrary to typical NetBeans projects (for example), maven insists on using a standard directory structure (more on Maven concepts here):

My Project
  |-src
    |-main
      |-java
      | |-MyPackage
      |   |-MyClass.java
      |-resources
        |-MyPackage
          |-MyData.txt

In a standard NetBeans project, since MyClass.java uses MyData.txt, both are (often) located in the same directory corresponding to the MyPackage Java package. However, in a Maven project, code is separated from data in different directories.

Some developers believe that the Maven directory structure will be replicated in the .jar after compilation. Therefore, they are tempted to try to open the data resource with a strategy similar to this one:
String loc = new File(".").getAbsolutePath()
  + "\src\main\resources\MyPackage\MyData.txt";
FileInputStream FIS = new FileInputStream(new File(loc));
...
In other words, they believe they have to handle the Maven directory structure themselves, including the absolute path to the current .jar location. This does not work.

First, one must keep in mind that Maven does not "push" its directory structure in .jars. Both MyClass.java and MyData.txt will be located in the same \MyPackage directory within the .jar. You can check this by opening the .jar with winzip for example.

The solution is the following (resource location is relative to Myclass location or package (*)):
InputStream IS = MyClass.class
    .getResourceAsStream("MyData.txt");

Caveat - Encoding Issue

If your data is not binary, you need to pay attention to the encoding format in the file itself (for example, set it to UTF-8) and make sure it is the same encoding as in your Maven project. You should have the following setting in your pom.xml:
<properties>
  <project.build.sourceEncoding>
    UTF-8
  </project.build.sourceEncoding>
  ...
<properties>
This is an issue that took me hours to solve, because encoding/display errors would only happen at runtime.

(*) More on absolute and relative path here.

REM: This post is a follow-up to an answer I provided on Stackoverflow.com.

Thursday, 10 May 2012

Introduction To Maven Concepts (Crash Course)

This is the post I wish someone had written to connect dots in 2007, when Maven documentation was scarce. This Maven tutorial is a starting point for those who have no experience with Maven, or who are willing to improve their global understanding of Maven concepts. It explains what Maven is, what you can do with it, but not how to do it. I will also give pointers to additional documentation.

What is Maven?

Maven is a software project implementation tool, but not a project management tool. In a factory, it would be the complete assembly line, taking in raw materials and producing finished products ready for use. It is mostly used by Java programmers, but it can be configured for other programming languages too.

If ever you have to work on a large Java project, you will most probably have to learn either about Maven or Ant (another project implementation tool). Otherwise, your project will quickly become unmanageable as it grows in size. Ant requires you to configure all your requirements from top to bottom. You have to build the whole assembly line for a given project. On the other side, Maven comes with default behaviors. If there is something you don't like in the assembly line, you can reconfigure it or extends parts to meet your specific needs.

There has been some religious wars between Ant users and Maven in the past. But today, they coexists in peace. In fact, it is pretty common for a Maven project to call Ant as a module to perform tasks it cannot perform itself.

Both Maven and Ant are functionally interchangeable. If an existing project works fine with Ant, you should not convert it to Maven. However, if you start a project from scratch, you may want to consider Maven, because of the very large support community and an incredible number of mature modules available for free under an open source license.

What Is The Form Factor?

Maven is a package you download and install on your PC. You just need to unzip it in a directory and make sure it is accessible from the command line (i.e., it has to be 'in the path'). Maven is a command line product with no graphic user interface (GUI). However, it is well integrated in free software development applications such as NetBeans or Eclipse. Most often, you will never need to run Maven from the command line. If you plan to use Ant with Maven, you will need to install it on your PC too.

How Does It Work?

When you start using Maven, it will first create a local repository on your PC. As you compile your software projects, all the results are posted in this local repository. The produced items are called artifacts. You can configure Maven to post those artifacts in other remote repositories or locations too, if necessary.

In addition to this local repository, there is what is called the central repository. It is a huge online repository containing tons of free artifacts contributed under an open source license over many years by thousands of developers. When Maven needs one of these artifacts to build a project and can't find it the local repository, it tries to fetch it from the central repository, if the local PC is connected to the Internet. Maven can be configured to search those artifacts in other public or private repositories too.

As a consequence, the first time Maven builds a project, it will download many artifacts from the central repository. It is a one time operation. You are not allowed to post something directly to the central repository. If you want to contribute your own artifacts, you need to read this.

There are three main types of repositories, the central repository, your local repository and public or private proprietary repositories.

What Is A Maven Project?

Contrary to many other software implementation tools, Maven projects operate according to a standard directory structure where different items (code files, test files, etc...) are expected to be found in well-known directories. It is part of the delivered assembly line.

It is not a good idea to try to reconfigure this directory structure to fit your karma. If another software engineer gets to work on your project, he will be confused. On the other side, if you get to work on another Maven project, you will be happy to find what you are looking for where it is supposed to be. Learn about Maven directory structures. Don't be a baby, open your mouth and do take the pill (lol)!

Another key project item is the Project Object Model XML file often called 'pom' or 'pom.xml'. Each project has its own directory structure with a pom.xml located at its root. Here is one the simplest possible pom.xml:

<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>


  <groupId>com.mycompany</groupId>
  <artifactId>SimpleMavenProject</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>pom</packaging>

</project>

It contains the 4 items making the coordinates of the project. Basically, it is the location of the project in repositories; a concatenation of the group id, the artifact id, and the project version (for a definition of SNAPSHOT, see (*) below) together with directory separators. The packaging explains how and which default artifacts will be bundled into the repository. You can organize and identify your projects as you wish using the coordinates you want. The packaging depends of the type of project your want to create.

The POM is where you will configure the different parts of the assembly line to meet your needs if default configuration is not enough.

Typically, under the hood, all Maven projects are created using an archetype. It is a kind of template used to create the default content of POMs and the default directory structure of Maven projects. You can create your own archetypes if you need to, but existing ones will cover most of your needs.

How Does The Compile Process Work?

The compile process is called the build process in Maven. It can be configured to perform much more than a simple compilation. Therefore, you should avoid mentioning a 'compile process' when talking about Maven, because it is only one of the phases of one of Maven's build processes (one step in the assembly line).

When a build process is executed, it goes through a life cycle using the information contained in the POM. Each life cycle is made of phases. Plugins are attached to phases. A phase can contain multiple plugins. A plugin is basically a set of operations of a given type which may be executed during a build cycle. Each possible plugin operation is called a goal. When a plugin is attached to a phase, a goal is specified (or else the default goal is executed).

The life cycle goes through each phase, sequentially, and executes each default (or configured in the POM) plugin goal, sequentially, until the end or until one of the plugin goal fails to execute. A Maven goal (as opposed to a plugin goal) is a step in the life cycle of a build process. By default, a build process will go the whole way through, unless a specific Maven goal is specified. In this case, Maven stops at this life cycle step, even if it is executed successfully.

By default, some plugins are attached to phases. Each plugin has a default goal which will be invoked unless it is configured differently in the POM. This is the default assembly line. You can also attach additional plugins to the phases of your build cycles. These will be downloaded from the central repository if necessary. You can also write your own plugins if you need to and use them in your build cycles.

Think about all this in terms of Lego's attached to a structural frame.

What About Maven Dependencies?

Large projects often use existing pieces of code (libraries) by making an explicit reference to them. In Maven projects, such dependencies to existing artifacts are specified in the POM, using their coordinates. Sometimes, these dependencies are just required for the build process (for the testing phase for example). Sometimes, they need to be shipped as part of the delivered artifacts. The type of use of the dependency is called a scope. It is specified in the POM

What About Profiles?

In order to cover complex situations (for example) when you need to create different types of artifacts for different target platforms, it would be tedious to maintain multiple POMs for the same project. The solution is called build profiles in Maven.

This is a mean to set additional configuration if the build process is to be executed for a specific platform (building for Windows or for Linux for example). In this case, corresponding plugins are only executed if they have been defined in the corresponding platform profile in the POM. A POM can be executed by specifying (or not) a build profile. This determines the set of plugins which will be executed on top of the default configuration.

Conclusion

There are many other features available in Maven. We have only mentioned the basics. If you want to learn more about Maven, including how to use it, the best resource available on the net is the Maven Complete Reference online guide.

After reading this guide, you should explore existing Maven modules. Learn what they can do for you. If you need help, type your question in Google followed by the word 'StackOverflow'. It most probably has already been answered. If not, go to StackOverflow.com and ask your question there.

-----

(*) SNAPSHOT versions can be confusing at the beginning. Let's assume you are working on a project and have released version 1.0.0. You are now working on version 1.1.0, but it has not been released and won't be released until you are done. Version 1.1.0 is work in progress. Yet, with Maven's build process, you are creating temporary work in progress artifacts. In order to differentiate these from production ready artifacts, you can add -SNAPSHOT to the work in progress version of your project (i.e.,  <version>1.1.0-SNAPSHOT</version>).

When you create Maven projects with dependencies to other artifacts/libraries, by default, maven ignores SNAPSHOT versions of those dependencies. Yet, if you want to access a specific SNAPSHOT version of a dependency, you can explicitly specify it in your pom.xml. This is often necessary during the development phase of a project.

For Maven parent projects, see here • More about Maven tips and tricks here.