-
Notifications
You must be signed in to change notification settings - Fork 24
Maven
Maven is a build tool used for Java projects. A build tool is a tool that automates everything related to building a software project. Building a software project usually follows the steps of:
- Generating source code
- Compiling source code
- Packaging compiled code into JARs or ZIPs
- Installing/deploying the packaged code into a server or somewhere else.
As we see, the advantage of a build tool is the automation of the build process for our software and minimizing the risk of humans making errors if they were to build the software manually.
Maven utilizes the so-called Project Object Model (POM), which configures the build process and is stored in the XML format in so-called pom.xml file. The POM file should be located in the root directory of the project it belongs to. Inside it, the developer can describe how the software is to be built as well as define the required dependencies, which are then dynamically downloaded from the specific repositories. In addition, Maven provides the developer with very specific, predefined tasks, that allow certain build processes to be performed without having to configure every detail.
The build process in Maven is split up into build life cycles, phases and goals. A build life cycle consists of a sequence of build phases, and each build phase consists of a sequence of goals. If a life cycle is requested executed, all build phases in that life cycle are executed. If a build phase is requested executed, all build phases before it in the pre-defined sequence of build phases are executed too. For example, the phase "maven package" would follow the
Maven lifecycle up to the package point and thus build, install, test and pack the project into the .jar format.
One of the most useful aspects of maven is the availability of plugins such as Tycho, Surefire, and Cobertura which extend Maven's toolset for very specific tasks. The use of these plugins is explained in the following sections.
For further information on the exact pom.xml structure and how to use the individual blocks and settings
please refer to the official Apache Maven site.
- Tycho: Since CogniCrypt is an Eclipse plugin, using Tycho makes the maven setup a lot easier. Tycho is a plugin for Maven which is specifically designed to be used for Eclipse projects. Since Maven requires the projects structure to be configured inside the POM and the IDE already defines the structure in its project specific files, plugins like Tycho can make use of this to ease the workload of developers. To use tycho it is enough to define it inside the plugin section of the pom. Tycho will then automatically retrieve the Eclipse specific files of this project.
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-maven-plugin</artifactId>
<version>${tycho-version}</version>
<extensions>true</extensions>
</plugin>
- Surefire: Surefire is a plugin for Maven which provides a way to execute the unit tests of the application during the test phase of the Maven lifecycle. In order for the test reports to be showed in Shippable at the at the end of the build, the output directory should be specified inside the POM as is shown in the code excerpt below:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.17</version>
<configuration>
<reportsDirectory>../../shippable/testresults</reportsDirectory>
</configuration>
</plugin>
- Cobertura: Cobertura plugin is used to generate test coverage reports in Shippable. Same as with Surefire plugin, the output directory for the coverage reports should be specified inside the POM file, as shown in the code excerpt below:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>2.7</version>
<configuration>
<maxmem>256m</maxmem>
<aggregate>true</aggregate>
<formats>
<format>html</format>
<format>xml</format>
</formats>
<outputDirectory>shippable/codecoverage</outputDirectory>
</configuration>
</plugin>
This section describes how a POM file is structured and explaining the structure of the POM files in CogniCrypt, since it is a project that contains multiple modules, each with their own child POM file.
The POMs that are used for the CogniCrypt project follow the basic maven structure to integrate and configure the necessary plugins. This basic structure starts with defining specifics of the object model and the artifact which is to be
build. A code excerpt from a POM file in CogniCrypt is shown below.
First the version of the object model that is being used is specified in the "modelVersion" setting. The ID and version settings after that are used to describe the artifact to be build. Packaging defines how the artifact type is packaged. While the standard setting for this is
"JAR", in our case it should usually be ’pom’. After that the necessary repositories and properties are being defined.
<modelVersion>4.0.0</modelVersion>
<groupId>de.cognicrypt</groupId>
<artifactId>de.cognicrypt.parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
The next step is used for the basic configuration. In the properties, we set the encoding or specific versions, which is in our case UTF-8 and the Tycho version 0.26.0. The repository part is used to give Maven access to all necessary repositories. Since we use tycho and therefore Eclipse, the only repository we need to set here is a valid p2 repository, that contains an Eclipse version for Maven to use. It is ideal to use the version of Eclipse that the artifact, which is to be build, is using. Otherwise you could encounter errors or unwanted behavior. As always, a code excerpt from the parent POM of CogniCrypt is shown below.
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<tycho-version>0.26.0</tycho-version>
</properties>
<repositories>
<repository>
<id>eclipse-oxygen</id>
<layout>p2</layout>
<url>http://download.eclipse.org/releases/oxygen</url>
</repository>
<repository>
<id>cryptsl</id>
<url>https://it.crossing.tu-darmstadt.de/cognicrypt/</url>
<layout>p2</layout>
</repository>
<repository>
<id>xtend</id>
<url>http://build.eclipse.org/common/xtend/maven/</url>
</repository>
<repository>
<id>xtext</id>
<layout>p2</layout>
<url>http://download.eclipse.org/modeling/tmf/xtext/updates/composite/releases/</url>
</repository>
</repositories>
The next step is setting up the actual build, which is done in the build part of the POM. While this part is being used to setup the build process, it is not necessary to go into the specifics as Maven handles most of it itself. What has to be setup in the build part of the POM, is which plugins or profiles to use and how they should be configured. In our case such plugins would be Tycho, Surefire, and Cobertura. We would have to get the groupID, artifactID and version of the specific plugin we want to use, which is information that can be gathered simply by entering the plugin's name in Google. An example of how it would look, is shown below:
<build>
<plugins>
<plugin>
<groupId></groupId>
<artifactId></artifactId>
<version></version>
</plugin>
</build>
In the case of CogniCrypt, it contains a parent POM, which is located at the root directory and multiple individual projects that are listed as modules in the parent POM. When the parent POM is being executed, it also contains the POMs of the individual projects as modules. This parent POM takes care of the general global settings, which are then used from all the child POMs, unless overwritten. We use this parent POM to configure the encoding, Tycho version and the Cobertura plugin for coverage reports, which are then also used from all child POMs. A code excerpt below shows how the child projects are listed as modules in the parent POM:
<modules>
<module>plugins/de.cognicrypt.core/</module>
<module>plugins/de.cognicrypt.codegenerator/</module>
<module>plugins/de.cognicrypt.crysl.handler/</module>
<module>plugins/de.cognicrypt.staticanalyzer/</module>
<module>plugins/de.cognicrypt.codegenerator.tests/</module>
<module>features/de.cognicrypt.codegenerator.feature/</module>
<module>features/de.cognicrypt.cryslhandler.feature/</module>
<module>features/de.cognicrypt.staticanalyzer.feature/</module>
<module>repository/</module>
</modules>
Lastly, we configure all the different environments for our target platform to use, which helps in ensuring our build runs on a multitude on different platforms. A code excerpt of the parent POM is shown below:
<configuration>
<environments>
<environment>
<os>linux</os>
<ws>gtk</ws>
<arch>x86</arch>
</environment>
<environment>
<os>linux</os>
<ws>gtk</ws>
<arch>x86_64</arch>
</environment>
<environment>
<os>win32</os>
<ws>win32</ws>
<arch>x86</arch>
</environment>
<environment>
<os>win32</os>
<ws>win32</ws>
<arch>x86_64</arch>
</environment>
<environment>
<os>macosx</os>
<ws>cocoa</ws>
<arch>x86_64</arch>
</environment>
</environments>
</configuration>
While the parent POM handles the global configurations that are used by most of the child POMs, the child POM for each project is used for project specific configurations. Firstly, we have to declare the parent POM at the beginning of the POM so that the global configurations are actually applied. This is done by adding the properties defined in the parent POM, as well as the relative path that leads to it. A code excerpt is shown below:
<parent>
<groupId>de.cognicrypt</groupId>
<artifactId>de.cognicrypt.parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
After this is done additional, project specific, configurations can be made in the following parts of the POM. In the case of CogniCrypt, we have made specific configurations mostly to the Surefire parts in order to be
able to run the plugin alongside Tycho. A code excerpt is shown below.
We first used a very specific version with 2.17, as versions of 2.18 and upwards rerun failed tests if not disabled. Since for some reason disabling this feature did not work correctly, we downgraded to a prior version because we did not need any of the other features that have been added. In addition, we set the specific JUnit version used to make sure that all tests work as intended.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.17</version>
<configuration>
<reportsDirectory>../../shippable/testresults</reportsDirectory>
</configuration>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit4</artifactId>
<version>2.17</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
</plugin>
The JUnit settings also have to be done for the test compiler plugin, as the same JUnit version has to be used in both cases. Since its also important that the tests are compiled at the correct time and even though Tycho has already compiled sources additional configurations have to be made for this plugin. A code excerpt is shown below.
The executions part makes sure that this plugin is executed every time its phase, which is the test-compile phase, is reached. Another configuration is the path to the source directory containing the tests. This is usually only important
if it differs from standard settings, which is ’src/test/java’ but it can be set just in case. The version of the source code can also be configured to make sure the correct Java version is used.
<executions>
<execution>
<id>compiletests</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
<configuration>
<testSourceDirectory></testSourceDirectory>
<source>1.8</source>
<target>1.8</target>
</configuration>
</execution>
</executions>
The last configuration is to make sure that M2Eclipse plugin doesn’t show any errors in the IDE. Therefore, we also add configurations that make M2Eclipse ignore the lifecycle metadata of our plugins. A code excerpt is shown below:
<pluginManagement>
<plugins>
<!--This plugin's configuration is used to store Eclipse m2e settings only.-->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.eclipse.tycho</groupId>
<artifactId>
tycho-packaging-plugin
</artifactId>
<versionRange>
[0.26.0,)
</versionRange>
<goals>
<goal>build-qualifier</goal>
<goal>validate-id</goal>
<goal>validate-version</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore></ignore>
</action>
</pluginExecution>
.................
</pluginManagement>