This framework provides a common mechanism and ui for adding and
removing units of functionality from a project. A unit of functionality (or a
"feature") is a marker that can be used, for instance, to enable
feature-specific UI. A feature also has a great deal of flexibility to
manipulate the project when it's being installed. It can add natures, builders,
and classpath entries. It can also lay down feature-specific metadata files
and other resources into the project directory.

Feature vs. Nature

A feature is similar to a nature, but it's scope is much wider.

Features are designed to be added and removed by the end user, while natures are an
implementation detail. A feature can, if necessary, add a nature to the project as
part of it's installation logic. Not all features will use natures.

Features can be versioned. Feature A can declare that it depends on feature B version
1.2 or newer. Upgrade handling can be associated with moving from version 1.2 to 1.3.

Features support a richer constraint expression language than natures.

It would be difficult to add additional lifecycle event methods to the
IProjectNature interface, because doing so will break all of the existing
implementations. The feature framework, on the other hand, uses a delegate
mechanism where every event method is represented by a separate interface.
This makes it very easy to add support for new lifecycle events without
effecting existing code. See the Delegates
section for more information.

The IProjectNature's configure and deconfigure methods do not take any
parameters. This makes them of limited use in situations where input from
UI needs to be taken into account and has resulted in a situation where
most of the necessary work happens in the wizards. This makes it quite
difficult for someone to say add java functionality to a project at the
API level. The features framework addresses this problem by allowing the
install and uninstall delegates to take a configuration object. The
configuration object can either be filled out by the UI or someone working
at the API level.

Version Support

The framework supports defining multiple versions of the same feature. This
makes it possible to, for example, express that feature A depends on version
1.3 or newer of feature B. There are no limitations placed on the format of the
version string. The feature author is responsible for providing an
implementation of a version comparator. If one is not provided, a default
implementation will be used.

Constraints

Each feature version can declaratively specify what constraints must be
satisfied before the feature can be installed. Four operators are supported:
and, or, requires, and oneof.

The feature and version attributes are required. The
allow-newer and soft attributes are optional and both are
defaulted to false. The soft attribute is used to indicate that
the feature is allowed to be installed even if the required feature is missing,
but if the required feature is selected, this feature should be installed after
it.

<oneof set="string"/>

The set attribute is required. This constraint is used to indicate
that the feature conflicts with members of the specified set.

Each feature version can implement any number of the supported delegate
interfaces to be given a chance to do some work during some event in a feature's
life cycle. Six delegates are supported: install, uninstall,
update, upgrade, activate, and deactivate. Most, if
not all, features will implement at least the install delegate.

install - Invoked when the feature is being added to a project. This
can happen either during project creation or when the user chooses to add a
feature to an existing project. This delegate will be invoked after all the
features that this feature depends on are installed. This delegate can take
input from UI through a config object. See the Wizard
Framework section for more information.

uninstall - Invoked when the feature is being removed from a project.
This delegate can take input from UI through a config object. See the
Wizard Framework section for more information.

update - Invoked on an installed feature when there is significant
change to some of the feature's dependencies. Some examples of a signficiant
change include: installing or installing a soft dependency, upgrading of a
dependent feature, and installing or uninstalling a hard dependency where an
"OR" constraint is involved.

upgrade - Invoked when the user changes the version of a feature
that's already installed.

activate - Invoked when a project containing this feature is loaded.
The feature's author should use caution when taking advantage of this delegate,
since this will cause the plugin that contains the delegate to be loaded every
time any project containing this feature is loaded.

deactivate - Invoked when a project containing this feature is closed.
The feature's author should use caution when taking advantage of this delegate,
since this will cause the plugin that contains the delegate to be loaded every
time any project containing this feature is closed.

A category is a grouping of several related features that would frequently
be added to a project as a set. Categories allow the feature author to provide a
fine-grained feature breakdown for an expert user wihout complicating matters
for a novice. A feature can belong to at most one category.

