NetBeans 4.0 introduced a project system that initially defined only project-wide build and run actions;
per-file build and run actions were added during the 4.0 development cycle. Project build and run options,
however, remained project-wide in the common project types such as j2seproject
and thus were not
meaningful for per-file actions. Many users objected particularly to the inability to separately configure
command-line application arguments for classes with main methods inside a project.
The project system did not prevent project types from adding such facilities, and in fact the NetBeans Mobility Pack’s Java ME project type soon provided a rich project configuration system used to control a variety of build and run characteristics (such as the device emulator to use). The newer CND (C/C++/native) project type also uses configurations.
This proposal tries to address these limitations (probably for NetBeans 6.0). An SPI with matching GUI is
introduced to permit a shared UI gesture for changing a project’s configuration. Additionally, the Java SE
project type (j2seproject
) is modified to include run configurations.
Basic goals include:
Some kind of configurations for j2seproject
s, tracked in
issue #49636 with many votes.
See also the wiki page.
The most frequently requested ability, considered to be a functional regression in NB 4.0 from 3.x, is
per-class application args (passed as a String[]
to a main
method). This
is adopted as a primary goal for this proposal.
Some people have requested the ability to customize other run parameters on a per-class basis, e.g. JVM startup parameters. This is considered a secondary goal, but the proposed implementation does address it.
Others have requested build configurations, e.g. debug vs. release builds. This is also considered a secondary goal, since the Java language permits little variation in build semantics anyway, and most interesting production release targets (e.g. creating a Pack200 JAR) can process binaries built for development purposes. The proposed implementation permits build configurations at the Ant level but provides no GUI support for them.
A common SPI for selecting configurations across project types, tracked in issue #49652. The proposed implementation addresses this, including a common GUI for switching configuration that can work with different project types.
It is not a goal for the common GUI to work with the old APIs in Java ME and CND projects, but these should be easily migrated to the new SPI.
Several API changes are proposed.
An SPI for defining configurations available in a project is needed. This SPI is adopted from an SPI already used in the Java ME project type (and copied to the CND project type), with only minor changes.
package org.netbeans.spi.project; public interface ProjectConfigurationProvider { String PROP_CONFIGURATION_ACTIVE; String PROP_CONFIGURATIONS; Collection<? extends ProjectConfiguration> getConfigurations(); ProjectConfiguration getActiveConfiguration(); void setActiveConfiguration(ProjectConfiguration) throws IllegalArgumentException, IOException; boolean configurationsAffectAction(String command); boolean hasCustomizer(); void customize(); void addPropertyChangeListener(PropertyChangeListener); void removePropertyChangeListener(PropertyChangeListener); } public interface ProjectConfiguration { String getDisplayName(); } package org.netbeans.spi.project.ui.support; public class CommonProjectActions { // ... public static Action setProjectConfigurationAction(); }
Some notes:
The hasCustomizer
and customize
methods were added from the original SPI.
setActiveConfiguration
can throw meaningful exceptions, unlike in the original SPI.
getConfigurations
is generified, unlike in the original SPI.
The use of interfaces rather than abstract classes is not expected to pose a threat to the evolution of this SPI. Replacement interfaces can be freely introduced since the SPI is permitted to be called only from fixed GUI infrastructure.
Two API additions in the Ant Project SPI are desirable to permit j2seproject
’s
PropertyEvaluator
to reflect the active configuration accurately, without duplicating a great deal
of subtle code already written and tested in support of
AntProjectHelper.getStandardPropertyEvaluator()
:
package org.netbeans.spi.project.support.ant; public class PropertyUtils { // ... public static PropertyProvider userPropertiesProvider(PropertyEvaluator, String, File); public static abstract class DelegatingPropertyProvider implements PropertyProvider { protected DelegatingPropertyProvider(PropertyProvider); protected final void setDelegate(PropertyProvider); public final Map getProperties(); public final void addChangeListener(ChangeListener); public final void removeChangeListener(ChangeListener); } }
A metadata format change is needed in j2seproject
to load configurations.
nbproject/private/config.properties
stores the currently active configuration in a property
config
. If ${config}
is undefined, the active configuration is considered to be a
default configuration.
nbproject/configs/CONFIGNAME.properties
signals that a configuration with the code name
CONFIGNAME exists. It may optionally define a property named $label
giving a
human-readable display name for the configuration. Any other properties defined in the configuration are
applied to the project when that configuration is active and override defaults in
nbproject/project.properties
.
nbproject/private/configs/CONFIGNAME.properties
is optional and can contain per-user
settings for the indicated configuration. Any such properties override defaults in
nbproject/private/private.properties
.
There is no support for orthogonal configurations, for example a build configuration and a run configuration active simultaneously, though a configuration could hold either build-oriented or run-oriented properties or both. Neither Java ME nor CND projects ever apparently needed orthogonal configurations, so this was not considered a goal.
There is no support for one configuration inheriting default settings from another, except in that all named configurations inherit defaults from project-wide settings. (The default configuration behaves like an empty configuration.)
The proposed changes affect both the global and j2seproject
GUIs.
These UI elements are borrowed from the Java ME and CND project types with only minor modifications.
A combo box for switching the active configuration is added to the Build toolbar. It is enabled iff a
main project is set which defines a ProjectConfigurationProvider
and lists the available
configurations in alphabetical order. If hasCustomizer()
, a final entry Customize… is added
which if selected just invokes customize()
.
Main-project-specific toolbar buttons are given an extra combo-box-like dropdown menu when a main project is
set, it has a ProjectConfigurationProvider
with multiple configurations available,
and configurationsAffectAction
returns
true for that command. The menu items correspond to available configurations; when selected, an item runs the
project action once with that configuration in effect without changing the active configuration. Java SE
projects enable this mode for the Run Main Project and Debug Main Project buttons.
A menu item Set Main Project Configuration is also added to the Build menu with similar semantics.
A menu item Set Configuration is added to the context menu of j2seproject
s to permit the
active configuration to be changed even if the project is not the main project. It is otherwise similar to the
main menu item.
The j2seproject
always defines a <default> configuration representing project-wide
settings, and additionally defines one configuration per entry in nbproject/configs/*.properties
.
(A project initially has no configurations.) The Customize… entry simply displays the Run panel
of the project Properties dialog.
This panel is modified to include a Configuration combo box listing available configurations (selection tracks the active configuration for the project). The other text fields in the panel apply to the selected configuration. A New… button prompts for a name for a new profile and adds it to the list (also selecting it). A Delete button removes the selected profile (disabled when <default> is selected). Properties set in the default configuration are also displayed in other configurations unless overridden; properties are stored in other configurations only if they differ from the value in the default configuration, in which case their corresponding labels are also displayed in boldface.
Possible enhancements, plausible but unlikely enhancements, and open questions.
Java EE project types are likely to want to define configurations, perhaps for selecting application servers or web browsers to test against. Since these changes would not be needed until NB 6.0, they could be deferred until after 5.5 work is complete, so long as nothing in the current proposal seems incompatible with the expected changes.
There are no plans to use configurations in NetBeans module and suite project types.
Adding GUI support for making some or all of the remaining j2seproject
properties
configuration-specific would probably not be difficult if it is found to be desirable. An add-on module could
also provide a GUI to mark certain properties as configuration-specific, though it could not integrate well
with the existing Properties dialog.
j2seproject
could directly permit associating arguments with classes run using Run File.
A third-party module exists which does just this. While simple and perhaps enough for many people, the UI is
different from that of the “main” class in the project; other parameters (such as JVM arguments) would need
to be handled separately; there would be no evolution path to add build or other kinds of configurations; and
the disparity with the UI of Java ME and CND projects would remain.
Java ME projects use a somewhat different storage format for configurations. They keep all the data in
project.properties
and private.properties
, but prefix configuration-specific
property names with the prefix configs.CONFIGNAME.
and use Ant filter chains to strip off
the prefix when loading. This style also works well and avoids the need for extra properties files, although
it is a bit trickier in build-impl.xml
and makes it less obvious which configurations exist in a
given project. (Configurations are listed in project.xml
for j2meproject
s.) Would
an inconsistency in storage format between j2seproject
and j2meproject
be a
potential problem? Would the other style be preferable for j2seproject
for independent reasons?
Is a public support SPI needed for configuration storage in Ant-based projects?
J2SEConfigurationProvider
is mostly generic, referring to j2seproject
-specific code
only in customize()
, so this could easily be made into a support SPI if desired. Of course this
question is dependent on the previous question about what storage format for configurations should be
recommended.
Loading and storing configuration-specific settings for the Properties dialog is a bit complex, and
not supported by the current StoreGroup
SPI (cf. J2SEProjectProperties
). Displaying
a configuration chooser in the Properties dialog and marking particular properties as belonging to the
currently selected configuration is also not trivial (cf. CustomizerRun
). Assuming there were a
conventional storage format for configurations, it would be nice to also have an extension to
StoreGroup
to mark certain properties as (potentially) configuration-specific, and perhaps even
to adjust a GUI display to make the elements switch themselves according to active configuration. However it
is not clear whether a configuration-sensitive storage SPI would be generally usable, as details of storage
for nontrivial properties like classpaths might still require project-type-specific logic; and a
configuration-sensitive GUI SPI could be even more difficult, especially without a standardized data binding
framework. So these enhancements are probably best left for a future release.