Project Configurations

Version:
May 4, 2007
Author:
Jesse Glick
Abstract:

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.

Motivation

Basic goals include:

  1. Some kind of configurations for j2seprojects, 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.

  2. 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.

API Change Overview

Several API changes are proposed.

Project Configuration SPI

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:

  1. The hasCustomizer and customize methods were added from the original SPI.

  2. setActiveConfiguration can throw meaningful exceptions, unlike in the original SPI.

  3. getConfigurations is generified, unlike in the original SPI.

  4. 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.

Ant Project SPI Enhancements

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);
    }
}

Java SE Project Metadata

A metadata format change is needed in j2seproject to load configurations.

  1. 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.
  2. 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.
  3. 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.)

UI Overview

The proposed changes affect both the global and j2seproject GUIs.

Global UI Changes

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.

Java SE Project UI Changes

A menu item Set Configuration is added to the context menu of j2seprojects 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.

Other Possibilities

Possible enhancements, plausible but unlikely enhancements, and open questions.

  1. 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.

  2. There are no plans to use configurations in NetBeans module and suite project types.

  3. 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.

  4. 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.

  5. 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 j2meprojects.) 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?

  6. 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.

  7. 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.