Wednesday, June 27, 2007

Artifactory Can Help you Manage a Repository

I was browsing TSS and found this article. It's a good read for any seasoned Maven 2 developer, talking about repository theory and a piece of software called Artifactory. I like that Artifactory combines caching of external artifacts with a nice Web-UI where you can manage your repository. The article does a great job of explaining why and when to use Artifactory.

Artifactory looks like a real helpful piece of software. I'll stick to my dead simple repository setup for now, but I am going to give it a try real soon. The caching alone makes it worth using, as I have found in the past it speeds up Maven's execution time.

Monday, June 25, 2007

Profiles + Dependency Management

The problem:

You want to be able to easily switch between versions of dependencies in your project. This could be in the range of only one project dependency up to every dependency in you project.

The solution:

You can create profiles that each define a dependency management section. In each of these dependency management sections you can set the versions for dependencies in your project. Then you will invoke a profile to set the dependency (or dependencies) version(s) used in building, testing, releasing etc.

Now why would you want to do this? Well there are a set of situations where you need your project to be able to build and release in lieu of differing version requirements. You may be building a framework that should work with Spring 1.x and Spring 2.x, or maybe Servlet spec 2.4 and 1.x. Let's look at such an example to demonstrate this technique:

<profiles>
<profile>
<id>newspring</id>
<dependencyManagement>
<dependencies>
<dependency>
<groupdId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.1</version>
</dependency>
<dependencies>
</dependencyManagement>
</profile>
<profile>
<id>oldspring</id>
<dependencyManagement>
<dependencies>
<dependency>
<groupdId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>1.2.1</version>
</dependency>
<dependencies>
</dependencyManagement>
</profile>
</profiles>


In the above example you can see that you could specify the "newspring" profile to use Spring version 2.1, or the profile "oldspring" to use 1.2. You can apply other profile techniques such as default profiles here. Where can you define configuration such as the above? Well normally you would put it directly into your pom.xml. Doing so allows you you to leverage the parent child relationship! You can create profiles which contain different dependency versions in dependency management sections, and inherit them by many child projects. This allows child projects to easily specify which versions of certain technologies are used (I need to create a lengthy example of this in action!).

FYI, you likely will not use this technique in a simple Maven project, rather it will be used with some other advanced techniques.

Dependency Management, WTF?

The problem:

You want to standardize versions of a set of dependencies used in a group of project.

The solution:

A set of projects may use a given dependency. I know that I often use both Hibernate 3.x and Spring 2.x in my projects. It can make a lot of sense to use the same versions of dependencies across multiple projects. This may be especially important when you have a set of projects that are very closely related, maybe with dependencies to one another. Enter the dependency management function of the Maven pom. I put WTF in the title because thats what I thought when I discovered this feature for myself. It really is a well thought addition to the Maven platform.

So how do you do this? First you will want to put a dependency management section in a pom. Likely this is a parent pom which is inherited by many projects, otherwise what is the point? I MEAN DEPENDENCY MANAGEMENT IS MEANT FOR MANAGING DEPENDENCIES ACROSS MANY POMS. Sorry that was the main point you should take away from this session.

Here is what the dependency management section will look like:

<dependencyManagement>
<dependencies>
<dependency>
<groupdId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.1</version>
</dependency>
<dependencies>
</dependencyManagement>

So that will set the version of the shown spring artifact to 2.1. Now how will this make a difference? You will not include a version when adding this dependency in a project which has this dependency management section. You will simply add this dependency config:
<dependency>
<groupdId>org.springframework</groupId>
<artifactId>spring</artifactId>
</dependency>


It is pretty simple, Eh? Also note that when you want to upgrade to a new version of a dependency it is as simple as changing the version in the parent pom's dependency management section. Hows that for simple management of your dependencies?

Maven Plugin for Generating Eclipse projects (Maven + Eclipse Pt. 1)

The problem:

You want to use the ubiquitous IDE, Eclipse, with your Maven project.

The solution:

