Hi all,
In order to prevent the issues we've had in 2.0.x, I've refactored
the extension mechanism in 2.1 to be much more careful about
separating extensions from the core of maven. All extensions are
loaded into their own ClassRealm that inherits from the maven core
ClassRealm, and each project that uses an extension gets its own
ClassRealm that inherits from the core realm as well. The project
realm then imports all implementations of components declared in the
extension artifact. The interfaces for these components are assumed
to exist inside maven's core realm, to prevent adding new interfaces
to the runtime that plugins see.
Plugins each get their own ClassRealm, which is associated with a
particular project realm (or, if the project isn't using extensions,
the core realm) just before the plugin executes. This allows plugin
realms to be reusable across multiple projects (at least, that's the
theory), and reduces the memory problem incurred by each project
having their own copy of each plugin's realm.
The problem we've run into is that the dotnet code relies on maven-
toolchains, but uses sub-interfaces of the main toolchain interfaces
to do its work. This means it's not as simple as just casting the
dotnet-specific toolchain components to their implementation classes
and using that. Instead, the dotnet work relies on access to the sub-
interfaces, which are loaded twice: once in the extension realm
(isolated from the rest of the build, but accessible from the
extension's imported classes), and once again in the plugin (since it
can't see the sub-interface from the extension).
Simply adding all classes in an extension (and its dependencies) to
the core maven realm (or a project-specific realm) is not a great
option, since this can cause incompatibilities between the extension
and plugins. If the project uses and extension that depends on maven-
scm 1.0, and plugin Y needs maven-scm 1.1, you're out of luck. In the
current 2.1 implementation, the dependency on maven-scm from the
extension should be effectively hidden from the rest of maven, only
accessible from the extension component itself. Obviously this hiding
mechanism is a little too restrictive, since it also hides other
public non-core interfaces that need to be present to be used from
plugins.
I'd propose to resolve this using a mechanism borrowed from OSGi: we
should create some sort of manifest of classes to be exported from
the extension for use by the rest of Maven. This file could be
optional, and the existing behavior would result. But if the file
were present, it would name all the classes (and class patterns?) in
the extension artifact (and possibly its dependencies) to "export"
into the main maven ClassRealm(s) for use by plugins. This is a
relatively small change to Maven's extension mechanism for 2.1, and
would restore many of the best features of the old extension
functionality without incurring the blind incompatibilities of the
old system.
Anyone have any thoughts on this?
-john
---
John Casey
Committer and PMC Member, Apache Maven
mail: jdcasey at commonjava dot org
blog: http://www.ejlife.net/blogs/john
rss: http://feeds.feedburner.com/ejlife/john