Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Wiki Markup
h2. 1. Background

h4. A. Shared Context in Systems of Interchangeable Components

  Most large, component-oriented systems provide a shared context for their
  components, so alternative component implementations are not dependent on a
  single, restrictive (or, even worse, all-anticipating) API to pass information
  across multiple subsystems. Such parameter-passing leads to bloated or
  inadequate APIs, since the API designer can choose either to try to
  accommodate every possible implementation for a component, or he can restrict
  the API to the minimum necessary to do the job with the original
  implementation. Resources like database connection pools are a good example of
  items that live in this shared context. Components that require such resources
  simply look them up, or are wired to use them by a composing container,
  instead of forcing all APIs in between the connection pool initializer and
  consumer to pass the pool instance around.
  
h4. B. Relevance to Maven

  Maven is a large, component-oriented application built on top of a container
  (Plexus) which is capable of this sort of composition. However, Maven's
  component implementations are currently restricted to the APIs used to pass
  information around the system. They don't have ready access to a shared
  context for reading build-time information. Also, they cannot coordinate build
  activities with one another. This lack of shared context leads to an
  unnecessarily restrictive set of component implementations and inefficient
  build processes. Maven component implementations - including, but not
  restricted to, plugins - must have the ability to retrieve as much information
  as possible about the current build environment.


h2. 2. Problem

h4. A. No Support for Querying Dynamic, Build-Time State

  Currently, Maven provides a mechanism for injecting static information about
  the current build into plugins. It also supports wiring plugins and other
  components with component requirements, which allow them to retrieve further
  information about the current build, though this information currently is not 
  cached for successive querying in a threadsafe way. It does not provide a
  mechanism for retrieving dynamic build-time state or progress for custom components
  and plugins to use. 
  
h4. B. Embeddable Property-Passing

  The simple act of passing System properties in an embeddable way (where 
  "System" properties need to vary across multiple threads in a single Maven 
  instance) introduces major API changes, since these properties, which are 
  initialized at the beginning of the build, must be passed throughout the 
  system until they reach the appropriate components. In some cases, these 
  properties must propagate through five or six layers of Maven APIs before they 
  can be used. Yet in many ways, the System properties represent a shared 
  context (though too widely shared, in the embedded scenario) by which 
  component-specific configurations can be communicated from the application 
  entry point to the appropriate component.
  
h4. C. Plugins in Silos

  Additionally, there is no way for plugins to mark progress in a build, or 
  signal that they have detected a state where the build has not failed but also 
  should not proceed. Multiple mojos within a single plugin can pass information 
  by way of a context map, but this context map restricts the consuming mojos to
  usage scenarios that also involve their counterpart mojos, since they cannot 
  function properly without their counterparts in place, regardless of whether 
  the functions of these counterparts could be fulfilled in other ways.
  

h2. 3. Proposed Solution

h4. A. The Build Context

  As a solution to the problem of a build-time shared context, a new project
  called maven-build-context should be created. This project would provide a
  formal mechanism for storing and retrieving structured data from the Plexus
  container's Context map. By using a set of tools to access the shared context, 
  it can be scoped appropriately (per-project, per-thread, etc.) in such a way 
  as to avoid the problems encountered when using System properties in an 
  embedded environment. By using structured data, it's possible to avoid 
  datatype-conversion problems (coercing a String to an int, for example).

h4. B. Plugin Cooperation
  
  By using a shared datatype with a controlled vocabulary, it's possible for
  plugins to cooperatively determine whether to execute, based on the actions of
  other plugins that were registered in the shared context. Plugins that go
  further in detecting build configurations beyond that explicitly laid out in
  the POM could inject this detected configuration for use by other plugins.
  Such advanced state might include the source or method used to resolve each 
  project dependency, so that dependencies from certain sources can be handled
  differently when the project is deployed (imagine building certain
  dependencies from source, then deploying those built dependencies alongside
  the main project artifact automatically).

h4. C. Baking it into the Container
  
  Ideally, these shared-context objects should be wired in as part of the
  composition process for dependent components, and injected into mojos along 
  with things like ${localRepository} or ${project}. The act of querying the
  application for this build-time information makes it much more difficult to
  chart dependencies between components that produce and consume such
  information. Therefore, it's important to specify this information as 
  declaratively as possible, in order to catch potential problems ahead of time,
  before the build is in progress. Rudimentary specification of a <dependency/>
  element in each component's POM that points to the shared datatype is a good
  start, but still doesn't enable a more advanced validation that producer and
  consumer of this shared datatype are present and aligned properly.
  
  
h2. 4. Potential Drawbacks
  
h4. A. Inter-Plugin Dependencies

  Obviously, the biggest concern here is the ability to form inter-plugin
  dependencies by specifying a shared datatype in one plugin, and developing
  another plugin that depends on that datatype. However, such a dependency
  doesn't preclude a new plugin from specifying a binary (not lifecycle) 
  dependency on the original plugin (the one with shared the datatype), then
  acting as an alternative producer. An even better approach would be to specify
  the shared datatype in its own project, then provide dependencies on this new
  project for each of the three plugins. By doing this, a developer effectively
  creates an open protocol for an infinite array of plugins to communicate with
  one another through the shared context of the build.
  
  
h2. 5. Relevant Conversations

# [Jesse McConnell and John Casey (transcript from IRC)]