Just because you use Maven doesn't mean that you are going to jump through hoops to make it work with Eclipse; all you need to do is type "mvn eclipse:eclipse". This command will generate the .classpath and .project files that Eclipse needs so that it can understand your project.

Once you run this command in your project boot up Eclipse and click File -> import -> General -> Existing projects into workspace -> next, now use the enabled browse button to find the project's root directory. Once you do this click OK. You should see your project in the projects window. Make sure it is selected and press the "Finish" button.

Right now you probably see all sorts of errors. LOL. One last thing. You must create an Eclipse classpath variable that points to your local Maven repository. Click the following: "Window -> Preferences... -> Java -> Build Path -> Classpath Variables". You now shall click "new" button and create a variable with name "M2_REPO" and value being where your local Maven repo is found. Usually this is ${HOME_DIR}/.m2/repository. On my OS X machine this is "/Users/ottaway/.m2/repository". On my Windows machine it is "C:\Documents and Settings\rob\.m2\repository". Once you set this press the "OK" button.

Your projects dependencies should now be loaded. Note that if you add new dependencies to your project you will need to run the "mvn eclipse:eclipse" command again. This will regenerate the .classpath file that contains the dependencies.

Exclude Transitive Dependencies

The problem:

You have a dependency in your project, that brings with it other dependencies. Some of these you do not want added to your project.

The solution:

First off if you don't know, transitive dependencies are those which are depended on by dependencies in your project. If you have dependency A in your pom, and it depends on dependencies B and C, then B and C are referred to as transitive dependencies. If B relies on D then it will also be referred to as a transitive dependency. In this scenario dependencies A, B, C and D are added to your project.

What if you load a newer version of B? Now you have two versions of B in your project. This may cause you pain. Well worry not. You can easily exclude dependency B from your project. Just use this example, but plug in your dependency details and those of the transitive dependency to exclude:


<dependency>
<groupId>group-a</groupId>
<artifactId>A</artifactId>
<version>2.0</version>
<exclusions>
<exclusion>
<groupId>group-b</groupId>
<artifactId>B</artifactId>
</exclusion>
</exclusions>
</dependency>


There you go, thats all there is to it! Note that you likely will not have to do this all too often, but it's good to know what to do when you experience this problem.

Friday, June 15, 2007

Install Maven On Your Machine

The problem:

You need Maven installed on your machine:

The solution:

Go to maven.apache.org and you will find the download you want. I recommend you get the newest 2.x release of Maven. Download Maven. Once complete unzip it onto your filesystem.

You now will want to create a MVN_HOME system variable to point to your installation (where you unzipped Maven). In Linux/BSD you will probably be adding this variable in your .bash_profile or .profile file in your home directory. Example:

export MVN_HOME=/usr/local/maven2.6
PATH=$PATH:$MVN_HOME/bin

On Windows you can add these vars through the control panel -> system -> advanced (tab) -> Environment variables (button). This is where you enter system variables for Windows. You probably only want to use Maven for your account, so create a new var in the top window. Name it MVN_HOME and set it's value to the location of Maven. Next, if you don't have a Path var in the user variables create one, set it's value to %MVN_HOME%/bin. (Windows tip, press windows-key + pause to bring up the system props).

Adding the Maven bin to your system path allows you to invoke via the command line anywhere . When you are done with the previous type 'mvn' and you should get an error saying you must specify a goal. This means you are ready to go!

Do Not Test!!!

The problem:

You would like to skip unit testing when using Maven.

The solution:

You can very easily tell Surefire, the plugin in Maven that handles testing, to not run tests. All you need to do is specify the system property 'maven.test.skip. Here is an example:
mvn -Dmaven.test.skip clean package

The above command will clean and package your project and will do so without running your tests. This is a very useful command in Maven. It comes in especially handy when trying to build someone else's project that contains non-portable test that run by default. These may keep you from building their project. Use this command to build the project and maybe install or deploy it.

Thursday, June 14, 2007

Using Snapshots for Rapid Development