Presets

A preset is a user convenience mechanism for quickly selecting a set of
features. Presets are intended as a quick starting point for doing a certain
type of development. For instance a server vendor might create a preset that can
be used when developing exclusively for that server platform or there might
be presets for doing webservice development vs. web ui development. After
applying a preset, the user can further tweak the set of selected features and
change their configurations.

A user can also define custom presets, which are stored in workspace
metadata. Once a custom preset is created it can be used just like a preset
defined through the extension point.

Presets would manifest in the UI as a drop-down above the feature selection
panel. The list of presets will be filtered to only show presets that would
not conflict with fixed features. A preset is allowed to change the version of
a fixed feature, but not deselect it.

A runtime is a container or an environment that projects will execute within.
Sun Java VM and Apache Tomcat are both examples of a runtime. Some features can
only run on specific types of runtimes. For instance, a Web Module feature
cannot run on a base Sun Java VM runtime. It needs a J2EE server such as Apache
Tomcat. A vendor-specific feature might only run on that vendor's runtime.

The framework provides a way to declare runtime types and to map features to
them. The runtimes are versioned and features can be mapped to either a specific
version, specific version or newer, or all versions. It is not necessary to map
all features to all runtimes that they will run on. If feature x depends on
feature y and feature x will run on all runtimes that y will run on, it is not
necessary to provide mappings for x. In fact, a feature will run on all runtimes
unless it is explicitly restricted by runtime mappings or features it depends
on.

If the set of features that a runtime supports varries based on it's
configuration, the "runtime extension" concept can help in modeling these
situations. A feature can be mapped to either a runtime or a runtime extension.
A runtime can have any number of extensions.

A runtime instance is formed by taking a particular version of the runtime
type and combining it with any applicable extensions. A runtime instance can
also "build-on" another runtime instance. For example, one can create "My JBoss"
runtime that's an instance of "jboss v.1.0" with "jboss.ejb.extension v.1.0"
installed and that builds on "My JVM Install" runtime instance. The framework
provides a way to register runtime instance, but tooling is left to runtime
vendors.

A user can choose to associate the project with a particular runtime at the
time of creation. If the user chooses to do that, the selected runtime instance
is available to feature wizard pages and the delegates. The features can adjust
their behavior based on the selected runtime. One common use of this is for
classpath setup. A feature can ask the runtime if it can provide classpath
entries for it. If the runtime is unable to provide classpath entries for a
particular feature, or if no runtime is selected, the feature is responsible for
setting up the classpath on it's own. This might mean gathering additional
input from the user. When the user changes the runtime associated with a
project, all of the installed features are notified so that they can adjust
the classpath accordingly.

Fixed Features

While it would be possible to allow the user to pick from the complete list
of available features when creating a project, the generality of that would
likely lead to user confusion. As such, certain features can be "fixed" at
project creation to define a "project type". Any features that conflict with
the fixed features are not displayed to the user. The user cannot de-select a
fixed feature, but can change it's version.

Part of the features framework is a wizard that provides a common way to add
and remove features. The wizard consists of a feature selection page followed
by pages associated with actions that the user takes in the feature selection
page (such as install feature or uninstall feature). The feature action pages are
displayed in dependency order. The wizard can either be used stand-alone on an
existing project or as part of a project creation wizard. In fact the framework
provides an abstract project creation wizard that prepends a page that allows
the user to specify project name and location. The abstract project creation
wizard is subclassed to specify the set of fixed features and which preset to
start with.

Feature authors can register pages and the config objects through the
provided extension point. The config object will be instantiated and passed to
all of the pages. The same config object will then be passed to the delegate
implementing the action. The framework places only one restriction on the config
object: it has to have a zero-argument constructor.

Wizard pages associated with particular feature can peek at the config of the
other features currently being operated on. That's done through the wizard
context that's available to all of the pages.