CI Tools and Best Practices in the Cloud

Continuous Integration

Subscribe to Continuous Integration: eMailAlertsEmail Alerts newslettersWeekly Newsletters
Get Continuous Integration: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn


Continuous Integration Authors: Stackify Blog, Aruna Ravichandran, Plutora Blog, Dalibor Siroky, PagerDuty Blog

Related Topics: Java EE Journal, Apache Web Server Journal, Continuous Integration

J2EE Journal: Article

An Introduction to Maven - Part I

A promising application development lifecycle management framework

Overview of the Maven 2 Working Model
Apart from the standardization of project structure and contents using conventions, Maven follows a set of in-built core competencies in pursuit of simplifying the project development build lifecycle.

Definition of build lifecycle phases: At Maven's core is the definition of build lifecycle phases. It's a fact that almost all software projects follow a series of steps during software building typically varying the number of steps and their sequencing. Maven standardizes these steps in pre-defined lifecycle phases and drives the build process through each phase in a specific logical sequencing order. Each phase can perform one or more actions or goals relevant to that lifecycle phase. Figure 1 captures Maven's phases and the logical order in which they are invoked.

The phase-specific actions and goals are accomplished by configuring Maven plug-ins. A Maven plug-in is a software extension that can execute one or more tasks. Each task is known as a Mojo and each Mojo tries to accomplish a certain build goal as part of executing a specific task.

For example, the JAR Mojo from Maven JAR plug-in creates a JAR file during the packaging phase of the Maven build lifecycle. With this kind of build choreography in place, different projects can take advantage of different combinations of phases with appropriate plug-ins bound to them to accomplish project specific build lifecycle.

Declarative execution and Project Object Model: Everything seems to be simplified using Maven because the Maven engine is driven in a declarative fashion. Project-specific metadata is declared in a descriptor file known as the Maven Project Object Model a k a POM. The project's POM file forms the cornerstone for executing Maven's build process. POM contains all the information required about the project such as project packaging type, output artifact coordinates, dependencies and dependency management information, and plug-in configuration information. Listing 1 is a sample POM file for a Maven project aimed at building a RAR file.

The sample POM in Listing 1 is for a JCA RAR project that will result in a 1.0 version of the JCA adapter. The sample POM states that the JCA project is dependent on two other artifacts, 'geronimo-spec-j2ee-connector-1.0-M1.jar' and 'junit-3.8.1.jar.' This POM also configures two plug-ins, 'maven-jar-plugin' and 'maven-rar-plugin,' and binds them to the 'package' phase of the Maven build lifecycle.

The sample POM in Listing 1 seems very simple in its configuration because in principle Maven shields the actual project POM from knowing all the other nitty-gritty default information by capturing such information in a Super-POM. When executing the build cycle, Maven implicitly associates the parent Super-POM with the project POM and thereby aggregates the overall project information needed to carry out the build process. Per se, every project POM has a parent Super-POM and so the project POM inherits lot of default information from the parent Super-POM. For more information on POM file contents, see http://maven.apache.org/pom.html.

Logical organization of dependencies and dynamic dependency resolution: As shown in the sample POM, all project dependencies and plug-ins are declared in the POM file. In the Maven world, each dependency and each plug-in is an artifact that can be uniquely identified using its coordinates namely group Id, artifact Id, and version number. As far as developers are concerned, their responsibility in terms of defining the project dependencies ends with the declaration of the dependencies in the POM file. Developers only deal with the declaration of logical dependencies without either physically downloading the dependencies to the project directory or setting the classpath to point to some location where dependent JARs are available. Everything else in terms of resolving the dependencies and setting dependent artifacts in the build classpath is transparently handled by Maven using its in-built dynamic dependency resolution mechanisms.

All artifacts are stored in Maven repositories. There are two kinds of Maven repositories - local and remote. Each repository stores artifacts in a logical structure using artifact coordinates. When Maven is installed, a local repository is typically created in the user home directory and is located at ~/.m2/repository. Figure 2 is an example local repository directory structure.

In the local repository example, the dom4j artifact is stored in a logical fashion using its group Id 'dom4j', artifact Id 'dom4j,' and version number '1.6.1.' In the dom4j/dom4j/1.6.1 directory, the actual artifact JAR file along with Maven's POM file is stored.

The Maven 2 remote repository is located at http://repo1.maven.org/maven2 and is a central repository for all kinds of open source artifacts. There are some other World Wide Web-accessible repositories such as the Codehaus repository located at http://repository.codehaus.org/ that contains artifacts for upcoming projects such as JRuby. A development organization can have its own remote repositories located in the company's intranet to store company-specific project artifacts. Figure 3 shows the repository layout for the central Maven repository.