The problem:

You are working on a project with a number of other related sub-projects. You would like to release snapshots of your project's artifact (maybe a war or jar) for use in these other projects. This will help those other projects move along while your project is being developed.

The solution:

You can configure your project to produce a snapshot artifact, just add '-SNAPSHOT' to the end of your project's version number in it's pom. Now when you package the project you will get a artifact labeled with SNAPSHOT. You now can take advantage of releasing the snapshot for other projects to use. You should configure a 'snapshotRepository' section in your 'distributionManagement' section of your pom. Here is an example of how this works:

<?xml version="1.0" encoding="UTF-8"?>
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>test_snaps</groupId>
<artifactId>test_snaps</artifactId>
<packaging>jar</packaging>
<version>0.0.1-SNAPSHOT</version>

<distributionManagement>
<snapshotRepository>
<id>test_snapshot_repo</id>
<uniqueVersion>true</uniqueVersion>
<name>test_snapshot_repo</name>
<url>file:/test_snapshot_repo</url>
</snapshotRepository>
</distributionManagement>

</project>

With the above pom you could type 'mvn deploy' and a unique jar will get deployed. You can check this by checking /test_snapshot_repo/test_snaps/test_snaps/0.0.1-SNAPSHOT/. Run the 'mvn deploy' command a few times and you will see a bunch of these begin to build up.

Specifying your Project's Artifact

The problem:

You want to specify what the output of your Maven project will be.

The solution:

You will set the the artifact type in the section called 'packaging'. This XML element normally exists directly under the root 'project' XML element in your pom. For most maven projects this value will be either jar or war. What you put here will affect what gets created when you type 'mvn package'. There are other plugins that will allow you to use other types of packaging. One is the 'maven-plugin' packaging type, which is used in the project pom for a maven plugin.

You can find more about plugins (and their packaging) here.

Install a Project Artifact

The problem:

Your project creates a war or jar that you would like to have in your local repository so that another project can include it as a dependency.

The solution:

The maven install command will get the job done. You can run this by typing 'mvn install'. When you do this your project gets built and packaged like normal, and then the jar, war, or whatever artifact your project builds gets put into your local repository. Once in your local repository your artifact becomes available to other projects being built on your machine. To get the artifact in other projects include it's information in a 'dependency' element in your pom.

Pom Inheritance

The problem:

You have a pom that contains configuration which you could reuse in another pom.

The solution:

You can inherit the configuration of a parent pom for use as the base of a new pom. This technique has many useful applications. One very important use is keeping configuration in one place. If you have a multitude of projects that inherit from one pom, then they will share some configuration. You can now change the configuration in the parent pom and all projects inheriting will get the changes. Think how much easier that makes changing a property that is inherited by 10, 15, maybe more projects.

So you are wondering how can I do such a great thing? It's easy just insert the parents pom's artifact id, group id, and version in your pom. You will put this information in the parent section of your pom. Here is what it will look like:
<parent>
<artifactId>Parent pom artifact id</artifactId>
<groupId>Parent pom group id</groupId>
<version>Parent pom's version</version>
</parent>
Thats all there is too it. Once you put that into your pom you inherit that pom's configuration. One last thing the parent pom must be in a reachable repository location.

Sunday, June 10, 2007

Integration Testing in your Maven Application

The problem:

You want to create integration tests in your Maven project. You don't want these tests to run every time you compile.

The solution:

Create some profiles in your pom.xml. You can create a profile that by default excludes running any test that starts or ends with the words 'IntegrationTest'. You can then include a profile that will run these tests when activated.

Here is an example you can use in your pom:
 
