Maven 2.2.1 Released


August 11, 2009 By John Casey

I’m proud to announce the release of Apache Maven 2.2.1.

This release aims to fix some critical regressions introduced in Maven 2.2.0, along with some long-standing issues related to custom lifecycle configurations.

Addressing Regressions in the HTTP Wagon

Beginning in Maven 2.2.0, the default implementation of the HTTP Wagon was switched from the old Sun- / HttpURLConnection-based wagon to one that wraps HttpClient. This seemed to have several advantages, not least of which was giving the user more access to fine-grained configuration options and moving to a better-documented core API for Maven’s most-used wagon. However, we soon realized that these improvements came with a hefty price tag.

One important downside to using HttpClient is that it doesn’t support NTLM version 2 authentication without some sort of GPL patch or add-on. Since Maven’s Apache license is incompatible with GPL, Maven 2.2.0 was effectively broken for users with NTLMv2 proxies. Making matters worse was the fact that the HttpClient-based wagon uses one of a few very simplistic strategies for authentication: either fully preemptive, or challenge-per-request. Sun’s implementation seems to cache the result of the first authentication challenge, and use this as a basis for preemptive authentication on subsequent requests. The problem with the approach in the HttpClient wagon is that you have to choose the lesser of two evils:

  1. Spray your sensitive authentication information around liberally, regardless of whether the server actually requires it. This constitutes a potential security hole.
  2. Send all uploaded files twice; once unauthenticated, and then again with credentials, in response to the authentication challenge.

To prevent introducing security flaws, we turned off preemptive authentication by default. However, this left us with option #2 above, which has the serious side effect of doubling the data seen by the checksum observer, thereby corrupting the checksum itself. It also caused widespread network timeouts as users on relatively slow connections attempted to upload large files multiple times during deployment.

Maven 2.2.1 addresses the above issues in the simplest way possible, to avoid any delay in providing a workaround to users: it reinstates the Sun- / HttpURLConnection-based HTTP wagon implementation as the default for HTTP/HTTPS transfers. This has the advantage of delivering a workable solution to users while buying the Maven development team a little breathing room to address the serious issues in the HttpClient-driven wagon implementation. However, we understand under just the right circumstances it may still make more sense to use the HttpClient-based wagon. So, starting in Maven 2.2.1, you have the option to specify an alternative wagon “provider” for any given protocol. Also, the two built-in wagons that implement the HTTP protocol have been aliased with their provider names included, allowing you to re-enable the HttpClient wagon using the following:

  mvn -Dmaven.wagon.provider.http=httpclient clean deploy

The result of using the httpclient provider is that Maven 2.2.1 will actually look for a Wagon defined with the Plexus role-hint: http-httpclient. In addition, you have the option of specifying the provider on a per-server basis in the settings.xml:

  <settings>
    <servers>
      <server>
        <id>my-repo</id>
        <configuration>
          <wagonProvider>httpclient</wagonProvider>
        </configuration>
      </server>
    </servers>
  </settings>

Using this new provider feature, it’s even possible to create your own wagon and load it via a build extension. In order to take advantage of the new wagon-provider feature, you’d need to create a component definition that looks something like this:

  <component>
    <role>org.apache.maven.wagon.Wagon</role>
    <role-hint>http-myprovider</role-hint>
    <implementation>com.foo.wagon.http.MyHttpWagon</implementation>
    [...]
  </component>

Or, if you’re using the Plexus Maven Plugin, your class-level javadoc might look like this:

  /**
   * @plexus.component role="org.apache.maven.Wagon" role-hint="http-myprovider"
   */
  public class MyHttpWagon implements Wagon
  {
      ...
  }

Fixing Custom Lifecycle Mappings

Ever since the 2.0 release, Maven’s support for custom lifecycle mappings and artifact handlers has been spotty at best, with a few key bugs making life unnecessarily difficult for users who wanted to define their own build process to create custom artifact types. These key bugs included:

  1. Custom ArtifactHandler components provided via build extension weren’t used by the main project artifact. (MNG-4238)

    This means that no matter how you defined the relationship between packaging, type, and artifact extension in your custom ArtifactHandler, the project build would always use Maven’s on-the-fly default ArtifactHandler for the main artifact. The result was that a project with packaging my-plugin would have its main artifact installed as a file called project-1.0.my-plugin in the Maven repository.

  2. Two or more plugins with the extensions flag enabled would see their extension component definitions collide, and only the first would be loaded. (MNG-3506)

    If your project made use of more than one custom ArtifactHandler when resolving dependencies, and these handler definitions were specified in two different plugins, you couldn’t use both at the same time. This was a quirk of the antiquated version of Plexus used by Maven 2.x, where it was impossible to load only the components from the local Plexus container if that container had a reference to its parent container. Instead, the child Plexus container – the one used for loading the plugin and its components – would load all of the known components from both the parent and the child. If some of the components referenced in the parent were from a different plugin container, the second plugin container would have no access, and the component-loading step would fail, leaving that plugin’s components out of the mix.

    This is a fairly involved issue, and requires some intimate knowledge of Plexus’ internal workings. Suffice it to say that some set-math calculations using only the component definitions themselves proved to be the key in solving the issue.

  3. Extensions were not loaded from plugin dependencies. (MNG-4270)

    Even if you enabled the extensions flag for plugins in Maven 2.2.0, no build extension would ever be loaded from one of the plugin’s dependencies. If the custom lifecycle mapping or artifact handler – or whatever – wasn’t present in the local plugin artifact, the only way to load it as a build extension was to define it directly in the POM’s extensions section of the build element. This was a particular problem in cases where users defined a generic suite of mojos, along with a generic lifecycle mapping, inside a plugin, then relied on application-specific artifact handlers and lifecycle-mapping aliases to apply the generic plugin and lifecycle to a artifact type.

I’m happy to say that, starting with Maven 2.2.1, the above bugfixes should make it much simpler to define a custom lifecycle mapping – with an accompanying artifact handler – and create your own custom build processes for your own custom artifact types.

Go Get It!

Head on over to the Apache Maven website and download your copy, check out the release notes, or take a look at the Guide to Wagon Providers.

You’ll be glad you did!