Using Maven 2

nutmegactΛογισμικό & κατασκευή λογ/κού

10 Νοε 2012 (πριν από 5 χρόνια και 4 μέρες)

339 εμφανίσεις

Using Maven2

Free Maven Books

Maven: The Definitive Guide (alpha)


www.sonatype.com/book

Better Builds with Maven

www.mergere.com

The Maven Site

http://maven.apache.org/

What is Maven?


Build lifecycle


Dependency management tool


Artifact repository


Collection of plugins


Project reporting tool


Set of conventions


Distilled experience

What Else is Maven?


Succinct command line tool


Designed for Java/Java EE/other


Holder/publisher of project documentation


Generator of project metrics


Customisable: environment, lifecycle, etc


Inheritable


Declarative


Encourager of modularity and reuse


Integrated with SCM tools


Integrated with IDEs


Integrated with Ant


System of repositories


Project kick starter


Release manager


Deployer


Enabler of portable build knowledge


Encourager of best practice


Community


Not perfect

Quick Start


Download Maven2, unzip, add bin directory to $PATH


Configure proxy in ~/.m2/settings.xml if required

$ mvn archetype:create
\

-
DgroupId=com.example
\

-
DartifactId=my
-
app

Directory Structure

Convention


Java sources:

src/main/java



Unit tests:

src/test/java



pom.xml

pom.xml


The Project Object Model

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


<modelVersion>4.0.0</modelVersion>


<groupId>
com.example
</groupId>


<artifactId>
my
-
app
</artifactId>


<packaging>jar</packaging>


<version>1.0
-
SNAPSHOT</version>


<name>my
-
app</name>


<url>http://maven.apache.org</url>


<dependencies>


<dependency>


<groupId>junit</groupId>


<artifactId>junit</artifactId>


<version>3.8.1</version>


<scope>test</scope>


</dependency>


</dependencies>

</project>


Directory Structure Convention

Added:


My app sources



Properties file:

src/main/resources/
messages.poperties



My unit test

Killer App

package com.example;




