Wednesday, July 28, 2010

Fixing Corrupt Metadata in Artifactory (and my thought process behind it)

Background:
At work, I was recently introduced to the maven archetype plugin. I used it to generate a sample project containing generated client code that interacts with our framework. After working on it for a while and deploying it (successfully) to Artifactory (version 2.0.1), I was excited to show it off to my colleagues. Right around that time, we decided to upgrade the version of Artifactory to 2.2.4. The steps we followed were: Use the web console on the older version to run a Full System Export, Download the latest version to another location, Start up the new version, Run the System Import on the new version with the imported file. Everything seemed to run fine, until a guy tried my code and it failed!

Error:
My code invoked the generate goal using the maven-archetype-plugin. And this is the error that it spewed:

mvn -e archetype:generate -DgroupId=test.sonali.parikh -DartifactId=1.0 -Dversion= -DarchetypeGroupId=aero.sonail.parikh -DarchetypeArtifactId=sonali-sample-project-archetype -DarchetypeVersion=1.0
+ Error stacktraces are turned on.
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'archetype'.
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Required goal not found: archetype:generate in org.apache.maven.plugins:maven-archetype-plugin:1.0-alpha-7
[INFO] ------------------------------------------------------------------------
[INFO] Trace
org.apache.maven.BuildFailureException: Required goal not found: archetype:generate in org.apache.maven.plugins:maven-archetypeplugin:1.0-alpha-7
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.getMojoDescriptor(DefaultLifecycleExecutor.java:1558)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.segmentTaskListByAggregationNeeds(DefaultLifecycleExecutor.java:405)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:137)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:336)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:129)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:287)
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)


Analysis:
Looking at the stack trace, this is valid error IF I was using version 1.0-alpha-7 and NOT 2.0-* of this maven plugin artifact. The 1.0* version does not have support for the generate goal, since it was only introduced in the 2.0 releases.

But, since I didn't specify the version of the plugin to be used, the Artifactory server should serve me the latest and greatest version. So, I should have been pulling down the latest 2.0* version from the remote artifactory server (I check, our Artifactory does serve up the 2.0-alpha-4 version). OK so, something's wrong with the process used by Artifactory to maintain its versions.

I browsed through my local m2 repository, and discovered this file maven-metadata-central.xml . This file is downloaded to the local file system as part of the maven-local-client-talking-to-the-remote-repository. It basically looks like this:
...
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-archetype-plugin</artifactId>
<version>2.0-alpha-4</version>
<versioning>
<latest>1.0-alpha-7</latest>
<release>1.0-alpha-7</release>
<versions>
<version>2.0-alpha-4</version>
<version>1.0-alpha-7</version>
<version>2.0-alpha-3</version>
</versions>
<lastUpdated>20100723072443</lastUpdated>
</versioning>
</metadata>
...

This file is not quite correct - the value of the latest tag should have read 2.0-alpha-4.

And this was indeed the bug - when I manually hacked this file in my local repo (location: C:\.m2\repository\org\apache\maven\plugins\maven-archetype-plugin\maven-metadata-central.xml) to contain the correct version, and downloaded the 2.0-alpha-4 jars and pom to my local repo, the maven command worked wonders (my code of course). So somehow the metadata was incorrect or corrupt and had to be re-generated for this artifact.

Cause:
The metadata (served up by the remote Artifactory server to a local maven client) getting corrupt/wrong might have been a by-product of the full system export, which was one the steps involved in upgrading artifactory to 2.2.4. This is sort of a known bug as of April 2010 according to this jira ticket - they say the patch fixed it, but I haven't tested the patch yet.

(My Hacky) Solution:
I didn't want to patch it just yet, so I decided to delete the 2.0-alpha-4 jar and pom from the Artifactory server repositories and re-deploy them. This workaround made the regenerate-metadata-process actually work, and the latest version was correctly downloaded on my local box!
My colleague also tested another workaround - While upgrading to 2.2.4, check the "Exclude Metadata" option while doing the full system export. That helps too!

So Why Am I Blogging About This:
Well, I spent quite some time wondering my code didn't work and why the generate goal was suddenly not a valid goal! So if anyone spends more than an hour, trying to figure out weird latest-versions of artifacts, just try and regenerate the metadata.