Thursday, March 10, 2011

ZIP Files - Ant and Maven

How hard it might be to ZIP a bunch of files you think right? Judge for yourself. Like in my previous post of getting the timestamp, I needed to ZIP all the source artifacts to upload to a server.

I could do this in one line in Ant. Yes, literally one line.


Now comes the fun part. Doing the same with Maven. Started browsing the Maven site to see what needs to be done to achieve the same. Sounds easy though, but the XML configured for such a fairly trivial task was not a 1 liner. Several lines to get this to work.


Not sure how many more things I will uncover using Maven. I would have written everything in Ant and asked the client to use the Ant plug-in for Maven, but that is not an option I have.

I am glad I am learning so many things about Maven. By the time I finish writing all the plug-ins for Maven, I am quite confident I will be able to say I am a Maven GURU. Hope that day comes soon.

Wednesday, March 9, 2011

Hudson or Jenkins

I have been using Hudson( now called Jenkins) from early 2008, i.e. almost 3 years. Also, if you have been reading my blogs, you already know I am a huge fan of Hudson.

I had been following what's happening with Hudson and Jenkins closely. Every time I do a presentation at client sites, I get frequently asked about which way I am going. Like "Have you switched to Jenkins, why are you still using Hudson"? What are your thoughts about both of them?

Most of our clients which are big financial institutions are still using Hudson. So, we will have to support Hudson as long as our clients are using. Most of them had no inclination to switch to Jenkins either. They didn't have any opinion when I asked about the switch.

So, for the time being we are using Hudson. However, I did download Jenkins, renamed it to hudson.war and everything worked like a charm. As expected.

So, what are you using? Have you made the switch yet to Jenkins? If yes, may I ask why?

Tuesday, March 8, 2011

Getting Timestamp in Ant (trivial) and Maven (nontrivial)

I have been working on custom plug-ins for Ant and Maven to upload artifacts to a server. These are source files, the binaries and anything required for scanning using a static code analysis tool for security. Having used Ant for more than a decade now getting the time stamp to keep track of the uploads and also the log files was done in a few minutes.

So, it is trivial getting a timestamp from within my build.xml file. Attached is the sample for doing the same.


No surprises, and everything works like a charm.

Now comes the tough part. Getting the timestamp in Maven. After writing several plug-ins for Hudson and Sonar, I was thinking I have some good knowledge about Maven. I was completely wrong. I have been struggling getting the time stamp plug-in to work with Maven.

So, here are the steps I followed when I saw there was a "Build Number Maven Plug-in".

I added the plugin details to my pom.xml file. Attached are the details:

As soon as I ran this, I got an exception as shown below:

artifact org.codehaus.mojo:buildnumber-maven-plugin: checking for updates from central
[WARNING] repository metadata for: 'artifact org.codehaus.mojo:buildnumber-maven-plugin' could not be retrieved from repository: central due to an error: Error transferring file: Connection timed out: connect
Repository 'central' will be blacklisted
------------------------------------------------------------------------
[ERROR]BUILD ERROR
------------------------------------------------------------------------
The plugin 'org.codehaus.mojo:buildnumber-maven-plugin' does not exist or no valid version could be found

Next, I decided to install the plug-in manually on my local repository. So, here I followed the following steps:

1. Downloaded the jar from http://mirrors.ibiblio.org/pub/mirrors/maven2/org/codehaus/mojo/buildnumber-maven-plugin/1.0-beta-4/buildnumber-maven-plugin-1.0-beta-4.jar

2. Installed it locally in my Maven repository as such:
mvn install:install-file -Dfile=buildnumber-maven-plugin-1.0-beta-4.jar \
-DgroupId=org.codehaus.mojo \
-DartifactId=buildnumber-maven-plugin \
-Dversion=1.0-beta-4 \
-Dpackaging=jar

The timestamp was created at this point, and now the plugin complains about the scm url being null.


