Sunday, May 18, 2008

Accessing Hudson Variables with a Free-Style Project

Here is a great article on creating a manifest file containing hudson variables so that you can know exactly what build number and svn number built your artifact. However, in my case I wanted to create a properties file under my maven2 project under src/main/resources and let maven filtering take care of the rest. But for some reason it wouldn't work. After some further research, I eventually found out that free-style projects appear to not work the same as a maven2 project in hudson when trying to access hudson variables.

In summary, hudson variables work as expected when you create a maven2 project in hudson. With a free-style project you have to perform an extra step. Why, I don't know; I am sure there is a good reason. It's just too late to figure it out.

Here are the extra steps you can follow to create a properties file containing hudson values.

Update POM
In your projects POM or parent POM add the following properties at the bottom

<project>
....
<properties>
<build.number>${BUILD_NUMBER}</build.number>
<build.id>${BUILD_ID}</build.id>
<job.name>${JOB_NAME}</job.name>
<build.tag>${BUILD_TAG}</build.tag>
<executor.number>${EXECUTOR_NUMBER}</executor.number>
<workspace>${WORKSPACE}</workspace>
<hudson.url>${HUDSON_URL}</hudson.url>
<svn.revision>${SVN_REVISION}</svn.revision>
</properties>
</project>
Create a properties file
Create a application.properties file under your maven2 projects src/main/resources directory.

Now add this to it

build.number=${build.number}
build.id=${build.id}
job.name=${job.name}
build.tag=${build.tag}
executor.number=${executor.number}
workspace=${workspace}
hudson.url=${hudson.url}
svn.revision=${svn.revision}

Saturday, May 17, 2008

Groovy Sort List

I am posting a simple example on how to sort a list in groovy because the examples google knows about aren't what I was looking for. With some deep digging I was able to find a clue that eventually solved my problem.

It's real easy to sort a list of numbers

assert [1,2,3,4] == [3,4,2,1].sort()

Or even strings

assert ['Chad','James','Travis'] == ['James','Travis','Chad'].sort()

But this was my example

class Person {
String id
String name
}
def list = [new Person(id: '1', name: 'James'),new Person(id: '2', name: 'Travis'), new Person(id: '3', name: 'Chad')]

list.sort() returns James, Travis, Chad