public class Hello {


public static void main(String[] args){


ResourceBundle messages = ResourceBundle.getBundle("messages");


MessagePrinter mp = new MessagePrinter();


mp.printMessage(messages.getString("message1"), System.out);


mp.printMessage("
\
n", System.out);


}

}

public class MessagePrinter {


public void printMessage(String message, OutputStream os){


PrintWriter pw = new PrintWriter(os);


pw.print(message);


pw.flush();


}

}


My Application POM

<project ...>


...


<name>
My Application
</name>


<url>http://localhost:8080/my
-
app</url>


...


<build>


<plugins>


<plugin>


<artifactId>maven
-
jar
-
plugin</artifactId>


<configuration>


<archive>


<manifest>


<mainClass>
com.example.Hello
</mainClass>


</manifest>


</archive>


</configuration>


</plugin>


</plugins>


</build>

</project>

Eclipse Integration


Maven
2
plugin for Eclipse;
either

from project
root execute:


$ mvn eclipse:eclipse


and import with Eclipse,
or

create the project
in Eclipse and add the Maven
2
project nature


Eclipse Integration

Ready for Take Off

$ mvn package

stdout

[INFO] Scanning for projects...

[INFO]
----------------------------------------------------------------------------

[INFO] Building My Application

[INFO] task
-
segment: [package]

[INFO]
----------------------------------------------------------------------------

[INFO] [resources:resources]

[INFO] Using default encoding to copy filtered resources.

[INFO] [compiler:compile]

[INFO] Compiling 1 source file to /home/russell/Desktop/maven
-
presentation/example/my
-
app/target/classes

[INFO] [resources:testResources]

[INFO] Using default encoding to copy filtered resources.

[INFO] [compiler:testCompile]

[INFO] Compiling 1 source file to /home/russell/Desktop/maven
-
presentation/example/my
-
app/target/test
-
classes

[INFO] [surefire:test]

[INFO] Surefire report directory: /home/russell/Desktop/maven
-
presentation/example/my
-
app/target/surefire
-
reports


-------------------------------------------------------


T E S T S

-------------------------------------------------------

Running com.example.AppTest

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.022 sec


Results :


Tests run: 1, Failures: 0, Errors: 0, Skipped: 0


[INFO] [jar:jar]

[INFO] Building jar: /home/russell/Desktop/maven
-
presentation/example/my
-
app/target/my
-
app
-
1.0
-
SNAPSHOT.jar

[INFO]
------------------------------------------------------------------------

[INFO] BUILD SUCCESSFUL

[INFO]
------------------------------------------------------------------------

[INFO] Total time: 3 seconds

[INFO] Finished at: Wed Jul 04 11:11:55 NZST 2007

[INFO] Final Memory: 4M/11M

[INFO]
------------------------------------------------------------------------

The (Almost)

Finished Product


Classes and test
classes compiled


Resources copied to
classes directory


Test reports created


Jar file created

$ java
-
jar my
-
app
-
1.0
-
SNAPSHOT.jar

Hello World!

Plugins & Goals


A plugin contains one or more goals

(Goal a.k.a. Mojo; Maven + Pojo = Mojo

?!@!)



A plugin is a Maven artifact


A goal is uniquely referenced/invoked by:

groupId:artifactId:version:goal


e.g: org.apache.maven.plugins:maven
-
eclipse
-
plugin:eclipse

defaults shorten this to: eclipse:eclipse

Anatomy of a Maven Command

1. Invoke a specific goal:

$ mvn [options] plugin:goal [parameter]...


e.g:

$ mvn
-
e eclipse:eclipse


-
> Generate Eclipse configuration, print verbose error messages

2. Invoke goals bound to the lifecycle(s) up to and including
a phase:

$ mvn [options] phase... [parameter]...


e.g:

$ mvn clean package
-
Dmaven.test.skip=true


-
>
Clean target, build package, skip tests

Maven Lifecycles


Three built
-
in lifecycles:


default


clean


site


You can create your own lifecycle, but only if
you have really weird build requirements!

The Default Build Lifecycle

Project Packaging

<project ...>


<modelVersion>
4.0.0
</modelVersion>


<groupId>com.example</groupId>


<artifactId>my
-
app</artifactId>


<packaging>
jar
</packaging>


<version>
1.0
-
SNAPSHOT</version>


...

</project>


Lifecycle Bindings

Build Lifecycle

$ mvn package

stdout

[INFO] Scanning for projects...

[INFO]
----------------------------------------------------------------------------

[INFO] Building My Application

[INFO] task
-
segment: [package]

[INFO]
----------------------------------------------------------------------------

[INFO] [resources:resources]

[INFO] Using default encoding to copy filtered resources.

[INFO] [compiler:compile]

[INFO] Compiling 1 source file to /home/russell/Desktop/maven
-
presentation/example/my
-
app/target/classes

[INFO] [resources:testResources]

[INFO] Using default encoding to copy filtered resources.

[INFO] [compiler:testCompile]

[INFO] Compiling 1 source file to /home/russell/Desktop/maven
-
presentation/example/my
-
app/target/test
-
classes

[INFO] [surefire:test]

[INFO] Surefire report directory: /home/russell/Desktop/maven
-
presentation/example/my
-
app/target/surefire
-
reports


-------------------------------------------------------


T E S T S

-------------------------------------------------------

Running com.example.AppTest

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.022 sec


Results :


Tests run: 1, Failures: 0, Errors: 0, Skipped: 0


[INFO] [jar:jar]

[INFO] Building jar: /home/russell/Desktop/maven
-
presentation/example/my
-
app/target/my
-
app
-
1.0
-
SNAPSHOT.jar

[INFO]
------------------------------------------------------------------------

[INFO] BUILD SUCCESSFUL

[INFO]
------------------------------------------------------------------------

[INFO] Total time: 3 seconds

[INFO] Finished at: Wed Jul 04 11:11:55 NZST 2007

[INFO] Final Memory: 4M/11M

[INFO]
------------------------------------------------------------------------

Dependencies

<project ...>


...


<dependencies>


<dependency>


<groupId>junit</groupId>


<artifactId>junit</artifactId>


<version>3.8.1</version>


<scope>test</scope>


</dependency>


</dependencies>

</project>


Explicitly declared, including version


Resolved by Maven, not required in project
directory / source control repository


Scoped: compile, provided, runtime, test


SNAPSHOT dependencies updated


Transitive


Strictly acyclic (a DAG not a tree)


Killer App Reloaded

public class Hello {


public static void main(String[] args) {


ReloadableResourceBundleMessageSource messages


= new ReloadableResourceBundleMessageSource();


messages.setCacheSeconds(1);


messages.setBasename("messages");


MessagePrinter mp = new MessagePrinter();


Scanner scanner = new Scanner(System.in);


do {


String message = messages.getMessage("message1", null,


Locale.getDefault());


mp.printMessage(message, System.out);


mp.printMessage("
\
n", System.out);


mp.printMessage("Keep playing? [Y/n]
\
n", System.out);


} while (!"n".equals(scanner.nextLine()));


}

}


Dependencies

<project ...>


...


<dependencies>


<dependency>


<groupId>org.springframework</groupId>


<artifactId>spring
-
context</artifactId>


<version>
[2.0,)
</version>


<exclusions>


<exclusion>


<groupId>org.springframework</groupId>


<artifactId>spring
-
aop</artifactId>


</exclusion>


...


</project>


Version ranges


Use exclusions to trim unwanted
dependencies

Transitive Dependencies

Reloadable Message Source

Hello World!

Keep playing? [Y/n]

y

Hello Again World!

Keep playing? [Y/n]

n



Note for anyone trying this at home: there's a bit of classpath
config required to get this working nicely. It's easiest to run it
on the Eclipse console, and modify the target
messages.properties

Configuring Plugins

e.g. Ant

<project...>


...


<build>


<plugins>


<plugin>


<artifactId>maven
-
antrun
-
plugin</artifactId>


<executions>


<execution>


<phase>generate
-
sources</phase>


<configuration>


<tasks>


<!
--


Place any ant task here. You can add anything you can add


between <target> and </target> in a build.xml.


--
>


</tasks>


</configuration>


<goals>


<goal>run</goal>


</goals>


</execution>


</executions>


</plugin>


</plugins>


</build>

</project>

Standard

Maven Plugins

clean

compiler

deploy

install

resources

site

surefire

verifier

ear

ejb

jar

rar

war

changelog

changes

checkstyle

clover

doap

docck

javadoc

jxr

pmd

project
-
info
-
reports

surefire
-
report

ant

antlr

antrun

archetype

assembly

dependency

enforcer

gpg

help

invoker

one

plugin

release

remote
-
resources

repository


scm

source

eclipse

idea

Codehaus:

build
-
helper

castor

javacc

jdepend

native

sql

taglist

Other:

cargo

jaxme

jetty

jalopy

Listed at: http://maven.apache.org/plugins/

POM Inheritance

<project>


<modelVersion>4.0.0</modelVersion>


<groupId>
com.example
</groupId>


<artifactId>
my
-
app
</artifactId>


<version>1.0
-
SNAPSHOT</version>

</project>


No source or target defined in
POM, yet this works:


$ mvn compile

Super POM

<project>


<build>


...


<outputDirectory>
target/classes
</outputDirectory>


...


<sourceDirectory>
src/main/java
</sourceDirectory>


...


<resources>


<resource>


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


</resource>


</resources>


...


</build>

</project>

To fully resolve the POM:

$ mvn help:effective
-
pom | less

POM Inheritance

<project>


<parent>


<groupId>com.example</groupId>


<artifactId>org
-
pom</artifactId>


<version>1</version>


</parent>


<groupId>com.example</groupId>


<artifactId>my
-
app</artifactId>


...

</project>

<project>


<groupId>com.example</groupId>


<artifactId>org
-
pom</artifactId>


<version>1</version>


<!
--

configure


JDK version, e.g: 1.5


standard reports, etc.
--
>

</project>

Maven Repositories


Repositories store artifacts:


plugins


project dependencies


Central:
http://repo
1
.maven.org/maven
2

(or mirror)



Local: ~/.m
2
/repository


The first execution of a
plugin, or requirement for a
dependency pulls the artifact
from central and caches it
locally

Maven Repositories

Problems:


Reliant on network and
external repository for
dependencies and plugins


Can't deploy to Central
Maven repository for reuse
as dependencies of other
projects (though usually
wouldn't want to)


Organisation Repository


No longer reliant on
network or external
repository for
dependencies and plugins


Can deploy to organisation
repository in order to share
artifacts


Multiple repository
configurations possible


Multiple repository tools
available: Archiva,
Proximity, Artifactory

Archiva

Install and Deploy

$ mvn deploy

Install and Deploy

$ mvn deploy

SCM Integration


Fully implemented:


Bazaar


CVS


Mercurial


Perforce


StarTeam


Subversion


CM Synergy


Partially implemented:


ClearCase


File system


Visual Source Safe

Configuring SCM

<project>


<groupId>com.example</groupId>


<artifactId>my
-
app</artifactId>


...


<scm>


<connection>


scm:svn:http://example.com/svn
-
read/my
-
app/trunk



</connection>


<developerConnection>


scm:svn:http://example.com/svn
-
dev/my
-
app/trunk


</developerConnection>


<url>


http://example.com/view.cvs


</url>


</scm>

</project>

SCM Integration,

What For?


Use SCM agnostic commands:

$ mvn scm:checkin
-
Dmessage="to the cause"

$ mvn scm:update


Project bootstrapping:
$ mvn scm:bootstrap


Available for use by Maven tools, e.g:
documented and linked in project website,
published in Archiva summary


Continuous Integration, SCM details located in
project rather than CI tool


Release management

Cutting a Release

$ mvn release:prepare [
-
DdryRun=true]


Checks SCM for modifications


Checks for use of SNAPSHOT dependencies or plugins


Runs $ mvn clean integration
-
test


Requests release info:


version numbers


Creates new POMs:


pom.xml for tag


pom.xml for next version


release
-
pom.xml


Creates tag in SCM

$ mvn release:perform


Uses release
-
pom.xml, deploys

project, generates site, etc.

Website / Reports (
1
)



Project website:


Conventions for structuring documentation,
supporting various formats: DocBook simple, FML,
XDOC, APT, Twiki


Directory structure conventions, supporting multiple
types of documentation, e.g: public, user, developer,
etc.


Configurable, skinnable site


Project info from POM: contact details: organisation,
developers; SCM details, etc.

Website / Reports (
2
)



Metrics, checks, and project reports (on website):


Javadoc


Test results


Code coverage (Cobertura)



Checkstyle, PMD, JDepend, Clirr


Database documentation (Hibernate)



Dependency report


TODO report (//TODO, FIXME, configurable)



Linked and line
-
numbered HTML sources


Release notes and roadmap from issue tracker

Quick Tour

In Brief (
1
)



Java EE support:


WAR, EAR packaging


Rapid web app development


Integration (in container) testing


Deployment to environments


Multi
-
module projects


Enable / encourage reuse between projects


Maven inter
-
module dependency eliminates cycles
between modules


Nicely supported in NetBeans


Not nicely supported in Eclipse


nested projects

In Brief (
2
)



Continuous Integration:


CruiseControl


Continuum


Reuses project information as defined in POM


Profiles


Build activity carried out under different conditions,
e.g: personal requirements, dev / test / release,
continuous integration


Maven settings


Help

Problems


History: Maven
1
, might have left a bad taste


Steep learning curve


Once you've got it, the knowledge is portable to
other projects built with Maven


Complex needs require complex configuration


Alan Kay: Simple things should be simple.
Complex things should be possible


Verbose XML config


Docs aren't great, but getting better


Error messages often do not provide much (or any)
detail (e.g. archetype problem)



Ensuring the project is buildable and testable in the
IDE as well as with Maven can be complex


Multi
-
module projects not supported by Eclipse (but
they are in Netbeans)


Stuff to Look at


Buildr


a build system configured in Ruby
that reuses parts of Maven:


repositories;


directory structure conventions;


Rake


a Ruby build tool

Still Interested?

Get reading and enjoy the ride

Questions?