Enterprise Java Development Made Easier with Vagrant, Maven, and Chef

Languages in the Java-verse have a really cool artifact management system: maven. This can be handy for Software teams because you can use a local repository for vagrant and a maven server (such as artifactory) for production. This trick only works in a unix environment (OS X, Linux, and cygwin) though you can make a Smart Vagrantfile deal with a windows environment pretty easily.

The Code

In Chef:

# Builds a URL for a maven artifact
def getMavenArtifact(group,artifactId,type,version)
  group=group.gsub(".","/")
  return node[:myorg][:repository]+"/"+group+"/"+artifact+"/"+version+"/"+artifactId+"-"+version+"."+type
end

# Now somewhere in your default.rb:
default[:myorg][:repository]="https://production.com/maven"
default[:myorg][:someWarOrSomethingSrc]=getMavenArtifact("com.myorg.myproject","mysweetwebapp","war","14")

In Vagrant:

…
  config.vm.synced_folder "~/.m2/repository", "/repository"
…
  chef.json = {
    "myorg" => {
      "repository" => "file:///repository"
    }
  }
…

Then in java, just do the normal stuff you would expect with Maven.

In general, this only works with Chef 11.6 or better since until then, url’s that were file:// were not well supported. In some cases, you may need to fix them with a little hack such as the following:

default[:myorg][:someOtherWarThatsFileSentitive]=getMavenArtifact("com.myorg.myproject","mysweetwebapp","war","14").gsub("file://","")

The Point

So what’s the point? Well, as a java developer, now all you have to do is your normal mvn clean install to prepare your vagrant box(s) and then vagrant provision to have a working copy that is identical to production. In enterprise integration, this is huge!

A smart chef recipe might even be able to go into “development mode” which would symlink link the war into tomcat/wherever so that a mvn clean install can trigger a redeploy of the war.

Next Step

Another neat trick you can do is keep your actual artifacts in maven (such as test databases). All you’ll need is a module which specifies the artifacts as dependencies to pull them into your repository and you’re in business. This has a nice feel to it if your team is using git, because you’ll be able to hook up and download a local copy of all of your artifacts for use when connectivity is limited.