The solution is ridiculously simple (not that I thought the previous sort would work; I have to be realistic; groovy can't do everything for me).

list.sort{it.name} will produce an order of Chad, James, Travis.

In the previous example note the use of the sort closure sort {} verses the sort() method.

Now I am not sure, off the top of my head and without a Groovy book handy, the simplest way to sort case insensitive.

assert ['a1','A1'] == ['A1,'a1'].sort{fancy closure}

Saturday, May 10, 2008

Finally OpenSolaris Installed

Finally, after 4 attempts, I got a half way decent install of Solaris. My previous attempts included installing Solaris Express Developer Edition on VMware Server 1.0.4 and VirtualBox 1.5. Both had major issues but I had the best luck with VMware Server, it just took like 15 minutes to boot and I couldn't install vmware tools. So at JavaOne 08 they announced http://www.opensolaris.com with the version 2008.05. So I thought I would give it a try and their install documentation seemed very thorough (see how to install on virtualbox). Unfortunately, installing this in virtualbox did not work (would't boot) and so I decided to give it one more shot on VMware Server and I guess I got lucky because it actually worked to my surprise. And it actually boots rather fast compared to my previous experience with solaris.

Since it uses GNOME it reminded me a lot of my ubuntu system. I was even able to successfully install vmware-tools which I got really excited about because I would have bet against this previously. Compiz is installed by default but I was unable to change the settings yet (it kept rebooting for some reason). Maybe it's because I haven't enable the nvida drivers yet; which was also a surprise that the nvida drivers where already installed.

Here are some features compared to Linux. I am not a file system guru but ZFS sounds interesting.

Anyways so far so good. I do miss sudo. I am now able to start working efficiently on providing hudson as a package in solaris. I am assuming that once I get done the below search will actually return a result (me <-- crossing my fingers).

Thursday, May 8, 2008

Why again am I not using JDK 1.6?

Why in the world am I still using jdk 1.5? It's almost 4 years old. Yesterday it just kind of hit me and I said to myself, "James, why not start using jdk 1.6 or java 6?". Is there anything technically preventing jdk 1.5 users from using jdk 1.6? Back in the day, weblogic 6.1 only worked with jdk 1.3 and when I wanted to start using jdk 1.4 it just wouldn't work. So for some reason I still had that same mindset.

So I started to do a little research and what I found was pleasantly surprising and I immediately downloaded the latest version of java 6 and started using it (verdict still out on that but so far so good). JBoss 4.2.1 seems to start just fine with java 6.

So what exactly did I find? First, straight from the java 6 home page is the answer to the question: Q: How is Java SE 6 different from the previous version (J2SE 5.0): what are the improved and updated areas, such as functionality, security, performance?

...the release delivers dramatic out-of-the-box benefits without any coding changes or even a re-compile necessary. Simply running existing Java applications on this latest release is all that is needed.
Now my interests are peaked. So how come I haven't heard this yet. Perhaps I was just content being able to upgrade from 1.4 to 1.5.

I think this article by Rick Ross on javalobby has some great points. Here are the ones that interested me:
  • Java 6 incorporates over 300 bug fixes
  • Java 6 features general performance improvements while preserving compatibility with older versions
  • In many cases you may find that your applications run as fast or faster under Java 6 as they would if you spent significant effort tuning heap, thread and garbage collection parameters under Java 5.
That last point hits me right at home since we recently went through "significant effort tuning heap, thread, and gc params."

So what about performance? This article is in an depth analysis of the performance improvements. The summary is it's faster.

So like mentioned above I downloaded java 6 update 6. Jboss 4.2.1 started just fine. Today I plan on building our EAR using maven 2.0.9 and deploying it to see if there are any issues. See the official compatibility page here. Specifically it states "Java SE 6 is upwards binary-compatible with J2SE 5.0 except for the incompatibilities listed below. Except for the noted incompatibilities, class files built with version 5.0 compilers will run correctly in JDK 6."

Thursday, May 1, 2008

Pimp my Linux: Maven2 Bash Completion

Inspired by this bash completion for ssh, I wanted to see what it would take to do something similar for maven2. Thanks to google it's already been done.

It's not perfect, but it's a start. For example, the choices are hard coded in the script. And when I tab after typing mvn assem it outputs mvn assembly\:assembly. Shouldn't be too hard to find that extra slash.

Here are some thoughts on how one could improve it. First, maybe it could be improved for at least the core plugins by searching the local repo in /m2/repository/org/apache/maven/plugins. Or searching the local repo for any pom that contains a packing value of maven-plugin (maven-plugin). Combine that with the help plugin to get the possible goals and all their parameters and one could probably create a pretty slick and useful bash completion for maven2.

For example, you can get everything you need for any plugin if you know the groupId and artifactid by running this:
mvn help:describe -DgroupId=org.apache.maven.plugins -DartifactId=maven-war-plugin -Dfull=true

I say all this, but I use a lot of alias's for my maven commands. Here are a few of my favorites:

alias mci='mvn clean install'

alias build='mvn clean install -Dmaven.test.skip=true -Dpmd.skip=true -Dcheckstyle.skip=true'

Using Maven War Overlays to extend Hudson

I just recently found out about one of the neatest features of the maven-war-plugin called WAR Overlays. Basically it provides a very simple way to merge multiple WARs together to create an Uber WAR. You simply add a WAR as a dependency in your POM verses adding a JAR, and the maven-war-plugin will take care of the rest. My team uses this ability to extend the JSPWiki WAR to add in our wiki pages. The result is an Uber WAR including the JSPWiki stuff and our wiki pages. Then when a new JSPWiki WAR is available we just update the dependency version in our POM.

So for an example, I am going to demonstrate extending my favorite CI tool Hudson since it's freaking awesome and is downloaded as a WAR. Don't try this at home since hudson already provides the ability to extend it using plugins (which also rocks by the way).

Create a Simple WAR Project
First, create a war project using maven-archetypes. Execute mvn archetype:generate and select #18. Run mvn clean install to ensure it builds correctly (I am using maven v2.0.9).

Install hudson into local repository
Next we need to be able to consume the hudson war in our pom and since I am unware of the hudson war being available on any external repository we are going to just install it manually into our local m2 repository.

  • Download the latest hudson war
  • Install hudson.war into your local repository using the mvn install plugin by running: mvn install:install-file -Dfile=hudson.war -DgroupId=hudson -DartifactId=hudson -Dversion=1.0 -Dpackaging=war
Consume the hudson.war in your pom
Open up your war's parent pom and add the hudson war as a dependency.
<dependency>
<groupId>hudson</groupId>
<artifactId>hudson</artifactId>
<version>1.0</version>
<type>war</type>
<scope>runtime</scope>
</dependency>
Next, since we want to run hudson in embedded mode without a container we need to add to the generated manifest file the Main class since I am too lazy to figure out how to include the original hudson manifest file (even though I am sure its possible). Include the following in your build section:
<build>
<finalName>mywar</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Main-Class>Main</Main-Class>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
Build and Run it
Now build the war again: mvn clean install. And your WAR should be merged with the hudson war. In fact for verification, your simple war contained an index.jsp under src/main/webapp and if you extract the war under target you will see your index.jsp.

Run: java -jar target/mywar.war
and go to: http://localhost:8080/index.jsp

If you are doing this on a serious level, you might want to look into the maven-cargo-plugins ability to create Uber wars.