By default, Maven uses http://repo1.maven.org/maven2 as the central remote repository at the time of dependency resolution. However, for a given project, additional remote repositories can be specified in the POM file as shown in Listing 2.

At the time of the build process, Maven resolves the dependencies specified in the POM file in the following order:
1.  Maven checks if the dependency artifact is present in the local repository using artifact coordinates. For example, the following POM snippet includes version 1.6.1 of dom4j as a dependency. To resolve this dependency, Maven will check if '~/.m2/repository/dom4j/dom4j/1.6.1/dom4j-1.6.1.jar' exists. Typically Maven will look for the dependency in the local repository using the location path built using the artifact coordinates - '~/.m2/repository/groupId/artifactId/version/artifactId-version.extenstion' where the extension by default is '.jar' unless the artifact type is specified in the dependency declaration using a '<type>' element.

<dependency>
         <groupId>dom4j</groupId>
         <artifactId>dom4j</artifactId>
         <version>1.6.1</version>
         <scope>runtime</scope>
</dependency>

If the group Id contains qualifiers separated by a period as in a company domain, Maven will include the qualifiers in the location path for the dependency artifact. For example, the location path '~/.m2/repository/com/ibatis/ibatis-sqlmap/1.3.1/ ibatis-sqlmap-1.3.1.jar' will be used to check if version 1.3.1 of the 'ibatis-sqlmap' artifact that has a group id of 'com.ibatis' is present in the local repository.
2.  If a dependency artifact isn't found in the local repository, Maven will attempt to download the artifact from the remote repository to the local repository. As in step 1, Maven will build the path using the artifact coordinates and the URL for the remote repository. For example, Maven will use the http://repo1.maven.org/maven2/dom4j/dom4j/1.6.1/dom4j-1.6.1.jar URL path to download version 1.6.1 of the dom4j artifact from the central Maven 2 artifact repository. The remote lookup for the artifact will start with the first configured remote repository in the POM. If the lookup fails with a '404 Not Found,' Maven will search for the artifact in the next configured remote repository. The purpose of downloading the artifacts to the local repository is to make the process more efficient by not having to look up remotely time and again. Thus the local repository acts as a local cache for all the artifacts and one place to go to for all artifact shopping. Note that Maven will also download other information such as the POM file for the dependency.
3.  If the dependency can't be resolved in any of the repositories, Maven will error out the build process.
4.  Once the dependency is resolved by downloading the artifact, if necessary, Maven will include that artifact in one of the Maven classpaths based on the scope of the artifact specified in the dependency declaration in the POM.
     a. compile: A compile-scope dependency is available in all phases. This is the default value for a dependency.
     b. provided: A provided dependency is needed at the time of compiling the application but need not be part of the deployment because such a dependency may be made available by other means during runtime such as an application server providing necessary container-specific classes etc.
     c. runtime: A runtime-scope dependency isn't needed for compilation but is needed at the time of execution.
     d. test: A test-scope dependency is needed for compiling and running test cases.
5.  Once the primary dependency is resolved, Maven will attempt to resolve all other artifacts that the primary dependency may internally depend on. This is commonly referred to as Maven 2 transitive dependency resolution. To achieve this, Maven will read the primary dependency's POM file found in the local repository alongside the artifact's JAR file, identify its dependencies, and go about resolving those dependencies using the same approach by repeating the steps from #1.

Conclusion
In Part 1 of this article, we introduced Maven through a quick tour of some of its core internals without delving into details of how to exercise Maven. We think that without understanding the basics first, it will be hard to sail into the nitty-gritty practicalities. In Part 2, we will get into the details of installing Maven, configuring the Maven plug-in in Eclipse, and providing a practical example that illustrates how to accomplish typical development tasks and how Maven simplifies the process, making development much more productive.

More Stories By Murali Kashaboina

Murali Kashaboina leads Enterprise Architecture at United Airlines, Inc. He has 15+ years of enterprise software development experience utilizing a broad range of technologies, including JEE, CORBA, Tuxedo, and Web services. Murali previously published articles in WLDJ and SilverStream Developer Center. He has master’s degree in mechanical engineering from the University of Dayton, Ohio.

More Stories By Geeth Narayanan

Geeth Narayanan is a senior architect at Ecommerce Technology, United Airlines, Inc. He has 10 years of experience in the IT industry, specializing in solutions using Java EE technologies. Geeth has master's degree in electrical engineering from the University of Toledo, Ohio.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.