------------------------------------------------------------------------
[buildnumber:create]
Storing buildNumber: 20110308095006 at timestamp: 1299595806804
------------------------------------------------------------------------
[ERROR]FATAL ERROR
------------------------------------------------------------------------
The scm url cannot be null.
------------------------------------------------------------------------
Trace
java.lang.NullPointerException: The scm url cannot be null.
at org.apache.maven.scm.manager.AbstractScmManager.makeScmRepository(AbstractScmManager.java:181)
at org.codehaus.mojo.build.CreateMojo.getScmRepository(CreateMojo.java:722)
at org.codehaus.mojo.build.CreateMojo.getScmBranch(CreateMojo.java:593)
at org.codehaus.mojo.build.CreateMojo.execute(CreateMojo.java:452)
at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:490)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:694)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalWithLifecycle(DefaultLifecycleExecutor.java:556)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(DefaultLifecycleExecutor.java:535)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.java:387)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:348)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:180)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:328)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:138)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:362)
at org.apache.maven.cli.compat.CompatibleMain.main(CompatibleMain.java:60)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.classworlds.Launcher.launchEnhanced(Launcher.java:315)
at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
at org.codehaus.classworlds.Launcher.main(Launcher.java:375)
------------------------------------------------------------------------
Total time: 2 seconds
Finished at: Tue Mar 08 09:50:07 EST 2011
Final Memory: 24M/224M
------------------------------------------------------------------------

I searched the FAQ section of this plugin at http://mojo.codehaus.org/buildnumber-maven-plugin/faq.html and it says to include the
revisionOnScmFailure 
which like you can see I have included.

At this point, I just gave up using this plug-in.

Have you used this plug-in and have a work around for this problem? Please share your thoughts. Is there anything else easier I can use to get the time stamp?

Update: After several tries using many other plug-ins including the one for Groovy, I found a workaround for some other bug at the following location http://jira.codehaus.org/browse/MRESOURCES-99, and I was able to successfully get the time stamp I need. Huh, I need my 3 hours back Maven......

Wednesday, March 2, 2011

RESTEasy - Connection Release Problems

If you are using RESTEasy client framework, and returning a Response from your service method, you will explicitly need to release the connection.

Here is the stack trace you will see, if the connection isn't released.

Exception in thread "main" java.lang.RuntimeException: java.lang.IllegalStateException: Invalid use of SingleClientConnManager: connection still allocated.
Make sure to release the connection before allocating another one.
at org.jboss.resteasy.client.core.ClientInvoker.invoke(ClientInvoker.java:101)
at org.jboss.resteasy.client.core.ClientProxy.invoke(ClientProxy.java:72)
at $Proxy25.updateSubmission(Unknown Source)
at meera.rest.main.MYRestWorkflow.main(MYRestWorkflow.java:61)
Caused by: java.lang.IllegalStateException: Invalid use of SingleClientConnManager: connection still allocated.
Make sure to release the connection before allocating another one.
at org.apache.http.impl.conn.SingleClientConnManager.getConnection(SingleClientConnManager.java:199)
at org.apache.http.impl.conn.SingleClientConnManager$1.getConnection(SingleClientConnManager.java:173)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:390)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:641)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:576)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:554)
at org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor.execute(ApacheHttpClient4Executor.java:86)
at org.jboss.resteasy.core.interception.ClientExecutionContextImpl.proceed(ClientExecutionContextImpl.java:39)
at org.jboss.resteasy.plugins.interceptors.encoding.AcceptEncodingGZIPInterceptor.execute(AcceptEncodingGZIPInterceptor.java:40)
at org.jboss.resteasy.core.interception.ClientExecutionContextImpl.proceed(ClientExecutionContextImpl.java:45)
at org.jboss.resteasy.client.ClientRequest.execute(ClientRequest.java:449)
at org.jboss.resteasy.client.ClientRequest.httpMethod(ClientRequest.java:679)
at org.jboss.resteasy.client.core.ClientInvoker.invoke(ClientInvoker.java:97)
... 3 more
------------------------------------------------------------------------
[ERROR]BUILD ERROR
------------------------------------------------------------------------

So, in order to fix this issue, RESTEasy has a method for releasing the connections which can be done using the following code:
MyResource resource = MyProxyFactory.create(MyResource.class, "resourcePath");
ClientResponse response = (ClientResponse) resource.create();
//Any REST Resource which returns a ClientResponse, has to call releaseConnection to release all the connections back
//to the connection pool
response.releaseConnection();