<!-- Use this profile to allow integration tests to run -->
<profiles>
<profile>
<id>no_integration_testing</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
<exclude>**/*IntegrationTest.java</exclude>
<exclude>**/IntegrationTest*.java</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>integration_testing</id>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>**/*IntegrationTest.java</include>
<include>**/IntegrationTest*.java</include>
</includes>
<excludes>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
If you use this configuration, by default a test called "LegacySystemIntegrationTest" would not get run by surefire when you compile. If you issue the command
"mvn -P integration_testing compile"
then this integration test (and any others named in this fashion) will get run. Note there are some gotchas when using this strategy:
  1. If you include the profiles above in a pom that gets inherited, the pom which inherits may override the default excludes. If the sub-pom does override excludes the entries from the profile go away and tests with "IntegrationTest" in them will get run by Surefire.
  2. Any integration tests that do not start or end with "IntegrationTest" will get run. You are expected to follow a convention here. You could add more excludes and incluedes to my example above in this case though.
My advice is that you use this configuration, and by convention always name integration tests with "IntegrationTest" in them. It saves headaches and normalizes development across all users.

Tuesday, June 5, 2007

Getting Groovy with Maven

The problem:

You would like to integrate Groovy scripts into your Maven application.

The solution:

Maven has a plug-in for groovy! You should put your scripts into "src/main/groovy", and test scripts into "src/test/groovy". To make groovy compile add this plug-in definition to your pom:


<build>
...
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>groovy-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
...
</build>


and then this dependency:


<dependency>
<groupId>groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>1.0-jsr-04</version>
</dependency>


Thats all there is to it! Now go script up a storm.

Monday, June 4, 2007

Output Your Effective Pom to disk

The problem:

You would like to have a copy of the effective pom file used in your project. The effective pom is your current projects pom merged with any inherited poms.

The solution:

If you have read the post "Seeing the Big Picture with Inherited Poms" you know that by type "mvn help:effective-pom" a copy of the effective pom will be outputted to your screen. This is nice but what if you want a copy of this on file? Maybe you would like to attach it to an email, or use it to cut and paste together a new file. Well Maven has this one covered. Use the following command
mvn -Doutput=<filename> help:effective-pom
Where <filename> is the name of the file you would like the effective pom written to.

Profiles in Maven

The problem:

You would like to set up Maven to run in one or more configurations that you have defined.

The solution:

Maven has a profile mechanism that naturally fits this type of thing. You can create any number of profiles that each contain settings that can override other Maven settings. Here is an example of some profiles:


<profiles>
<!-- profile for java 5 -->
<profile>
<id>java5</id>
<activation>
<property>
<name>jdk</name>
<value>5</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<!-- profile for java 6 -->
<profile>
<id>java6</id>
<activation>
<property>
<name>jdk</name>
<value>6</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>


Name this profiles.xml and put it into your projects folder next to the pom.xml. You may have noticed the activation elements in the file. These are what trigger the profile to be active. You can trigger these by defining a system property with the value given in the activation value element. So you use Java 6 compilation you would do "mvn -Djdk=6 ..." where ... is the Maven commands to execute.

Note that more than one profile can be active at once. Since profiles can contain the same types of configuration there can be clashes. If two profiles clash the last to be activated will override those activated earlier.

Saturday, June 2, 2007

Seeing the Big Picture with Inherited Poms

The problem:

You have a child pom that inherits from a parent pom, which may inherit from another and then some. You are not sure exactly what all is going on in the child pom.

The solution:

When you use inheritance in a pom it makes life easier. You don't need to know about all the stuff that was defined in the higher level POM, it just works. Then there are times when you get into some fancy Maven configuration and you really need to troubleshoot a problem that could be inheritance related. This one is dirt simple:

mvn help:effective-pom

By typing this on the command line you can get the full configuration that is being used in your project. This is done by merging all the parent configuration with your projects configuration, and then displaying it in the terminal.

Per user server authentication

The problem:

Each user has their own username and password for network machines that are accessed by Maven when deploying artifacts, websites, or maybe some other files. You wouldn't want this type of information in your project pom.xml so what do you do?

The solution:

The settings.xml file in your {HOME_DIR}/.m2* folder is your ticket. You can define servers and for each one define your username and password. Note that each server entry must have an id that matches with the one defined in the distribution management or other part of your pom.xml. Here is the example:
<settings>
<servers>
<server>
<id>hood</id>
<username>ottaway</username>
<password>Cm0nkeyz</password>
<privateKey>/Users/ottaway/.ssh/known_hosts</privateKey>
</server>
</servers>
</settings>
You should fill in the username, password and path to keys. On my Mac the path to ssh keys is /Users/ottaway/.ssh/known_hosts. You will need to do a little investigation on this if using a Windows machine. Please let me know if you figure it out.

* This is /Users/{username} on Macs, Documents and Settings/{username} on Windows or /home/{username} on most linux machines.

Concepts of Maven pt. 1

Project structure...

You should never have to change the basic Maven project structure. Believe me, I have worked with Spring 1.x/2.x, Hibernate 2.x/3.x, DWR, Struts, Web MVC (Spring), Portlets, XFire web services, etc. etc. Pretty much any J2EE or Java technology out there I have used in one of my Maven projects.

Why am I stating the above? Because the #1 thing I hear about Maven, and why some person does not use it, is that Java framework X does not work with Maven. This is erroneous. I wish people could be more honest and just state "Hey I don't know". Instead they attack the unknown. Lame. Linking back to structure, often I hear these complaints and other offer solutions that include overriding the default Maven project structure.

If you override the defaults you are destroying the simplicity of the Maven project. By setting up defaults for things in Maven, it provides users the security that they can open any Maven project and quickly understand exactly it's structure. I know that files in src/main/resources will be loaded right into the top of the class path hierarchy once compiled. So any Spring, Hibernate, logging, or other configuration files will be found here. Likewise src/test/resources will be where testing resources go, such as testing Hibernate configuration, testing logging configuration and so on. I know that when creating a web application the basic J2EE web application structure will be contained in the project, and found at src/main/webapp. So WEB-INF will be at src/main/webapp/WEB-INF. I know, enough already. I'm beating a dead horse, you all got the point... Ok just wanted to emphasize why you don't change the structure.

If you have a framework you want to work with in Maven, and can't figure it out after reading this blog and other resources out there then email me, or post a comment to this blog. Please I beg of you, Maven does not deserve a bad rap!!!

Learn it...

Maven is not so simple to just sit down and start using. I say this in direct comparison to Ant, or make. Ant is really easy to get going for a project with very little work. I would say Maven is too, but only for simple compiling and packaging. Get into testing and know things get a little tougher. There are a lot of options, a lot of plug-ins. I recommend two things.
  1. First read this article off of the Maven site. It wasn't always there, and the first time I read it a lot of things clicked in my head. It may not really make full sense until you use Maven for a bit. It talks of the build life cycle, which is the backbone of Maven.
  2. Get the free book "Better Builds with Maven". A company called Mergere put this out. It is really good. Here is a link, if it is dead use google!
Don't be afraid to work through the Maven site. You should spend at least 3-4 hours just investigating it before you really start up any projects. And of course read this site!

Please understand a few things...

Maven is a system. That means it is a bit complex. But... know this. You should have a super experienced maven pro at your place, who can do ALL the heavy lifting so that developers can very quickly develop. It's the same paradigm as a sys-admin setting up all the test environments so that the developer can come in and do their job.

