Object Oriented and beyond Maven 2 in the real world Carlo Bonamico carlo.bonamico@gmail.com JUG Genova
Maven2: love it or hate it? Widespread build platform used by many open source and commercial projects PROs automatic dependency management good tool/ide support automate the entire build life cycle highly configurable CONs highly configurable :-) too much XML... also... lots of tutorials on simple cases, less documentation on complex builds
Presentation goals Maven can be your friend (and save lots of time!) if you learn it and understand it use it in the right way My talk is about how to maximize usefulness and efficiency while minimizing complexity & overhead Sharing real world experience in designing and managing the build process for several large projects (>20 modules, >100 kloc)
Part 1 Maven2 in 5 minutes
Maven2 in 5 minutes Maven is a modular automation system built around 4 main elements POM repository Maven src Plugins input: project src/resources + POM output: tested and packaged artifact
Maven in 5': the POM The Project Object Model describes project coordinates project type packaging (JAR, WAR, EAR, POM) source structure groupid: net.juggenova artifactid: sample version: 1.0 build phases standard + custom dependencies plugins
Maven in 5': build lifecycle Default life cycle validate Every goal implies all the previous ones generate-sources process-resources compile test-compile test package integration-test mvn compile actually executes validate generate-sources process-resource compile verify install Stand-alone goals deploy (some skipped for clarity) mvn scm:update
Maven in 5': Dependency Management Dependencies include all external libraries and files needed to completely assemble the output JARs, WARs, ZIPs, POMs are versioned can be transitive e.g. include just spring, get commons-logging automatically Conflict resolution mechanism determines the version to be used when a jar is included multiple times
Maven in 5': repositories Maven repository a structured store containing artifacts (JAR, WAR, ZIP...) Maven uses at leas two local repository on your PC central repository http://repo1.maven.org/maven2/ Three types of repositories plain filesystem folder local repository folder served by HTTP daemon populated via SCP/FTP/WEBDAV ${user.home}/.m2/repository full intelligent repository (with indexing, search, cache,...)
From code to repo (and back) deploy install remote repository local repository package resolve central repository
Part 2 Effective maven2
Getting the most out of Maven Good old sw engineering principles still apply! Don't repeat yourself the DRY principle reduce time, effort, maintenance minimize the impact of changes Separate concerns Automate as much as possible Use the right tools (plugins & repositories) Keep the build fast things always change in a project
How to minimize XML Exploit the three main POM relationships inheritance, aggregation, dependency This is a valid (and working) maven POM <project xmlns="..." xmlns:xsi="..." xsi:schemalocation="..."> <modelversion>4.0.0</modelversion> <groupid>net.juggenova.sample</groupid> <artifactid>minimal</artifactid> <version>1.0</version> </project> How can this work?
The Super POM Implicitely, all POMs inherit from the Super POM see http://maven.apache.org/pom.html Defines standard directory structure default plugins & repo Super POM where it is? inside mvn jars how to check it? mvn help:effective-pom Convention over Configuration your POM
The Super-POM <repos itories > <repos itory> <id>central</id> <name>maven R epos itory S witchboard</name> <url>http://repo1.maven.org/maven2</url> </repos itory> </repos itories > <build> <s ourcedirectory>s rc/main/java</s ourcedirectory> <tes ts ourcedirectory>s rc/tes t/java</tes ts ourcedirectory> <outputdirectory>targ et/clas s es </outputdirectory>... <res ources > <res ource> <directory>s rc/main/res ources </directory> </res ource> </res ources > <tes tresources >...</testres ources >
The Super-POM <plug inmanag ement> <plugins> <plug in> <artifactid>maven-as s embly-plug in</artifactid> <vers ion>2.2-beta-1</vers ion> </plug in> <plug in> <artifactid>maven-compiler-plug in</artifactid> <vers ion>2.0.2</vers ion> </plug in>... </plugins > </plug inmanag ement> </build>
Parent POM: make you own Create a POM defining your project conventions and tools additional resource directories default plugin configuration e.g. custom configuration for maven-compiler-plugin standard libraries e.g. default spring version with <dependencymanagement> repositories and deployment config e.g. your company repository with <distributionmanagement>
net.juggenova.sample:parent <build> <s ourcedirectory>java/s rc</s ourcedirectory>... <plug inmanag ement> <plugins> <plug in> <g roupid>org.apache.maven.plug ins </g roupid> <artifactid>maven-compiler-plug in</artifactid> <config uration> <s ource>1.6</s ource> <targ et>1.6</targ et> </config uration> </plug in> <plug in> <artifactid>maven-s urefire-plug in</artifactid> <config uration>...</config uration> </plug in> </plugins >
Parent POM: use it Reference the parent at the beginning of a POM Useful <parent> <artifactid>parent</artifactid> <groupid>net.juggenova.sample</groupid> <version>1.1</version> <relativepath>../parent</relativepath> </parent> if you have many similar projects/components to separate responsibilities between senior and junior developers to encapsulate company-wide settings
Issues and suggestions Main issue: children must reference parent version explicitely strong dependency! (as usual with inheritance) there is no <version>latest</version> or <version>[1.0,)</version> for the parent if you change the parent, must update ALL children So, avoid putting in the parent things that change your project modules versions developer/machine-specific settings
Suggestion Separate things that change from things that stay the same Bruce Eckel
Dependency POMs Maven2 supports transitive dependencies controlled by a consistent use of the <scope> tag compile (default) your libs test junit, spring-test provided servlet-api runtime your POM library POM log4j system minimize them! tools.jar
Issues and suggestions Good old encapsulation / minimize coupling minimize dependencies minimize visibility Can also define codeless POMs, which only contain a group of other dependencies declare with <packaging>pom</packaging> used with <dependency>... <type>pom</type> </dependency>
Dependency Management Several libraries are often used in many modules commons-logging, spring, servlet-api,... avoid repeating their version everywhere in POMs Apply DRY & separation of concerns which version to use in the parent/main POM <dependencymanagement> (artifact, group, version) whether to use it <dependency> (artifact, group only) </dependency> Tip: <dependencymanagement> is also effective in overriding versions coming from transitive dependencies
Aggregation Multimodule projects every goal is repeated on all modules by the reactor plugin mvn clean mvn compile modules can be children of master but not necessarily <modules > <module>client</module> <module>s erver</module> <module>tes t</module> </modules > main POM module POM
Issues and suggestions Issue: modules are referenced by folder name beware when checking out or renaming Issue: IDE plugin support is not perfect m2eclipse requires manual refresh of dependencies after configuration changes also, different classpaths in eclipse and maven when opening a multimodule project as a single project netbeans only supports separate modules Risk: pom proliferation (think of maintenance) mvn modules vs SVN modules
Suggestion Common Reuse Principle Package together what is used/reused togehter Robert C. Martin
Tip: create a Master POM A component list POM does not have its own code or settings just an index of all modules to be built it is NOT the parent of the modules Example: the main spring pom which triggers the build of spring-core spring-mvc spring-test...
Make it easy to create new projects Define an archetype a customizable template for creating a kind of projects (e.g. a web application) defines POMs, project structure Simple setup with mvn archetype:create-from-project customize with resource filtering ${property} references in the archetype Use http://appfuse.org library of pre-assembled archetypes
Part 3 Automate the entire build
Automate the entire build Build means much more than compile! Avoid manual steps! copy, rename, deploy to a test server... pass configuration information Automatically process resources copy and filter configuration files, CSS, HTML, properties Share resources across projects package them as jar/zip reuse them in a war project with jar/zip/war overlays http://maven.apache.org/plugins/maven-war-plugin/overlays.html
Assembly plugin Creates zips/jars containing any kind of resource project sources common files XSDs html/css templates http://maven.apache.org/plugins/maven-assembly-plugin
Preview and test webapps with the Jetty plugin Run a webapp directly from source folders Advantages mvn jetty:run very fast resource changes are visible without restart automatic redeploy after code changes http://docs.codehaus.org/display/jetty/maven+jetty+plugin Now a mvn glassfish:run goal is also available full JEE 5.0 support https://maven-glassfish-plugin.dev.java.net/
Automate deployment Deploy to an application server with cargo can even download, install and run a full Jboss instance for testing purposes http://cargo.codehaus.org/ Write custom ssh-based scripts using the ssh/scp ant tasks within the maven-antrun-plugin transfer files to test servers launch administration scripts
Integrate with the IDE E.g. Eclipse plugin (m2eclipse) http://m2eclipse.sonatype.com
Use a group repository Why your own? Within a Team deploy and share your project artifacts so that other developers do not have to rebuild them mavenize external jars which miss a POM centrally configure and control which repositories and artifacts are used cache dependencies available when internet connection breaks faster download times
Sonatype Nexus repository Powerful web-based console and REST API Lightweight Easily upload artifacts via HTTP Quickly search for jars with the included index Download from http://nexus.sonatype.org/ unzip and run!
settings.xml: Mirror definition Team repository in addition to central <repository> <id> set </id> <url> http://server:8080/repository </url> </repository> Team repository as a mirror of central (or others) <mirror> <id> central </id> <url> http://server:8080/repository</url> <mirrorof> central </mirrorof> </mirror> Team repository as the only one <mirror> <id>... </id> <url>... </url> <mirrorof> * </mirrorof> </mirror>
Part 4 Troubleshooting
Build troubleshooting Verify POM structure mvn validate Verify actually used dependencies mvn dependency:tree Verify the full POM -Dinclude=spring mvn help:effective-pom m2eclipse plugin Moreover, keep a consistent naming scheme to prevent typos
Debug/Log Run mvn with -e (print Exception stacktraces) -X (print debug info) POM information can be accessed at runtime! META-INF/<group>/<artifact>/pom.properties groupid artifactid version META-INF/../pom.xml full POM info R es ource[] res ources = applicationc ontext.getres ources ("clas s path*:meta-inf/maven"+ "/**/pom.properties "); for (Res ource r : res ources ) { Properties p = new Properties (); p.load(r.g etinputs tream()); artifact = p.g etproperty(" artifactid"); vers ion = p.getproperty("vers ion"); }
Add a timestamp to your builds Automatically define a timestamp property use it in resources or test properties <plugin> <groupid>org.codehaus.mojo</groupid> <artifactid>buildnumber-mavenplugin</artifactid> <executions>... </executions> <configuration> <format>{0,date,yyyy-mm-dd HH:mm:ss}</format> <items> <item>timestamp</item> </items> </configuration> </plugin> http://mojo.codehaus.org/buildnumber-maven-plugin
Part 5 Keep the build fast
Keep the build fast Ideally, zero-time build http://blog.carbonfive.com/2008/09/java/make-thethings-you-do-often-fast-and-easy The more often a task is performed, the more its optimization improves developer productivity save time for actual project work Run maven on the latest JDK benefit from JDK 1.6 fast startup times/optimizations
Eclipse compiler Faster than JDK's javac also provides more warnings (unused variables, generics misuse...) <plugin> <artifactid>maven-compiler-plugin</artifactid> <configuration> <compilerid>eclipse</compilerid> </configuration> <dependencies> <dependency> <groupid>org.codehaus.plexus</groupid> <artifactid>plexus-compiler-eclipse</artifactid> <version>1.5.2</version> </dependency> </dependencies> </plugin>
Unit test vs integration tests Run unit tests often must not take half an hour! or else developers will just skip them -Dmaven.test.skip=true Separate unit tests from integration tests unit tests in every project/module fast run at every build (within mvn install) integration and acceptance tests in dedicated module run after major changes, and/or on build servers
Remove useless build elements POM, plugin and dependency list keeps growing Periodically review the POM Remove unused dependencies copying them around means more slow disk accesses mvn dependency:analyze Remove unused plugins move them to optionally-activated profiles
Speed-up day-to-day tasks Define a default goal <defaultgoal>compile</defaultgoal> then just run mvn Use the right goal avoid a full mvn install if you just need a mvn test Define shell aliases for common tasks Use a CI server that reads and reuses mvn configuration such as hudson https://hudson.dev.java.net
Incrementally build large multimodule projects Reactor plugin http://maven.apache.org/plugins/maven-reactor-plugin/ manages dependencies and build order resume a build from the last failed module mvn reactor:resume build a project and all its dependencies mvn reactor:make build all modules which have an SVN status of changed mvn reactor:make-scm-changes
References Maven official site http://maven.apache.org Best online book Maven 2 The Definitive Guide http://books.sonatype.com/maven-book JavaWorld articles Introduction to maven2 POM http://www.javaworld.com/javaworld/jw-12-2005/jw-1205-maven.html http://www.javaworld.com/javaworld/jw-05-2006/jw-0529-maven.html
Thanks for your attention! Learn more at http://www.carlobonamico.com/blog http://juggenova.net presentations, demos, code samples Play with the samples http://juggenova.net/code-samples/ Contact me at carlo.bonamico@gmail.com Related reading: Continuous Integration with Hudson http://www.slideshare.net/carlo.bonamico/continuous-integration-with-hudson