Substitution of Custom Maven Components

We're already starting to see an emerging need to customize Maven, by adding new types of artifact resolvers, project builders, etc. Since we've taken so much care to design Maven as component-oriented software, we need to open up those component-oriented aspects.

State of the Art

Currently, if a user wants to add a custom artifact handler to Maven, the cleanest way to do it is to write the resolver along with a new components.xml. This components.xml must define a new component descriptor that overrides the default one. After that, the user will have to stash this resolver jar into a new directory, most likely under someplace like ${maven.home}/custom. Finally, they have to add a new line to the ${maven.home}/bin/m2.conf file, to add the new directory to the front of the classpath, like this:

load ${maven.home}/custom/*.jar <-- this one has to come first, to override.
load ${maven.home}/lib/*.jar

Where can we go from here?

It would be much nicer to have the ability to simply dump the new resolver jar into ${maven.home}/lib, and change the selection priority for the ArtifactResolver to use the new implementation instead of the default one...this would happen in a master config XML file, maybe. It would also allow the new resolver to delegate to the default implementation without redefining it's descriptor (right now, we'd be overriding the default implementation's component descriptor, effectively wiping it out of the container).

  • No labels

4 Comments

  1. this would be also nice to have settable for the embedder dynamically. Like before starting it, one could assign custom impl of some services. That seems like the only way now to some issues I have now with the project retrieval from the embedder.

  2. I disagree with this proposal, and lean more towards Milos' point.

    For one, we should not be stashing anything in lib/ or some custom directory of the install, it should be part of the pom for reproducibility. And it is - its the <extensions> mechanism.

    As for selection, I think a better method of selection is to use role-hints and some other configuration to select that role hint. This is how it works (quite well) for wagons, etc.

    The only enhancement I'd like to see (other than the already JIRA'd limitations of the current extension mechanism), is to be able to register role hints in the repository so that things like ftp:// in a wagon URL finds the latest ftp wagon without having to provide an extension (though if an extension were given, it would be used for version reproducibility).

  3. I also think that customizing this stuff through the embedder is highly desirable. However, it's important to realize that specification of build extension will not cut it.

    Consider the case where you want to use a custom artifact resolver. By the time you have access to the build extensions in the POM, the artifact resolver has already been retrieved from the container (in order to resolve parent POM, etc.). So, introducing an alternate, preferred, implmeentation of ArtifactResolver at this point may cause inconsistencies if any other component is storing a reference to the original ArtifactResolver instance.

    Looking up wagons by protocol/role-hint is completely different, in that you have a well-specified and easily accessibl role-hint built into the usage. With a resolver, this won't be the case...it's meant to be used behind-the-scenes.

    I simply don't think you can control this from the POM. It's a deeper issue. It would, however, be feasible to push this kind of configuration into the settings descriptor and then resolve the artifacts for these customizations when the settings descriptor is loaded - which could be done using an explicit reference to DefaultArtifactResolver (not ideal, but manageable). However, if you're thinking of loading a centralized version of the settings.xml, you'll need some even deeper initialization method...which starts to look a lot like $maven.home/lib or a setter in the embedder prior to starting it.

  4. One use case I would like to implement is merging the local repository with the Debian packages. On Debian, once a package is installed, its content goes to /usr/share/java/ for the jars, and /usr/share/doc/ for the documentation. So I can easily link the jar in /usr/share/java/ to the Maven repo (this both saves disk space and enable me to build Maven projects according to Debian rules which disallow any downloading of external artifacts). But for the documentation, I have a toughter time as it is unpacked in /usr/share/doc. So it's not possible to create a link here to mylib-javadoc.jar in the local Maven repository. A solution for that problem would be to have a Debian enhanced version of Maven, which can handle unpacked docs (or ear, war...) in its repository and serve them to Maven users (the build or the IDE). I tried to do that, but at the moment it's very hard to change the DefaultRepository with what I need. Thanks!