In Maven there are a few things involved in the "sys-admin" type work.
  1. First and foremost is setting up the network repositories being used by developers. This may simply be a single location on a machine, but could be multiple locations on multiple machines. It really depends on your companies circumstances. You may also want to set up a proxying software for one or more repos. This makes it so that developers only need access your local network repo(s), which can go to repos outside the network, get a dependency and cache it local. This has benefits in speeding up download time for dependencies. I highly recommend you do this if you are serious about Maven.
  2. POM inheritance model. This is maybe the most powerful feature of Maven. You can specify a lot of things in a POM, Java compiler version, website location, reports to generate (JUnit health, PMD, JIRA..), how to configure Jetty to run your web application (yes type mvn jetty:run and bam you have your app running!!!). These and more can be specified in a POM, and that POM can then be added as parent to another POM. The child POM then inherits all the configuration from the parent, overriding where collisions occur. As the "sys-admin" of Maven you can configure many things so that users will never have to worry about them. Look for examples of this here, in my blog.
  3. Archetypes are great. They really are pretty easy to develop once you get the hang. The problem is that there are not a lot of great archetypes available and documented. This will change eventually. To give you the idea of an archetype think of a template but more complex. An archetype allows you to generate a project using a simple 'mvn' command. This could create a XFire, Hibernate, JMS or some other type of project. By the "sys-admin" making available and documenting archetypes projects can get done quicker
    . I have personally created and used them for XFire SOAP services and Hibernate 3.x ORM projects, and you can crank them out using archetypes. If you have used Ruby on Rails think of these as generators. You can create any number of them yourself and put them in the network repo where other developers can use them.
So, if you have one person who can provide the above duties then the rest of your developers should have a pretty easy time working with Maven. These developers will still need to learn about Maven, therefore reading the f**king manual ;)

Maven 2 + Hibernate + HSQLDB (project contained integration testing for Hibernate)

The problem:

You must check your Hibernate objects against a database for testing purposes. This database is somewhere on your network, and accessible to many of your fellow co-workers. You cannot expect anything to stay static in this db, which means eventually your tests will fail.

A solution:

Maven can make projects very portable. Hibernate makes working with persistent objects simple. HSQLDB is a Java database that you can run embeded in other programs.

A problem with using Hibernate is it can take away some of the portability of your project. This happens because you must provide a database for making your objects persistent. In doing so your test configuration files will be spec'd to a single database. What happens when someone runs the project's tests and does not have access to the test database? The tests will fail :( We want to have unit tests be used for all our hibernate objects. It is especially important to thoroughly test them, as they will be a central part of your projects functioning properly (especially web projects!).

Luckily Maven makes it easy to use one database for testing, and another for production. This is where HSQLDB can come in handy. You can create a hibernate config just for testing which connects to an in memory HSQL database. You will need the proper files in src/test/resources folder of your Maven 2 project. The files include the test version of your hibernate config file. I put the hibernate mapping files into folders that mirror the packaging of the POJO object classes. When you run 'mvn package' the .hbm files will be placed in the same folder as the POJO class they belong to. Here is an example of my Maven 2 project's structure:

/project
pom.xml
...other files
/src
/main
/java
/some
/package
Foo.java
/resources
hibernate.cfg.xml
/some
/package
Foo.hbm.xml
/test
/java
/some
/testpackage
TestFoo.java
/resources
hibernate.cfg.xm

So you can see that there are a hibernate configuration file for the build and the test phase. Now in the test hibernate.cfg.xml file you will need to have the following properties set:


<!-- Database connection settings -->
<!-- HSQL DB -->
<property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
<property name="connection.url">jdbc:hsqldb:mem:aname</property>
<property name="connection.username">sa</property>
<property name="connection.password"></property>

and...

<property name="dialect">org.hibernate.dialect.HSQLDialect</property>
<mapping resource="some/package/Foo.hbm.xml" />


These entries should have you now set up to use a in memory database for all your testing with hibernate. But before this will work you need to do one more thing.

Set up you Maven 2 project so that HSQLDB is a dependency. Added this dependency section to your project:

<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.1</version>
</dependency>

Note that you will not need to make any specific JDBC driver available. The HSQLDB dependency contains the proper driver!

Using this recipe you will be able to make very portable Maven/Hibernate projects. Users any place in the world will be able to check out your project and test it immediately. If they would like to test using their own database it is not hard for them to overwrite what is in the src/test/hibernate.cfg.xml file.

About this blog

I have been blogging for about a year or so. I sometimes put entries about programming into my blog. One or more have been about Maven. I use Maven a lot at work with Java projects I work on. I felt I should create a blog to hold all the nice little cookbook style recipes I have whipped up using Maven. Enjoy!!!