NetBeans Master Developer FAQ

How do I have two source directories within one module?

Adding an extra source directories is possible in case you need to create a separate output JARs (besides the module itself), generally with its own special classpath.

In your module's project.xml, add a declaration of the source root just before </data>:

<extra-compilation-unit>
    <package-root>othersrc</package-root>
    <classpath>...anything it might need to compile against...</classpath>
    <built-to>build/otherclasses</built-to>
    <built-to>${cluster}/modules/ext/other.jar</built-to>
</extra-compilation-unit>

This declaration has no effect on the build, but lets you work with the sources in the IDE's code editor.

You will separately need to add a target to your build.xml to compile and package these sources however you like. (You can name your target netbeans-extra and it will get run automatically toward the end of the module's build cycle.) If you define properties like a special classpath in project.properties, you can use the values in both build.xml and project.xml to minimize duplication.

You can also create a plain Java SE project in a subdirectory of your module and bundle its JAR. DevFaqWrapperModules describes a related technique.

Read the harness/README file under your Netbeans installation directory for information about issues like this one. The build harness has many capabilities not exposed through the GUI.


Applies to: NetBeans IDE 6.x Platforms: All

How do I get access to NetBeans sources using Mercurial (hg)?

First, make sure you have Mercurial installed on your machine, along with its requirements such as python.

Then, from the command line, you run

hg clone http://hg.netbeans.org/main/
to get the full Platform and IDE sources. If you also want the contrib/ and misc/ repositories, it is best to first install the Forest extension for Mercurial, and then run
hg fclone http://hg.netbeans.org/main/ nb_all

To build, simply run Ant in the root of your NetBeans sources. The build will appear in $NB_SRC/nbbuild/netbeans/.

More info about using Mercurial with Netbeans sources...

How do I get access to zipped NetBeans sources for a periodic build?

(as of June, 2009)

1. Go to the nightly build download site:

http://bits.netbeans.org/dev/nightly/

2. Click the link for the build you want.

3. You will be shown an index page which makes no mention of how you can get a ZIP file or a source archive, so ignore it.

4. Add "zip/" to the end of the URL in your browser's address bar and hit enter. In other words, the complete URL might look like this:

http://bits.netbeans.org/dev/nightly/2008-06-24_02-01-08/zip/

5. There are about a dozen links on that page. The one you want is begins with "netbeans-trunk-nightly" and ends with "-src.zip" Click that link to download the source archive.

related message in the NetBeans mailing list

How do I add an action to my custom node type ?

Override the public Action getActions(boolean context) method of your node (99% of the time you can ignore the boolean parameter).

If this node is really a DataNode for your own file type, instead see DevFaqActionAddFileMime.

See also:

How do I add an action to a the popup menu of the Java editor?

The simplest way is to run New Action Wizard (File > New... > Module Development > Action) which creates an action for you and registers it in your layer.xml.

  1. On the first tab, choose Conditionally Enabled action and select EditorCookie as the cookie class.
  2. On the second tab, check Editor Context Menu Item and choose MIME type (text/x-java in this case) and position.

You can also declare your action in your layer manually:

<folder name="Editors">
  <folder name="text">
    <folder name="x-java">
      <folder name="Popup">
        <file name="org-mymodule-MyAction.instance"/>
      </folder>
    </folder>
  </folder>
</folder>

You can also use Editors/Popup/ to add an action to all editor kits.

See also:

How do I add an action to a file of a given mime-type?

The simplest way is to run File > New... > Module Development > Action which creates an action for you and registers it in your layer.xml.

  1. On the first tab, choose Conditionally Enabled action and select DataObject as the cookie class.
  2. On the second tab, check File Type Context Menu Item and choose the MIME type and position.

You can also declare your action in your layer manually:

<folder name="Loaders">
  <folder name="text">
    <folder name="html">
      <folder name="Actions">
        <file name="org-mymodule-MyAction.instance"/>
      </folder>
    </folder>
  </folder>
</folder>

You can replace text/html with text/x-java, text/x-ant+xml, text/x-jsp, image/png, etc.

However, this still may not work depending on how the data loader for the type works. The DataLoader implementation has to override actionsContext() and return this path if it wants to load the Action instances from there. If the data loader you are interested in does not yet do this, please first file a bug report to make sure this is fixed in a future release; as an inferior workaround, you can use e.g.

DataLoader loader = DataLoaderPool.getDefault().firstProducerOf(SomeDataObject.class);
if (loader != null) {
    SystemAction[] actions = loader.getActions();
    SystemAction[] newactions = new SystemAction[actions.length + 2];
    System.arraycopy(actions, 0, newactions, 0, actions.length);
    // More realistically: take care that it is not a duplicate,
    // place into a specific position, etc.:
    newactions[actions.length] = null;
    newactions[actions.length + 1] = SystemAction.get(SomeAction.class);
    loader.setActions(newactions);
}

You need to know the implementation class of the foreign data object to implement this workaround. You should avoid doing this unless it is really critical to usability, and replace it with layer-based declarative actions as soon as that is available (you did file that bug report, right?).

See also:

How do I add an action to a folder?

Add to your layer:

<folder name="Loaders">
  <folder name="folder">
    <folder name="any">
      <folder name="Actions">
        <file name="org-mymodule-MyAction.instance"/>
      </folder>
    </folder>
  </folder>
</folder>

See also:

How do I add an action to the menu bar?

The simplest way is to run New Action Wizard (File > New... > Module Development > Action) which creates an action for you and registers it in your layer.xml file.

See also:

How do I add a new panel to a Project Properties dialog?

Register the panel like this in the layer (here for Java SE projects):

<filesystem>
    <folder name="Projects">
        <folder name="org-netbeans-modules-java-j2seproject">
            <folder name="Customizer">
                <file name="Bla.instance">
                    <attr name="instanceCreate" methodvalue="org.bla.BlaPanelProvider.createBlaPanel"/>
                </file>
            </folder>
        </folder>
    </folder>
</filesystem>

Then create it:

public class BlaPanelProvider implements ProjectCustomizer.CompositeCategoryProvider {

    public static BlaPanelProvider createBlaPanel() {
        return new BlaPanelProvider();
    }

    @Override
    public Category createCategory(Lookup arg0) {
        ProjectCustomizer.Category toReturn = null;
        toReturn = ProjectCustomizer.Category.create(
                "Bla",
                "Bla",
                null,
                null);
        return toReturn;
    }

    @Override
    public JComponent createComponent(Category arg0, Lookup arg1) {
        return new BlaPanel();
    }
    
}

See also Project Properties GUI for custom project templates

How do I add an action to a project node's popup menu of my own project type?

  • To add the Copy/Delete/Move/Rename action to your project's node, you should:
    1. Implement the corresponding interface such as org.netbeans.spi.project.CopyOperationImplementation.
    2. Implement org.netbeans.spi.project.ActionProvider: public final class AddActionActions implements ActionProvider { private final AddActionProject project; //suppose this is your project public AddActionActions(AddActionProject project) { this.project = project; } public String[] getSupportedActions() { return new String[] { ActionProvider.COMMAND_COPY }; } public boolean isActionEnabled(String command, Lookup context) { if (command.equals(ActionProvider.COMMAND_COPY)) { return true; } else { throw new IllegalArgumentException(command); } } public void invokeAction(String command, Lookup context) { if (command.equalsIgnoreCase(ActionProvider.COMMAND_COPY)){ DefaultProjectOperations.performDefaultCopyOperation(project); } } }
    3. Add these implementations to your project's lookup: lookup = Lookups.fixed( // ... as before new AddActionOperation(this), new AddActionActions(this), );
    4. Register the actions into the project node's context menu: public @Override Action[] getActions(boolean context) { Action[] nodeActions = new Action[2]; nodeActions[0] = CommonProjectActions.copyProjectAction(); nodeActions[1] = CommonProjectActions.closeProjectAction(); return nodeActions; }
  • To add the other actions specified in the Project API such as closeProjectAction, just add it to the list of actions of your node.
  • To add an action you created yourself, just add it to the list of actions of your node.

See also: Common Project Actions

How do I add an action to a project popup menu?

Just register an instance of the action in your XML layer under Actions/SomeFolder and add shadow reference in Projects/Actions/. It should implement a ContextAwareAction interface, e.g. a CookieAction.

<filesystem>
    <folder name="Actions">
        <folder name="SomeFolder">
            <file name="projectcontextmenudemo-DemoAction.instance"/>
        </folder>
    </folder>
    <folder name="Projects">
        <folder name="Actions">
            <file name="projectcontextmenudemo-DemoAction.shadow">
                <attr name="originalFile"
stringvalue="Actions/SomeFolder/projectcontextmenudemo-DemoAction.instance"/>
            </file>
        </folder>
    </folder>
</filesystem>

See also How do I add an action to a project popup menu of a specific project type?

How do I add an action to a project popup menu of a specific project type?

You can install an action into the context menu of all projects simply by adding to your layer under the folder Projects/Actions/. Your action should be context-sensitive, meaning it should be a placeholder which implements ContextAwareAction; the context-aware derived action will do the real work. Generally it will look for an instance of Project in the supplied Lookup (context).

If you just override isEnabled on the derived action based on the context, the menu item will always be present, though it will be greyed out in the case of inappropriate projects. If you want to hide the menu item for all but relevant projects, you will need to make the derived action implement Presenter.Popup and the resulting component should also implement DynamicMenuContext.

This is a lot of boilerplate (hopefully a future revision of the APIs will make it simpler and/or the module development support will include a wizard for it), so it is better to show an example you can copy and customize. The following trivial action shows the location of a project so long as its name comes in the first half of the alphabet:

package projectcontextmenudemo;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JMenuItem;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectUtils;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.awt.DynamicMenuContent;
import org.openide.awt.Mnemonics;
import org.openide.filesystems.FileUtil;
import org.openide.util.ContextAwareAction;
import org.openide.util.Lookup;
import org.openide.util.actions.Presenter;
public class DemoAction extends AbstractAction implements ContextAwareAction {
    public void actionPerformed(ActionEvent e) {assert false;}
    public Action createContextAwareInstance(Lookup context) {
        return new ContextAction(context);
    }
    private boolean enable(Project p) {
        assert p != null;
        // TODO state for which projects action should be enabled
        char c = ProjectUtils.getInformation(p).getDisplayName().charAt(0);
        return c >= 'A' && c <= 'M';
    }
    private String labelFor(Project p) {
        assert p != null;
        // TODO menu item label with optional mnemonics
        return "&Info on " + ProjectUtils.getInformation(p).getDisplayName();
    }
    private void perform(Project p) {
        assert p != null;
        // TODO what to do when run
        String msg = "Project location: " +
            FileUtil.getFileDisplayName(p.getProjectDirectory());
        DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(msg));
    }
    private final class ContextAction extends AbstractAction implements Presenter.Popup {
        private final Project p;
        public ContextAction(Lookup context) {
            Project _p = context.lookup(Project.class);
            p = (_p != null && enable(_p)) ? _p : null;
        }
        public void actionPerformed(ActionEvent e) {
            perform(p);
        }
        public JMenuItem getPopupPresenter() {
            class Presenter extends JMenuItem implements DynamicMenuContent {
                public Presenter() {
                    super(ContextAction.this);
                }
                public JComponent[] getMenuPresenters() {
                    if (p != null) {
                        Mnemonics.setLocalizedText(this, labelFor(p));
                        return new JComponent[] {this};
                    } else {
                        return new JComponent[0];
                    }
                }
                public JComponent[] synchMenuPresenters(JComponent[] items) {
                    return getMenuPresenters();
                }
            }
            return new Presenter();
        }
    }
}

and here is how to register it:

<filesystem>
    <folder name="Actions">
        <folder name="SomeFolder">
            <file name="projectcontextmenudemo-DemoAction.instance"/>
        </folder>
    </folder>
    <folder name="Projects">
        <folder name="Actions">
            <file name="projectcontextmenudemo-DemoAction.shadow">
                <attr name="originalFile"
stringvalue="Actions/SomeFolder/projectcontextmenudemo-DemoAction.instance"/>
            </file>
        </folder>
    </folder>
</filesystem>

Applies to: NetBeans 5.0, 5.5, 6.x

How do I add an action to the global popup menu of tabs?

While there is no official way to add a custom action to a foreign TopComponent's tab, you can achieve this by installing a hook into the Swing event dispatch thread and listening for the popup activation. Then when the popup is detected, copy the actions from the TopComponent, add your custom actions, and finally set a new popup menu for that particular TopComponent.

// Install hook into the AWT event dispatch thread so we can capture context popup
private void addGlobalContextAction() {
    Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
        public void eventDispatched(AWTEvent event) {
            MouseEvent mouseEvent = (MouseEvent) event;
            if (mouseEvent.isPopupTrigger()) {
                if (mouseEvent.getSource() instanceof TabDisplayer) {

                    // Find the TopComponent being wrapped
                    TabDisplayer tabDisplayer = (TabDisplayer) mouseEvent.getSource();
                    TabData tabData = tabDisplayer.getModel().getTab(
                        tabDisplayer.getSelectionModel().getSelectedIndex());
                    TopComponent tc = (TopComponent) tabData.getComponent();

                    // Copy existing popup-menu
                    mouseEvent.consume();
                    JPopupMenu popup = new JPopupMenu();
                    boolean separatorJustAdded = false;
                    for (Action action : tc.getActions()) {
                        if (action == null) {
                            if (!separatorJustAdded) {
                                popup.addSeparator();
                                separatorJustAdded = true;
                            }
                        } else if (action.isEnabled() &&
                                   !(action instanceof FileSystemAction)) {
                            JMenuItem wrappedAction = new JMenuItem(action);
                            wrappedAction.setText(removeAmpersand(
                                action.getValue(Action.NAME)));
                            popup.add(wrappedAction);
                            separatorJustAdded = false;
                        }
                    }

                    // Add custom action
                    popup.add(new AbstractAction("Click me") {
                        public void actionPerformed(ActionEvent e) {
                            System.out.println("Yay, you clicked me!");
                        }
                    });
                    tabDisplayer.setComponentPopupMenu(popup);
                }
            }
        }
    }, AWTEvent.MOUSE_EVENT_MASK);
}

private String removeAmpersand(Object actionName) {
    return ((String) actionName).replaceAll("&", "");
}

Notice however, there are some ugly action filtering going on and keyboard accelerator indications have to be removed from the action text. Furthermore, it's relatively expensive to add such an application-wide hook. As such, this is to be considered a fragile hack until a better solution becomes available.


Applies to: NetBeans IDE 6.5, ?? Platforms: All

How do I add an action to the Toolbar?

The simplest way is to run New Action Wizard (File > New... > Module Development > Action) which creates an action for you and registers it in your layer.xml file.

See also:

How do I create an Action that is automatically enabled and disabled depending on the selection?

There are three ways to do this, depending on what exactly you need:

CookieAction

CookieAction is used to write actions that are sensitive to what is in the selected Node(s) Lookup. You can specify one or more classes that must be present in the selected Node's Lookup, and some other semantics about enablement.

Being an older class, under the hood it is using Node.getCookie(), so your action will only be sensitive to things actually returned by that method - in other words, only objects that implement the marker interface Node.Cookie can work here.

NodeAction

NodeAction is somewhat more flexible, but requires more code to implement. It is just passed the array of activated nodes whenever that changes, and can choose to enable or disable itself as it wishes. Essentially this is just an action that automagically tracks the global Node selection.

Roll your own

The following is relatively simple and affords a way to perform whatever enablement logic you like (NodeAction can do that too, but this might be a little more straightforward and your code doesn't have to worry about nodes at all: DevFaqWhatIsANode). To understand how this works, see DevFaqTrackGlobalSelection:

public class FooAction extends AbstractAction implements LookupListener, ContextAwareAction {
    private Lookup context;
    Lookup.Result<Whatever> lkpInfo;

    public FooAction() {
        this(Utilities.actionsGlobalContext());
    }

    private FooAction(Lookup context) {
        putValue (Action.NAME, NbBundle.getMessage(FooAction.class,
                "LBL_Action")); //NOI18N

        this.context = context;
    }

    void init() {
        assert SwingUtilities.isEventDispatchThread() 
               : "this shall be called just from AWT thread";

        if (lkpInfo != null) {
            return;
        }

        //The thing we want to listen for the presence or absence of
        //on the global selection
        lkpInfo = context.lookupResult(Whatever.class);
        lkpInfo.addLookupListener(this);
        resultChanged(null);
    }

    public boolean isEnabled() {
        init();
        return super.isEnabled();
    }

    public void actionPerformed(ActionEvent e) {
        init();
        Collection<? extends Whatever> c = lkpInfo.allItems();
        //do something with them here
    }

    public void resultChanged(LookupEvent ev) {
        setEnabled (lkpInfo.allItems().size() != 0);
    }

    public Action createContextAwareInstance(Lookup context) {
        return new FooAction(context);
    }
}

Applies to: NetBeans 6.5, 6.7

How do I make my Node have a submenu on its popup menu?

  • Override getActions() of your Node subclass.
  • Create a custom subclass of javax.swing.Action which implements the interface Presenter.Popup.
  • Return a JMenu with whatever you want on it from getPopupPresenter().
  • Return that action in the array of actions from getActions().

What is the Actions folder in the system filesystem, and why should I use it?

You may have noticed that the examples of adding actions typically look like this:

<folder name="Actions">
   <folder name="Build">
     <file name="com-foo-SomeAction.instance"/>
   </folder>
</folder>
<folder name="Menu">
   <folder name="Build">
     <file name="pointerToComFooSomeAction.shadow">
        <attr name="originalFile" stringvalue="Actions/Build/com-foo-SomeAction.instance"/>
     </file>
   </folder>
</folder>

And you may have noticed that actions are usually put, not directly into the Menu/ folders, but into subfolders of this Actions/ folder. Then we create .shadow files that act like symbolic links, pointing to the real .instance file . Why all this indirection?

Older versions of the NetBeans UI included the ability to rearrange, and even delete, whole menus or individual menu items, and future ones may again. (Many applications built on NetBeans will not want to expose such customizability, but some do.) The current UI does include a key binding editor; the Actions/ folder can be used from this editor to list available actions, even those which are not currently bound to any keystroke.

Additionally, for actions which are javax.swing.Action but not SystemAction, creating the action instance in only a single place ensures that it acts as a singleton. (While the action class likely has no declared instance fields, it does have some state, notably information about keyboard accelerators which should be displayed in menu presenters.)


Applies to: NetBeans 6.7

I have a reference to an existing Node from some other module. Can I add cookies/properties/actions/children?

No.

Occasionally people want to do something like this, because they want to enhance, for example, the behavior or nodes for Java files or other nodes created by some other modules. However, this is a recipe for disaster - nobody writing a Node subclass does so expecting that random modules will change its internal structures without warning. It is possible to write code that does this sort of thing that looks like it works, but it is sheer luck and it will probably not work for long.

DO NOT DO THAT UNDER ANY CIRCUMSTANCES

(there, did I say that strongly enough?).

Many modules are designed for extensibility - in fact, Nodes for Java files in the IDE do allow you to add children, actions, etc. They offer an API for doing this sort of thing (for example, adding Actions to Loaders/text/x-java/Actions declaratively); see the beans module for an example of adding sub-nodes to Java classes.

If you want to modify the children/properties/actions/etc. of a Node you did not create, look for an API that lets you do that in a supported way.

If one does not exist, file an enhancement request against the module that actually creates these nodes, asking for an appropriate API for doing what you want (and be clear about exactly what you want or why). If you really want to expedite it, write a patch that creates such an API (look at how other modules do this sort of thing and aim to follow a similar pattern) - it's hard to say no to working code.

Can I add or remove children of a node on the fly?

Yes. Have your node subclass AbstractNode or whatever else you like.

NB 6 > m9 Specific: Implement ChildFactory. To create the Children object for your Node, pass it to Children.create(). When the child list needs updating, call refresh() on your ChildFactory. Its createKeys method will be called again and you can update the set of key objects as needed; Nodes for objects that remain in the list of keys will simply continue to exist; additions and removals will be handled.

NB 5 And Earlier: Have your Children object subclass Children.Keys . As needed, call setKeys() on the Children.Keys object. Just by passing a larger or smaller (or reordered) list of keys, you will be adding or removing (or reordering) children.

Do not ever try to add/remove children from a node you did not create (unless it has an API that explicitly gives you permission to do that); occasionally people try to add child nodes to nodes for things like Java files. If it works at all it's by accident.


Applies to: NetBeans 4.0, 4.1, 5.0

What are the basic things I should know about NetBeans' architecture to get started?

The most important thing is to know what you are trying to do clearly, so you can find what you need to get started quickly. Here are some basic NetBeans factoids which will either answer some questions or whet your appetite for more information:

A lot of things in NetBeans are based around file recognition and using files to provide Java objects. Even if your application has nothing to do with editing files, this may still be very useful to you, since the same mechanism that recognizes/displays a user's files on disk also recognizes/displays configuration data (which may not even be files in the traditional sense at all), and such "files" can actually be factories for whatever kind of object you want (and that way you get persistence of those files for free).

For example, the FeedReader tutorial simply serializes POJO Feed objects into the configuration filesystem , and its whole UI consists of aiming a standard tree component at a folder full of those objects, and providing a few actions to let the user create more of them. When the application shuts down, it does not need to any special code for persisting them, it is all automatic.

For more information about how that works, see the section on file recognition.

One of the most basic and important things to know about is how modules register objects - this is mainly done through a configuration file inside the module's jar file (if you are using NetBeans 5.0 or greater's module building support, you can usually avoid hand-editing this file). Most things a module does to influence the environment are declarative rather than programmatic - in other words, you put some text in an XML file, or an entry in a jar manifest, or a file in some specific place in the module jar, and your functionality will be discovered when the system starts up - as opposed to writing java code.

Two of the most common needs are opening custom Swing components in the UI, and installing actions in the main menu .

Other basic topics that are worth reading to get the lay of the land are:

There are various tutorials, and the canonical reference to NetBeans APIs is the API javadoc.

Java EE Application Client on top of the NetBeans Platform Tutorial

Draft

This is document currently has draft status

This tutorial will show you how easy is to create an application client on top of the NetBeans Platform. It will be demonstrated on the example of Database Reader.

Table of Contents



Requirements

Installation And Configuration

Install all of the required products (installation guides are available on the product's websites). When it'll be done we have to set up a few things. First of all please start NetBeans IDE 5.5.1 and register GlassFish v2. Right click on the Servers node in the Runtime tab and select Add server (choose Sun Java Application Server).

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/addserver.png

Now we need to register NetBeans Platform into IDE. It's in fact almost same as to add a new server. In menu Tools -> NetBeans Platform Manager click on a Add Platform button and pass through the wizard (as a new platform select downloaded NetBeans Platform 5.5.1).

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/addplatform.png

Projects Creation

It's time to create all projects. We need NetBeans Module Suite project, NetBeans Module (added into your NetBeans Module Suite) project and Enterprise Application project with Application Client and EJB module included. Let's do it. First of all we create NetBeans Module Suite project. Call it dbreader. As used platform choose the new one what you registered before.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/createsuite1.png

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/createsuite2.png

Then create NetBeans Module Project. Call it customers. And check that you want to add it into your dbreader suite. All other options leave as default.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/createmodule.png

Actually we have had NetBeans Modules created and now we have to create Java EE part. So let's create an Enterprise Application with Application Client and EJB module. Call it dbreader-ear. Include Application Client and EJB module. Exclude Web module. Also select Java EE 5 version and choose Sun Java Application Server as development server.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/createear1.png

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/createear2.png

Great ! You have successfully created all required projects. Now you should see something like this in Projects tab.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/projects.png

Enterprise Application Development

Build Script Modifying (5.5.x)

We need to modify dbreader-ear build.xml script because the dbreader suite jnlp distro has to be packed into dbreader ear. Due to add these lines into dbreader-ear build.xml (instructions for 6.x are in the next part).

    <property name="dbreader.home" value="../"/>
    
    <target name="build-dbreader-jnlp">
        <java classname="org.apache.tools.ant.Main" dir="${dbreader.home}" failonerror="true" fork="true">
            <jvmarg value="-Dant.home=${ant.home}"/>
            <arg value="build-jnlp"/>
            <classpath path="${java.class.path}"/>
        </java>
    </target>
    
    <target name="pre-dist" depends="build-dbreader-jnlp">
        <!-- dbreader.home must point to DatabaseReader Application home directory -->

        <mkdir dir="${build.dir}/lib"/>
        <copy todir="${build.dir}/lib">
            <fileset dir="${dbreader.home}/build/jnlp/app" includes="*.jar" />
            <fileset dir="${dbreader.home}/build/jnlp/branding" includes="*.jar" />
            <fileset dir="${dbreader.home}/build/jnlp/netbeans" includes="*.jar" />
        </copy>
    </target>

You are able to access build.xml file in Files view.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/editearbuild1.png

After editing you should see something like this.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/editearbuild2.png

Build Script Modifying (6.x)

    <property name="dbreader.home" value="../"/>
    
    <target name="build-dbreader-jnlp">
        <java classname="org.apache.tools.ant.Main" dir="${dbreader.home}" failonerror="true" fork="true">
            <jvmarg value="-Dant.home=${ant.home}"/>
            <arg value="build-jnlp"/>
            <classpath path="${java.class.path}"/>
        </java>
    </target>
    
    <target name="pre-dist" depends="build-dbreader-jnlp">
        <!-- dbreader.home must point to DatabaseReader Application home directory -->

        <mkdir dir="${build.dir}/lib"/>
        <copy todir="${build.dir}/lib">
            <flattenmapper/>
            <fileset dir="${dbreader.home}/build/jnlp/app" includes="**/*.jar" />
            <fileset dir="${dbreader.home}/build/jnlp/branding" includes="**/*.jar" />
            <fileset dir="${dbreader.home}/build/jnlp/netbeans" includes="**/*.jar" />
        </copy> 
    </target>

If you're not using Mac then also don't forget to exclude "Apple Application Menu" module (module suite project properties -> libraries -> PlatformX). Also make sure you're including only modules from platformX cluster.

Generating Entity Classes From Database

We have dbreader-ear project infrastructure prepared. Now we have to generate entity classes from sample database. Right click on dbreader-ear-ejb project in Project tab and select New -> Entity Classes From Database. In wizard chose as datasource jdbc/sample datasource and select CUSTOMER table.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/generateentity1.png

On the next wizard panel type package for entity classes. Type db. Then Click on create persistence unit. Persistence unit dialog will appear. Click on Create. Now finish the wizard by clicking on the Finish button.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/generateentity2.png

Now we have generated entity classes from jdbc/sample database. Under dbreader-ear-ejb project you can see generated classes.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/generateentity3.png

Create Session Bean

We need to create stateless session bean with remote interface to communicate with persistence unit. Create one and call it DataBean.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/createsession1.png

When you have session bean created add business method called getData. You are able to do it by right clicking on the editor pane (in DataBean.java file opened) and select EJB Methods -> Add Business Method. Pass through the wizard and create getData method which returns java.util.List.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/createsession2.png

Now use entity manager. Once again do a right click on the editor pane and select Persistence -> Use Entity Manager. Entity manager code is generated. Now implement getData method.

    public List getData() {
        //TODO implement getData
        return em.createQuery("SELECT c FROM Customer c").getResultList();
    }

After that you should see in editor (in DataBean.java file) something like this.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/createsession3.png

Modify Application Client

We prepared EJB module and now we have to implement functionality into dbreader-ear-app-client Application Client module. Open Main.java file in dbreader-ear-app-client project.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/modifyappclient1.png

Now call your session bean DataBean. Right click on editor pane and select Enterprise Resources -> Call Enterprise Bean. In the dialog select your DataBean and click OK.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/modifyappclient2.png

Now we need to implement main method and create getCustomers method. Before that add <dbreader_project_home>/build/jnlp/netbeans/boot.jar (or <dbreader_project_home>/build/jnlp/netbeans/org-netbeans-bootstrap/boot.jar in case of NetBeans 6.1) file on classpath. Do it by right clicking on dbreader-ear-app-client project and select Properties. There select Libraries and then click on Add JAR/Folder and in open file dialog select boot.jar file. Don't forget to uncheck the checkbox. We do not want to package this file with dbreader-ear-app-client module. Actually you have to run build-jnlp target on dbreader suite. Before that please perform step Set Up Suite. Then you can right click on dbreader project and select Build JNLP Application.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/modifyappclient3.png

Implement main method by this code.

    public static void main(String[] args) {
        try {
            String userDir = System.getProperty("user.home") + File.separator + ".dbreader";
            org.netbeans.Main.main(new String[] {"--branding", "dbreader", "--userdir", userDir});
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

Now create getCustomers static method.

    public static List getCustomers() {
        return dataBean.getData();
    }

After doing this you should see something like this in editor pane.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/modifyappclient4.png

Great ! We have finished development of the dbreader-ear Enterprise Application. Let's go to develop NetBeans Modules.

NetBeans Modules Development

Set Up Suite

Now we set up the dbreader NetBeans module suite. We have to set it as standalone application and also we are able to change splash screen. Right click on dbreader project and select Properties. There select Application and then click on the Create Standalone Application.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/setupsuite1.png

Also you are able to set up your own splash screen. Do it by same way and under the Application node in project Properties click on Splash Screen.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/setupsuite2.png

Set Up Module

Now we set up the customers NetBeans Module. We have to add dbreader-ear-ejb.jar, dbreader-ear-app-client.jar and javaee.jar on compile classpath. First of all set sources level of the module to 1.5. Right click on customers project and on the first panel select 1.5 for sources level.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/setupmodule1.png

Open project.properties file from project tab.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/setupmodule2.png

Add this code into project.properties file. Of course use your own path to dbreader and glassfish.

cp.extra=\
/home/marigan/temp/dbreader/dbreader-ear/dbreader-ear-ejb/dist/dbreader-ear-ejb.jar:\
/home/marigan/temp/dbreader/dbreader-ear/dbreader-ear-app-client/dist/dbreader-ear-app-client.jar:\
/home/marigan/apps/glassfish/lib/javaee.jar

After that you should see something like this in editor pane.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/setupmodule3.png

Create Window Component

Now we create a new window component which will serve as viewer for database data. Right click on customers project and select New -> Window Component. On the first wizard panel choose editor as Window Position and select Open on Application Start.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/createwindow1.png

On the second panel specify component Class Name Prefix (use Customers) and finish the wizard.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/createwindow2.png

After that you should see this in Project tab.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/createwindow3.png

Write Customers Top Component Logic

We have to write application logic for customers top component. Open CustomersTopComponent.java file in design mode and drag and drop a jTable component from palette into it.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/writelogic1.png

Now switch into source view and modify constructor and add initData method.

    private CustomersTopComponent() {
        initComponents();
        setName(NbBundle.getMessage(CustomersTopComponent.class, "CTL_CustomersTopComponent"));
        setToolTipText(NbBundle.getMessage(CustomersTopComponent.class, "HINT_CustomersTopComponent"));
//        setIcon(Utilities.loadImage(ICON_PATH, true));
        
        initData();
    }
    
    private void initData() {
        List<Customer> data = Main.getCustomers();
        
        Object[][] rows = new Object[data.size()][3];
        int i = 0;
        
        for (Customer c : data) {
            rows[i][0] = c.getName();
            rows[i][1] = c.getEmail();
            rows[i++][2] = c.getPhone();
        }
        
        Object[] colums = new Object[] {"Name", "E-mail", "Phone"};
        
        jTable1.setModel(new DefaultTableModel(rows, colums));
    }

After that you should see something like this.

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/writelogic2.png

Run Application

Great job !! Everything is done. Now you can run your application. Right click on dbreader-ear project and select Run Project. Wait a minute do build and glassfish to start. Enjoy your application :o)

http://wiki.netbeans.org/wiki/attach/DevFaqAppClientOnNbPlatformTut/runapp.png

Debug Application

There of course comes a time when you need to debug your application. Debugging the server side is relatively easy: start Glassfish in Debug mode and simply "Attach" to it ('Attach Debugger...' from the 'Run' menu).

Debugging the client side is a little harder. On NetBeans 6.1, simply right-clicking on the EAR project and select "Debug" doesn't seem to work. It fails with error messages saying that your classes from your other modules are not found on the classpath. Manually referring to them isn't sufficient either, because once you've done that the Ant debug script will complain about not finding classes belonging to the Platform modules you depend on.

The simple solution is to add the following 2 Ant targets to your build.xml :

   <target name="Debug platform (Attach-debug)" description="Debug the platform, need to attach the debugger once the JVM is started"
            depends="-debug-init-jvm,run"/>

   <target name="-debug-init-jvm">
        <property name="j2ee.appclient.jvmoptions.param" value="-agentlib:jdwp=transport=dt_socket,server=y,address=9009"/>
    </target>
To run the "Debug platform (Attach-debug) target, right-click on the 'build.xml' file in the "Files" (can't see it from the "Project") view and select it from the "Run target" menu item. Once the JVM is started (the console stops scrolling but the program is still running), attach to the JVM just like when debugging the server.

The idea is to call the already-existing "run" target, but specify arguments to be passed to the JVM when its launched. The above arguments will launch the JVM in debug mode, asking it to wait for a connection (default behavior) and the address will be 9009. You could even specify a different port number if you want to run Glassfish in debug mode at the same time (note that the debugger can only attach to one JVM at a time, so you have to detach from the client and then attach to the server).

For more details about the JPDA debugging arguments, see here.

What are some of the hooks in the application's lifecycle I can plug into?

One major difference between developing a platform application and a monolithic Java application is that there's no main method. This sometimes leaves developers wondering where they can insert their own code. This FAQ entry describes some places where this is possible.

Although a bit drastic for most cases, you can replace the main class used to start NetBeans (DevFaqPlatformAppAuthStrategies) with your own class and then delegate back to NetBeans' normal main class. This offers you a hook early in the startup sequence without having to modify the launchers or shell scripts.

Any module may provide a ModuleInstall class. The validate method will be called before your module is even loaded, so it's the first module-level hook typically available in the startup sequence. Note that many services and classes offered by the platform are unlikely to be initialized at this point.

A short time afterwards, the restored() method will be called on each ModuleInstall class. More services and classes will be initialized at this point than with the validate() method, but the GUI will probably not yet be realized. You can post some code to be executed when the UI is fully loaded like this:

@Override public void restored() {
    WindowManager.getDefault().invokeWhenUIReady(
        new Runnable() {
            public void run() {
                // any code here will be run with the UI is available
                SomeTopComponent.findInstance().open();
            }
        });
}

The ModuleInstall class offers two methods which let you plug into the exit sequence. The closing method is called first and requires that you return a boolean value. If true, then your module agrees to be closed, but if false, then you will prevent the exit sequence from continuing. The close method is called after all ModuleInstall classes return true from the closing method and is the final hook in which modules can participate in the application's lifecycle.

Note that providing a ModuleInstall class will increase total startup time a little, even if you have taken care to execute any long-running tasks from its methods in a background thread. It is always preferable to register objects declaratively, and/or run procedural code when it is first needed rather than eagerly.

Another major class in platform development is the TopComponent class. It offers several methods which allow you to hook into its lifecycle.

Here are some events you can hook into for when a TopComponent is opened:

When you set focus on a TopComponent, the componentActivated method is called. Likewise, the componentDeactivated method is called when focus is moved away from that TopComponent.

Here are some events you can hook into for when a TopComponent is closed:

It seems that the exact sequence in which the opening/closing hooks are invoked could vary, perhaps based on platform. Tom Wheeler listed them above in they order in which he observed them on Windows XP but later found they were invoked in a slightly different order. Likewise, Fabrizio Giudici found that they occurred in yet a different sequence.

Note that you can return false from TopComponent.canClose to prevent the TopComponent from being closed at all.


Applies to: NetBeans 6.5

How can I find Javadoc of Autoupdate API with hints to use it?

Since NetBeans 6.0 there is a public API to use Autoupdate Services. Autoupdate API provides several services to applications built on NetBeans Platform: it allows users to download and install available updates of installed plugins, search and install new plugins from subscribed Update Centers, browsing and manipulating plugins already installed. To use these services NetBeans Platform supplies a GUI (Plugin Manager in Tools->Plugins menu item) to easy call these services. AutoUpdate API also cares about registration of Update Centers.

Other resources

How can I update the splash screen, title bar and other branding items via AutoUpdate?

It's easy to distribute new and/or updated modules via AutoUpdate, but you might also like to update branding items like the splash screen and version number in the application's title bar to reflect the changes.

To do this, create a new module in your suite. Edit its build.xml to add the following, but replace "app" with the branding token for your application (see your suite's project.properties if you don't know the value to use):

<target name="netbeans-extra" depends="init">
    <branding cluster="${cluster}" overrides="${suite.dir}/branding" token="app"/>
</target>

Next, add the following to the modules' nbproject/project.properties file, again replacing "app" with your branding token. You may also need to update the list of files in extra.module.files to include only those JARs which your suite actually brands.

nbm.needs.restart=true
nbm.is.global=true
nbm.target.cluster=app
extra.module.files=\
        core/locale/core_app.jar,\
        modules/ext/locale/updater_app.jar,\
        modules/locale/org-netbeans-core-windows_app.jar,\
        modules/locale/org-netbeans-core_app.jar,\
        modules/locale/org-netbeans-modules-autoupdate-ui_app.jar,\
        modules/locale/org-netbeans-modules-favorites_app.jar,\
        modules/locale/org-netbeans-modules-javahelp_app.jar,\
        modules/locale/org-netbeans-modules-projectui_app.jar

Finally, run the "nbms" Ant target on your suite and deploy the updates to your AutoUpdate center.

Note that you may encounter problems doing this in NetBeans 6.0.

Thanks to Matteo Di Giovinazzo for sharing how to do this on the dev@openide list.

What is a background thread and why do I need one?

As with most user interface (UI) toolkits, Swing is single threaded. That means there is one and only one thread that should create or alter the state of UI components, and that is the AWT Event Dispatch Thread (also known as the EDT or the "event thread"). It processes things like key and mouse events and calls components to respond to them.

This also means that code that responds to a key or mouse event, or some call triggered by one, should run very quickly, because the user can by typing or clicking, but the entire application is blocked from responding to more events until your code exits. So sometimes you will want to move expensive or slow work onto a background thread.

A background thread is any thread that is not the event thread.

If you are running on some other thread, but need to modify some component, a simple way to do this is EventQueue.invokeLater(new Runnable() { public void run() { //this code can modify components } });

Note that the caveat about Swing includes creating components - it is provably not safe to even construct Swing components on a background thread, because of synchronization on Component.getTreeLock().

Becoming a Proficient NetBeans Module Developer

NetBeans has a learning curve. The goal of this article is to get you over the basic humps quickly. Being proficient does not necessarily mean knowing everything there is to know. It means being able to find what you need to know quickly when you need it. Here are some pointers.

All of the documents linked here are also available from del.icio.us.

It's a good thing to bookmark.

Javadoc

The reference documentation for all of NetBeans APIs can be found on the web here: http://www.netbeans.org/download/dev/javadoc/

If you want a local copy of it, you can either download it from the update center, or build it from your source checkout

cd $NB_SRC_ROOT
ant build-javadoc

Using the Javadoc

Notice the list of APIs in the upper left in the javadoc. These restrict the list of classes to a single API. /Also notice the link that says _javadoc_ next to each API name. It's important! This links to the overview page for each API. That page contains a list of changes, an architecture description, and other very useful stuff!/

NetBeans Tutorials

There are a huge number of tutorials. Do at least some of them - step by step.

FAQs

There is a huge Frequently Asked Questions for Module Developers list. It is worth bookmarking.

Getting the Source Code

Some people claim that they should never need to look at source code - documentation should suffice. That's just silly. The NetBeans codebase is a treasure-trove of examples of how to do things.

Since the end of January 2008 the NetBeans sources are stored in Mercurial repository at hg.netbeans.org.

You can see useful documentation about Mercurial and also about its specifics for NetBeans repository in HgMigrationDocs wiki topic. If you are already familiar with Mercurial you cat go directly to HgHowTos topic.

You will end up with a large number of directories representing top-level NetBeans projects. Most of them will be openable as projects in NetBeans.

Here's how to build it.

The build of NetBeans will be created in nbbuild/netbeans.

How To Find Useful APIs

See the tasks to APIs faq for a list of common tasks and what APIs you will want to use to accomplish those tasks.

Get the Platform Examples

There are a large number of samples. Many of these correspond to the tutorials. You can find the samples in module platform in main/misc repository at hg.netbeans.org. They are in the platform/samples/ subdirectory. The platform/samples/ folder can be browsed online here.

Build Platform from Sources

First get platform sources from download page or use Hg client as described in HgHowTos.

To build platform run

cd $NB_SRC_ROOT
ant build-platform

Mining the NetBeans Source Code for Examples

For most things you will need to do, there is some module that does something similar already. For example, say that you want to show a window that shows the contents of some random directories on disk or some registry of objects your module creates. The core/favorites module provides the Favorites window which does exactly this. A bit of intuition and a willingness to open a couple of projects is all it takes to find examples of many things. Often a good place to start is simply to open the source for a class you think you want to use and run Find Usages on it.

Use the Mailing Lists

If you have questions, the best place to go is the developer mailing list. Click this link to subscribe. You can also get there via a newsreader by going to news://news.gmane.org or access them on the web via Nabble. Ask questions, and when you can answer them, do that too. There is a very healthy and helpful community there.

How to call EJB from NetBeans module

This How-To is based on GlassFish EJB Faq

How to call EJB from Java EE Application Client built on top of NetBeans Platform

Important: Application Client must be created as it is described in Java EE Application Client on top of the NetBeans Platform Tutorial otherwise this will not work

Example

protected mypkg.MySessionBeanRemote lookupMySessionBean() {
    try {
        javax.naming.Context c = new javax.naming.InitialContext();
        return (mypkg.MySessionBeanRemote) c.lookup("java:comp/env/ejb/MySessionBean");
    } catch(javax.naming.NamingException ne) {
        java.util.logging.Logger.getLogger(getClass().getName()).log(java.util.logging.Level.SEVERE,"exception caught" ,ne);
        throw new RuntimeException(ne);
    }
}
<ejb-ref>
    <ejb-ref-name>ejb/MySessionBean</ejb-ref-name>
    <ejb-ref-type>Session</ejb-ref-type>
    <remote>mypkg.MySessionBeanRemote</remote>
</ejb-ref>

How to call EJB from standalone module/NB platform based application

Call EJB on GlassFish

Example

run.args.extra=-J-da -J-Dorg.omg.CORBA.ORBInitialHost=localhost -J-Dorg.omg.CORBA.ORBInitialPort=3700 \
               -cp:a $GLASSFISH_HOME/lib/appserv-rt.jar:$GLASSFISH_HOME/lib/appserv-ext.jar:\
                     $GLASSFISH_HOME/lib/appserv-deployment-client.jar:$GLASSFISH_HOME/lib/javaee.jar:\
                     $GLASSFISH_HOME/lib/jmxremote_optional.jar:someejb.jar
to module suite project.properties
// for EJB 3.0 bean
protected mypkg.MyBeanRemote lookupMyBeanRemote30 throws NamingException {
    javax.naming.Context ic = new javax.naming.InitialContext();
    return (mypkg.MyBeanRemote) ic.lookup("mypkg.MyBeanRemote");
}

// for EJB 2.1 and/or earlier
protected mypkg.MyBeanRemote lookupMyBeanRemote21 throws NamingException {
    javax.naming.Context ic = new javax.naming.InitialContext();
    Object remote = c.lookup("java:comp/env/ejb/MyBean");
    mypkg.MyBeanRemoteHome rv = (mypkg.MyBeanRemoteHome) PortableRemoteObject.narrow(remote, mypkg.MyBeanRemoteHome.class);
    return rv.create();
}


Applies to: NetBeans 5.5, 6.0, 6.1

Platforms: all

Generally, you can change the look and feel either by passing command line arguments, e.g. netbeans --laf javax.swing.plaf.metal.MetalLookAndFeel or do so programmatically on startup in a module's ModuleInstall class (generally if you're installing a custom look and feel, you probably want to have a separate module to do that; some look and feels provide NetBeans modules to make it easy to use them.

If you want to test running with a different look and feel during development of your application, and you know it will be on the application's classpath, see the example in DevFaqPassCommandLineArgumentsAtDevTime for how to include --laf in the runtime arguments to your module suite.

How do I change the appearance of the menu items and toolbar buttons for my action?

The main menus and toolbars of a NetBeans Platform application are configured based on the contents of folders in the system filesystem. There are many benefits of this approach, such as improved performance since the platform can create all the menus and toolbars without having to actually instantiate the actions with which they are associated.

Because the platform builds the menus and toolbars for you, it might seem like you have little control over how those items appear. In practice, you have a great deal of control over the appearance for any action you create. Typically, actions in a NetBeans platform application which will be shown in the main menu or toolbar extend from CallableSystemAction, perhaps indirectly through its CookieAction subclass.

In the code you've written for one of these actions, you can override getMenuPresenter to change the appearance of the menu item associated with your action and/or override getToolbarPresenter to change the appearance of the toolbar component associated with your action.

For example, if you wanted to make the menu item for your action have a blue background and yellow text, you could do something like this:

@Override
public JMenuItem getMenuPresenter() {
    JMenuItem item = super.getMenuPresenter();
    item.setOpaque(true);
    item.setBackground(Color.BLUE);
    item.setForeground(Color.YELLOW);
    return item;
}

Note that if you are changing the menu item to support a tooltip, the object returned by getMenuPresenter needs a property change listener on the action's SHORT_DESCRIPTION so that its tooltip value is updated correctly upon change.

Note about using alternate components in the main menu: If you want your action to work properly on Mac OS, you probably don't want to return anything other than a JMenu or JMenuItem from getMenuPresenter() if you implement Presenter.Menu. In general, Swing allows you to treat menu popups as generic Swing containers you can put what you like into. This is not true at all of the Mac OS screen menu bar - it expects normal menu items, and will not handle unusual contents for menus.

How can I change my node's appearance?

It's pretty simple to change the font color, style or weight for your node's label. Simply override getHtmlDisplayName and provide some HTML in your return value. (An example can be found in this tutorial.) Here is another example:

public class MovieNode extends AbstractNode {

    private Movie movie;

    public MovieNode(Movie key) {
        super(Children.LEAF, Lookups.fixed(new Object[]{key}));
        this.movie = key;
        setName(key.getTitle());
        setDisplayName(key.getTitle());
        getHandle();
        setIconBaseWithExtension("org/nb/marilyn/pics/marilyn.gif");
    }

    @Override
    public String getHtmlDisplayName() {
        return "<b>" + this.getDisplayName() + "</b>";
    }
    
}

The javadoc for the HtmlRenderer class explains what subset of HTML is supported. You can also change the icon's node by overriding various methods such as getIcon(int type) or getOpenedIcon().

It's also possible, but far more difficult, to control other aspects of the node's appearance; for example, drawing a box around the node or changing its background color. To do this you must create or modify the explorer view in which the node is rendered. Fabrizio Giudici posted code that illustrates this on the dev@openide list.

How Can I Change the NetBeans Splash Screen Shown When A User Installs a Module Requiring Restart?

The splash screen is here:

autoupdate.services/libsrc/org/netbeans/updater/resources/updatersplash.gif

You can brand this in your application by following the instructions in this FAQ entry.


Applies to: NetBeans 6.5, 6.7

What class loaders are created by the module system?

Overview

This FAQ item should be a companion to the main classpath documentation. Please refer to the original document for additional details.

Class loaders in the NetBeans platform

There are basically three main class loader types used in the platform. Most code is loaded by module class loaders. In special cases the "system" class loader can be used, when you need access to resources from unknown modules. Resources directly on the classpath from the launch script (mainly platform*/lib/*.jar) are loaded by the application loader. (There are also bootstrap and extension loaders in the JRE, and the platform has a special loader for a couple of JARs in platform*/core/*.jar.)

Most of the class loaders in the NetBeans platform are multi-parented class loaders. This means that the class loader can have zero or more parents. org.netbeans.ProxyClassLoader implements the search across multiple parents.

Module class loader

Every module loaded by the module system has its own class loader. This loader loads resources primarily from the module's JAR. The application loader is an implicit parent of each module loader.

The module loader is able to load from additional JARs (besides delegating to various parents):

The implementation class is org.netbeans.StandardModule$OneModuleClassLoader.

System class loader

The "system" loader loads no resources on its own, but has as its parents all enabled module's class loaders. It is accessible via Lookup.getDefault().lookup(ClassLoader.class) or by using the fact that it is the context loader on all threads by default: Thread.currentThread().getContextClassLoader()

Application class loader

This class loader is set up by the launch script (or by javaws if running in JNLP mode). It can load classes from lib/*.jar in specified clusters. It is generally discouraged to use this loader for your own classes, but it is sometimes needed e.g. for Look & Feel classes (which must be loaded very early during the startup sequence).

Example

Take a very simple module a:

Manifest-Version: 1.0
OpenIDE-Module: org.netbeans.modules.a

and module b depending on a:

Manifest-Version: 1.0
OpenIDE-Module: org.netbeans.modules.b
OpenIDE-Module-Module-Dependencies: org.netbeans.modules.a
Class-Path: ext/library-b-1.1.jar

Classes in org-netbeans-modules-a.jar will be loaded in a's module class loader. Classes in both org-netbeans-modules-b.jar and library-b-1.1.jar will be loaded in b's module loader, and can refer to classes in org-netbeans-modules-a.jar.


Applies to: NetBeans 6.5

I have written a module for NetBeans. Can I contribute it to the NetBeans project?

Yes. In fact, once you have some code written, request the developer role on contrib.netbeans.org (you need to have an account and be logged in to see the link), so you have write access to CVS there, and go ahead and check it in. You will need to sign a Contributor Agreement to get CVS write access.

For more info on how to start module projects or join existing ones, see the contributing page on netbeans.org .


If you have initially written the module as a standalone module project using the NB 5.0 IDE, beware that the format for module projects inside the netbeans.org CVS tree is slightly different. To convert a standalone module project to a netbeans.org module:

  1. . Close your module and shut down the IDE, just to be safe.
  1. . Copy the module into the desired location in the netbeans.org CVS source tree.
  1. . Open nbproject/project.xml and delete the line <standalone/>.
  1. . Delete =nbproject/genfiles.properties=, =nbproject/platform.properties=, and =nbproject/build-impl.xml=.
  1. . Open build.xml and change <import file="nbproject/build-impl.xml"/> to <import file="../../nbbuild/templates/projectized.xml"/> (assuming a second-level module like =contrib/foo=; adjust number of ../ occurrences as needed).

Now you ought to be able to open the new project in the IDE and work with it as usual.

If you had specified an explicit NBM license (=license.file=) before, you might just remove it - netbeans.org modules by default use nbbuild/standard-nbm-license.txt which is appropriate for any SPL module with no external (non-SPL) components.

If you had a module suite project with several module suite component projects, just discard the suite project (netbeans.org modules cannot reside in suites) and copy the component module projects into the netbeans.org CVS tree. You will be deleting <suite-component/> from project.xml and deleting suite.properties rather than platform.properties but the process is otherwise similar.

A future release of the module development support should permit you to simply select Move Project or Copy Project from the GUI and handle these format changes automatically.

How do I create a TopComponent to show an explorer view?

Explorer views are generic Swing components, not subclasses of TopComponent , the Swing panel class that is used for top level components (tabs) in the main window. So an explorer view component is added to a TopComponent, using the TopComponent as a Swing container for the view.

A little bit of plumbing is needed to wire up an explorer view to the global Node selection so that code that is sensitive to selection such as context sensitive actions . Basically you want the TopComponent to expose the selection in your Explorer View so that when your view has focus, the global selection that affects everything will be whatever the user selects in your view.

In olden times, there was a convenient class called ExplorerPanel (now in org.openide.compat ) which would do this for you; due to a tragedy of being in the wrong package, it is now deprecated, but the required plumbing is not hard:

public class MyView extends TopComponent implements ExplorerManager.Provider {
    private final ExplorerManager manager = new ExplorerManager();
    private final JComponent view = new BeanTreeView();
    public MyView() {
        setLayout (new BorderLayout());
        add(view, BorderLayout.CENTER);
        manager.setRootContext(someNode);

        // Probably boilerplate (depends on what you are doing):
        ActionMap map = getActionMap();
        map.put(DefaultEditorKit.copyAction, ExplorerUtils.actionCopy(manager));
        map.put(DefaultEditorKit.cutAction, ExplorerUtils.actionCut(manager));
        map.put(DefaultEditorKit.pasteAction, ExplorerUtils.actionPaste(manager));
        // This one is sometimes changed to say "false":
        map.put("delete", ExplorerUtils.actionDelete(manager, true));
        // Boilerplate:
        associateLookup(ExplorerUtils.createLookup(manager, map));
    }
    // This is optional:
    public boolean requestFocusInWindow() {
        super.requestFocusInWindow();
        // You will need to pick a view to focus:
        return view.requestFocusInWindow();
    }
    // The rest is boilerplate.
    public ExplorerManager getExplorerManager() {
        return manager;
    }
    protected void componentActivated() {
        ExplorerUtils.activateActions(manager, true);
    }
    protected void componentDeactivated() {
        ExplorerUtils.activateActions(manager, false);
    }
}

The primary difference between the above code and ExplorerPanel is that ExplorerPanel automagically persisted paths from the selected nodes to the root, so that it could be deserialized on restart with the same selection it had before shutdown (assuming that selection still existed - this was never terribly robust).

-- Main.timboudreau w/ cut & paste from Jesse Glick - 17 Sep 2005

How do I read the fontsize value from my netbeans module?

Integer fontSize = (Integer) UIManager.get("customFontSize");
if (fontSize != null) {
    //--fontsize was passed - adjust your fonts accordingly
}

You can also just set your font with UIManager.getFont("controlFont") which will be set according to --fontsize, but sometimes you do need the actual value for using fixed width fonts or computing fixed cell height for an unusual font or similar.

The code in core.swing.plaf processes the --fontsize argument and sets the UIManager key/value pair if it was passed on startup.

How to implement custom IOProvider

You need to extend IOProvider and override/implement following methods:

// registration, you can change default instance returned by IOProvider.getDefault() by adjusting position
@org.openide.util.lookup.ServiceProvider(service=org.xxx.MyIOProvider.class, position=200)
public final class MyIOProvider extends IOProvider {

    // unique name of your provider
    private static final String NAME = "My IO provider"; // NOI18N

    public OutputWriter getStdOut() {
        // implement
    }

    public InputOutput getIO(String name, boolean newIO) {
        // implement
    }
        
    @Override
    public InputOutput getIO(String name, Action[] toolbarActions) {
        // override
    }

    @Override
    public InputOutput getIO(String name, Action[] additionalActions, IOContainer ioContainer) {
        // override
    }

    @Override
    public String getName() {
        return NAME;
    }
}
Add "OpenIDE-Module-Provides: org.openide.windows.IOProvider" to your module manifest (manifest.mf file) to inform that your module provides IOProvider service. Then instance of your provider could be obtained by IOProvider.get("My IO provider")
Applies to: NetBeans 6.7

How can I use AutoUpdate to deploy updates and new modules for my application?

An AutoUpdate server (also called an AutoUpdate Center or AUC) it not as complicated as it sounds. It's just a server which contains a set of modules and an XML file that describes them all (the autoupdate XML descriptor).

There are four main steps in setting up your AUC, all of which are quite simple:

1. Deciding where you will host it.

This is typically just a Web server (Tomcat, Apache, etc.) which has a directory that's writable by you. You will need to know how to map that directory to the URL which will be used to request the files you add there; for example, you might put a file com-example-foo.nbm in the /var/www/html/mysite directory and that will map to http://www.example.com/mysite/com-example-foo.nbm.

2. Creating your NBM files and autoupdate XML descriptor.

Just right-click on your suite and choose "Create NBMs", or if you prefer the command line, type ant nbms from a command prompt in the root directory of your suite. This will create an NBM file for every module in your suite and will also generate the autoupdate XML descriptor which describes each module.

3. Uploading your NBM files and autoupdate XML descriptor to the server.

You can do this manually at first, but later you might wish to automate this using Ant's support for FTP or scp, or simply copy files via shares or NFS mounts. Which method you choose will largely be dictated by what your Web server's operating system supports.

4. Making sure your application knows about it.

There is a wizard for this in recent versions of the NetBeans IDE. Right-click on one of the modules in your suite (or add a new one, if you prefer) and choose New -> Other. Select "Module development" in the dialog, choose "Update Center" and then click the Next button. Specify the URL of the update center descriptor (i.e. the URL of the file you uploaded in step 3) and a display name of your choice, and then click Finish.

Note: Whenever you need to deploy an update, be sure you have incremented the module's specification version number and then repeat steps 2 and 3 above. Users should be able to easily install the updates you've published. There is more explanation of module versioning and dependencies elsewhere in this FAQ.

How do I handle cut, copy and paste?

The subject of properly handling cut, copy and paste is underdocumented in modern material on the NetBeans Platform and I am not aware of any clear and concise examples that show how to handle all aspects of these common actions. Anyone who can improve these shortcomings would be doing a great service for the NetBeans Platform developer community.

The Nodes API documentation provides some guidance, while chapter 14 of NetBeans: The Definitive Guide goes into greater detail. Although some parts of NetBeans: The Definitive Guide are now outdated, the portions related to the Nodes API are likely still relevant.

What is a DataLoader?

DataLoaders recognize files by type - type is typically determined by the file extension, though it can depend on content for things like XML files. They are the mechanism by which NetBeans recognizes files.

DataLoaders are factories for DataObjects. Typically there is a 1:1 mapping between file-type:DataLoader-subclass and a 1:1 mapping from files:DataObject instances for files that are visible in the UI. When a file is encountered, a DataLoader is found and used to produce a DataObject for that file.

Modules that provide the ability the system to open (or otherwise use) files of a particular type will register DataLoaders for those types. When the system needs to display a file in the UI, or when some code calls DataObject.find(someFileObject), the registered loaders are queried and one of them will claim it, and create a DataObject to represent it. So typically for each file type (as defined by file name extension, or XML subtype) there is a matching DataObject subclass.

DataLoaders are registered in the module manifest - for example:

Name: org/netbeans/modules/povray/PovDataLoader.class
OpenIDE-Module-Class: Loader

Note that the empty line above the Name: line must be present; create such entries at the bottom of the module manifest.

What is a DataObject?

DataObjects wrap FileObjects. A FileObject is just a container for data; it happens to have a MIME type, but like java.io.File, it doesn't know or care what kind of file it represents, or what the file is. DataObject is part of the Loaders API - a good overview of this API can be found here.

A DataObject represents one or more (typically only one) FileObjects. A DataObject knows what kind of a file it represents; it may represent the parsed contents of a file such as a .java file; or, as in the case of InstanceDataObject the file name may provide all the information it needs to be useful.

DataObjects are produced by DataLoaders, which modules register for specific file types. So for each file type, there is (usually) one DataLoader; and for each file of that type, there is (typically) one DataObject.

DataObjects are seldom referred to by type - if you are casting a DataObject to its implementation class, you are probably doing something wrong. This is a general rule for which there can be exceptions, but is especially true if you're doing the cast from code in a different module than the one in which the DataObject was defined. The usage pattern is to ask a DataObject for instances of interfaces that are the things your code will actually interact with. The method for doing this is dataObject.getCookie(Interface.class) (or in newer versions of NB, dataObject.getLookup().lookup(Interface.class)).

As a simple example, the NetBeans APIs define an interface org.openide.cookies.OpenCookie. It has one method, open(). That method will open the file in the editor. What exactly will happen when open() is called is entirely up to the module that implements the DataObject. The rest of the system does not need to know any of the implementation details - it just needs to know if the DataObject has an OpenCookie. If it does, then the Open action on its context menu can be enabled, and that action will call ((OpenCookie) theDataObject.getCookie(OpenCookie.class)).open().

The name cookie is historical and somewhat unfortunate; the getCookie() pattern is an older variation on the Lookup pattern for service discovery. The two are equivalent, with the exception that getCookie() requires all returned objects to implement the empty Node.Cookie marker interface, and Lookup can return any object. Expect getCookie() to be replaced with a new getLookup() method at some point in the future.

As suggested above, a DataObject may actually represent more than one file - so when you expand a folder in the UI, there may actually be fewer DataObjects in that folder than there are files. This is why, in the NetBeans IDE, a Swing form is represented by a .java file and a corresponding .form file, but the .form file is not visible in the UI; in the past, .properties files have also used this mechanism to present resource bundles in various languages as a single node in the files tree.

However, this ability to represent multiple files with a single DataObject is strongly discouraged for new code and will probably eventually be deprecated - it has serious negative implications for scalability.

How do I get a DataObject for a FileObject?

DataObject.find (theFileObject)

The next button is never enabled when I create my DataObject from a template. Help!

Most likely your DataObject does not put itself into its own CookieSet/Lookup. If you call setCookieSet(), or override getLookup() or getCookie(), this can happen. There are a few parts of NetBeans which will expect Nodes to be present in their own Lookups and DataObjects to be present in theirs. It is always best to make sure they are there. For a DataObject, the code for this is usually as simple as:

getCookieSet().add(this);

How do I get a DataObject for a Node?

DataObject dob = (DataObject) theNode.getLookup().lookup (DataObject.class);
if (dob != null) {
   //do something
}

How do I add an item to for every folder in the system?

There is a folder in the System Filesystem called Loaders. It is where various things are registered that apply to specific DataObject types. For example, there is a folder Loaders/text/x-java that contains things that pertain to Java files (notice that the path is a MIME type). It has an Actions subfolder where you can add actions to the popup menu for Java files.

You may not think of a folder as being a file type, but to NetBeans it is. There is a subfolder Loaders/folder/any/Actions which contains actions that should appear in the popup menu for folders. Just add your action in your layer file to that folder, i.e.

<filesystem>
  <folder name="Loaders">
      <folder name="folder">
          <folder name="any">
            <folder name="Actions">
               <file name="com-foo-module-MyAction.instance"/>
          </folder>
        </folder>
      </folder>
    </folder>
</filesystem>

There is a class under org.netbeans.core that does what I need. Can I call/use/depend on it?

No. Not if you want your module to work in the future. Copy the code instead. If it is a thing that seems generally useful, file an enhancement request requesting an API for the thing you need to do (and make sure there isn't already a supported way to do it).

Anything under org.netbeans.core is non-public, not an API, and subject to change without notice. An API is a contract - an agreement about compatibility. There is no such contract for this namespace, under any circumstances. The class or method you are using may not even exist in the future. Depend on it at your peril.

A perfect example of why not to do this is JProfiler's plugin for NetBeans - it broke very badly across releases because it needlessly depended on the implementation of DialogDisplayer rather than on the API class - so when that class moved, it could no longer link, so the module didn't work.

If you really must use some non-API classes to do what you need to do, use an implementation dependency (DevFaqImplementationDependency) - your module probably won't load in any version except the one it was built against, but at least your users won't get nasty surprises. And ideally, notify the maintainer of the thing you're depending on - they can give you a heads-up if they think they're about to make a change that will break your module.


Applies to: NetBeans 6.5

How can I control when the OK button is enabled?

The NetBeans Dialogs API makes it easy to create consistent dialogs that behave as users would expect. But since you don't directly create the OK button, it may not be obvious how you can enable it or disable it.

You can enable the OK button by calling setValid(true) and disable it by calling setValid(false). This thread from the dev@openide list might also be helpful.

What is the Dialogs API and How Do I Use It?

The Dialogs API provides support for dialogs and wizards.

Whenever you'd use JDialog or JOptionPane in Swing, using the Dialogs API provides some alternatives. These are easier to use as they automatically take care of centering and other display details, but also allow you to later plug in a different implementation of how they're actually "displayed." Instead of showing them on screen, for example, you could override the default DialogDisplayer class to specify your own that logged them to a printer or read them aloud using speech synthesis.

I'll illustrate three of the most common use cases. The first is when you want to simply show a dialog box with some text:

String msg = "There is something you should know..."
NotifyDescriptor nd = new NotifyDescriptor.Message(msg, NotifyDescriptor.INFORMATION_MESSAGE);
DialogDisplayer.getDefault().notify(nd);

For exceptions, you'll use a similar mechanism. The msg argument is optional here:

String msg = "Something bad happened..."
NotifyDescriptor nd = new NotifyDescriptor.Exception(throwable, msg);
DialogDisplayer.getDefault().notify(nd);

And to request simple user input:

String txt = "Name: ";
String title = "State your name";

NotifyDescriptor.InputLine input = new NotifyDescriptor.InputLine(txt, title);
input.setInputText("John Doe"); // specify a default name
Object result = DialogDisplayer.getDefault().notify(input);
if (result != NotifyDescriptor.OK_OPTION) {
    return;
}

String userInput = input.getInputText();

And finally, the DialogDescriptor subclass, handles complex cases (there are many variants here; see Dialog Descriptor's Javadoc for details):

JPanel form = new MyComplexForm();
String msg = "Something bad happened..."
DialogDescriptor dd = new DialogDescriptor(form, msg);
Object result = DialogDisplayer.getDefault().notify(dd);
if (result != NotifyDescriptor.OK_OPTION) {
    return;
}

// you can now examine the form's state...

Can I disable Auto Update (for example, while running tests)?

The IDE often checks for updates on startup. This behavior may not be desired in some cases; for example, when running tests on the GUI, because they can slow the application down or potentially change its behavior from what you expected. In order to prevent the Auto Update check, run the application with the netbeans.full.hack system property set to true. For example, use -J-Dnetbeans.full.hack=true on the command line.

Setting this property has some other side-effects. Among them:

  • The Exit IDE dialog which checks for running processes is not shown on shutdown.
  • When first starting on a user directory, you are not prompted to
    • accept a license
    • register the product
    • submit usage statistics
  • The RSS feed in the Start Page window is suppressed. (In NetBeans 6.7, the Start Page will also not be shown by default).

Functional tests using NbModuleSuite get this property set automatically. So do unit tests using NbTestCase (though they would rarely need it anyway).


Applies to: NetBeans 6.5, 6.7

What are *.settings files?

*.settings files are similar to *.instance files (DevFaqInstanceDataObject), with the difference that they can contain serialized data rather than just default instances. They may also use custom persistence formats according to the Convertors API.

After the introduction of NbPreferences to replace SystemOption, very little new code uses these files, and they should be considered semi-deprecated. They are difficult and error-prone to use, and have a fair amount of overhead. The Window System still requires them to be used for TopComponent persistence.


Applies to: NetBeans 6.5, 6.7

What are *.shadow files?

*.shadow files are mainly used in the system filesystem (DevFaqSystemFilesystem) for configuration data. They are the functional equivalent of Unix symbolic links - a *.shadow file is a pointer to another file whose behavior in every respect except its path and file name is the same as the original.

*.shadow files are commonly used where only a single instance of an object is needed, but it must be registered in multiple folders. For example, a general Action is declared in the Actions/ folder of the System Filesystem. But the action also needs to appear in menus and toolbars, possibly other places. So, rather than create multiple instances of an action, one *.instance file (DevFaqInstanceDataObject) is created in the module's layer file (DevFaqModulesLayerFile), in the Actions/ folder. Then *.shadow files are created in all of the other places the *.instance file would be needed, pointing to the original file.

Declaring a .shadow file in the system filesystem looks like this:

<folder name="A">
    <file name="com-foo-mymodule-MyClass.instance"/>
</folder>
<folder name="B">
    <file name="Shadow1.shadow">
        <attr name="originalFile" stringvalue="A/com-foo-mymodule-MyClass.instance"/>
    </file>
</folder>
<folder name="C">
    <file name="anotherShadow.shadow">
        <attr name="originalFile" stringvalue="A/com-foo-mymodule-MyClass.instance"/>
    </file>
</folder>

Shadow files can also point to real files on disk. For example, the Favorites tab in the NetBeans IDE uses shadow files to link to real directories on disk.


Applies to: NetBeans 6.5, 6.7

How do I add a drop-down menu to a toolbar button?

To add a drop-down menu to a component in a toolbar, you can either extend CallableSystemAction and override public Component getToolbarPresenter(), or implement javax.swing.Action or any subclass thereof, and implement Presenter.Toolbar which defines that method.

You might want to create a JToggleButton, and when the button is pressed, show a JPopupMenu. (Also try org.openide.awt.DropDownButtonFactory.)

Example:

public class PickDrawingLineAction extends CallableSystemAction {
    private static JToggleButton toggleButton;
    private static ButtonGroup buttonGroup;
    private static JPopupMenu popup;
    private MyMenuItemListener menuItemListener;

    List handledCharts;

    public void performAction() {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                toggleButton.setSelected(true);
            }
        });

    }

    public String getName() {
        return "Pick Drawing Line";
    }

    public HelpCtx getHelpCtx() {
        return HelpCtx.DEFAULT_HELP;
    }

    protected boolean asynchronous() {
        return false;
    }

    public Component getToolbarPresenter() {
        Image iconImage = Utilities.loadImage(
            "org/blogtrader/platform/core/netbeans/resources/drawingLine.png");
        ImageIcon icon = new ImageIcon(iconImage);

        toggleButton = new JToggleButton();

        toggleButton.setIcon(icon);
        toggleButton.setToolTipText("Pick Drawing Line");

        popup = new JPopupMenu();
        menuItemListener = new MyMenuItemListener();

        handledCharts = PersistenceManager.getDefalut()
                        .getAllAvailableHandledChart();

        buttonGroup = new ButtonGroup();

        for (AbstractHandledChart handledChart : handledCharts) {
            JRadioButtonMenuItem item =
                new JRadioButtonMenuItem(handledChart.toString());
            item.addActionListener(menuItemListener);
            buttonGroup.add(item);
            popup.add(item);
        }

        toggleButton.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                int state = e.getStateChange();
                if (state == ItemEvent.SELECTED) {
                    /** show popup menu on toggleButton at position: (0, height) */
                    popup.show(toggleButton, 0, toggleButton.getHeight());
                }
            }
        });

        popup.addPopupMenuListener(new PopupMenuListener() {
            public void popupMenuCanceled(PopupMenuEvent e) {
                toggleButton.setSelected(false);
            }
            public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                toggleButton.setSelected(false);
            }
            public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
            }
        });

        return toggleButton;
    }

    private class MyMenuItemListener implements ActionListener {
        public void actionPerformed(ActionEvent ev) {
            JMenuItem item = (JMenuItem)ev.getSource();
            String selectedStr = item.getText();

            AnalysisChartTopComponent analysisTc =
                AnalysisChartTopComponent.getSelected();

            if (analysisTc == null) {
                return;
            }

            AbstractChartViewContainer viewContainer =
                analysisTc.getSelectedViewContainer();
            AbstractChartView masterView = viewContainer.getMasterView();
            if (!(masterView instanceof WithDrawingPart)) {
                return;
            }

            DrawingPart drawingPart =
                ((WithDrawingPart)masterView).getCurrentDrawing();

            if (drawingPart == null) {
                JOptionPane.showMessageDialog(
                        WindowManager.getDefault().getMainWindow(),
                        "Please add a layer firstly to pick line type",
                        "Pick line type",
                        JOptionPane.OK_OPTION,
                        null);
                return;
            }

            AbstractHandledChart selectedHandledChart = null;

            for (AbstractHandledChart handledChart : handledCharts) {
                if (handledChart.toString().equalsIgnoreCase(selectedStr)) {
                    selectedHandledChart = handledChart;
                    break;
                }
            }

            if (selectedHandledChart == null) {
                return;
            }

            AbstractHandledChart handledChart =
                selectedHandledChart.createNewInstance();
            handledChart.setPart(drawingPart);
            drawingPart.setHandledChart(handledChart);

            Series masterSeries = viewContainer.getMasterSeries();
            DrawingDescriptor description =
                viewContainer.getDescriptors().findDrawingDescriptor(
                    drawingPart.getLayerName(),
                    masterSeries.getUnit(),
                    masterSeries.getNUnits());

            if (description != null) {
                Node stockNode = analysisTc.getActivatedNodes()[0];
                Node node =
                    stockNode.getChildren()
                        .findChild(DescriptorGroupNode.DRAWINGS)
                        .getChildren().findChild(description.getDisplayName());

                if (node != null) {
                    ViewAction action =
                        (ViewAction)node.getLookup().lookup(ViewAction.class);
                    assert action != null :
                        "view action of this layer's node is null!";
                    action.view();
                }
            } else {
                /** best effort, should not happen */
                viewContainer.setCursorCrossVisible(false);
                drawingPart.setActived(true);

                SwitchHideShowDrawingLineAction.updateToolbar(viewContainer);
            }

        }
    }

}
You can add the built-in Java code completion from the Netbeans 6 Java editor to any arbitrary JEditorPane. See the code below for how this can be achieved. Note that Netbeans Java editor functionality is derived from an underlying FileObject, so we are essentially creating a dummy Java FileObject and tying our JEditorPane document in with the appropriate hooks.


The end result of this code is that we create a Java context for our JEditorPane. This context initializes code completion with a default class path, and that grants us access to the standard Java APIs (i.e. the code completion box can include classes such as java.lang.String, java.util.List, etc.). However, this context has no visibility into any additional jars nor Java projects. In order to expand this default Java context, you will need to create your own class path provider (see the
"Java Support APIs" module).


First, let's take a look at some of the classes we'll be using:


Now we're ready to take a look at the actual code:


        JEditorPane editorPane = new JEditorPane();

        // This will find the Java editor kit and associate it with
        // our editor pane. But that does not give us code completion 
        // just yet because we have no Java context (i.e. no class path, etc.).
        // However, this does give us syntax coloring.
        EditorKit kit = CloneableEditorSupport.getEditorKit("text/x-java");
        editorPane.setEditorKit(kit);
        
        // You can specify any ".java" file.
        // If the file does not exist, it will be created.
        // The contents of the file does not matter.
        // The extension must be ".java", however.
        String newSourcePath = "tmp.java";

        File tmpFile = new File(newSourcePath);
        FileObject fob = FileUtil.createData(tmpFile);

        DataObject dob = DataObject.find(fob);
        editorPane.getDocument().putProperty(
                Document.StreamDescriptionProperty, 
                dob);
        
        // This sets up a default class path for us so that
        // we can find all the JDK classes via code completion.
        DialogBinding.bindComponentToFile(fob, 0, 0, editorPane);

        // Last but not least, we need to fill the editor pane with
        // some initial dummy code - as it seems somehow required to
        // kick-start code completion.
        // A simple dummy package declaration will do.
        editorPane.setText("package dummy;");

How can I find the currently open document in the selected editor?

JTextComponent ed = org.netbeans.api.editor.EditorRegistry.lastFocusedComponent();
Document doc = ed.getDocument();

How is MimeLookup composed?

In order to get MimeLookup you have to supply MimePath. With the default MimeLookup implementation provided by Netbeans the contents of MimeLookup is defined by a hierarchical structure of folders on the system FileSystem. The structure starts in the Editors folder and then follows all the components of the MimePath you have supplied.

For example if you ask for MimeLookup for the following MimePath of text/x-java you will get Lookup with contents from the following folders:

    Editors/text/x-java
    Editors

As you can see MimeLookup for text/x-java contains not only editor features registered for the text/x-java mime type itself, but it also inherits general features registered for an empty MimePath (i.e. in the root of the hierarchy).

The inheritence algorithm used for composing MimeLookup for a given MimePath supports more than just simple inheritance from the root. It also supports compound mime types such as text/x-ant+xml and embedded mime types such as text/x-jsp/text/x-java.

Compound mime types

Let's have a look at the MimeLookup composition for a compound mime type text/x-ant+xml. The resulting Lookup will contain things registered in the following folders:

    Editors/text/x-ant+xml
    Editors/text/xml
    Editors

That's the reason why editor features provided by XML modules for general XML files work also for specialized, but XML-based, files.

Embedded mime types

The inheritance hierarchy becomes even more complicated when dealing with embedded mime types. Let's use a java scriplet inside a JSP page as an example of language embedding. The MimePath for the scriplet is text/x-jsp/text/x-java and its MimeLookup will contain features registered in the following folders:

    Editors/text/x-jsp/text/x-java
    Editors/text/x-java
    Editors

The algorithm for computing the inheritance tree for a particular MimePath combines all the above cases together and works always the same way no matter what feature you are going to look for in the resulting MimeLookup.


Applies to: NetBeans 6.0 and with some exceptions also to 5.0, 5.5
Platforms: All
See also:
What is MimeLookup?, What is MimePath?, MimeLookup API

How to get mime type from Document or JTextComponent?

WARNING: The API described here is not official! Check the javadoc for its stability level.

    // Suppose you have javax.swing.text.Document
    String mimeType = NbEditorUtilities.getMimeType(document);

    // Suppose you have javax.swing.text.JTextComponent
    String mimeType = NbEditorUtilities.getMimeType(component);

The method accepting JTextComponent is generally more practical, because JTextComponent or its subclasses is what you usually have to start with. Internally the method calls the Document version of itself on the document loaded in the component and returns its mime type (if it has any assigned). If the document does not have mime type information attached (and non-Netbeans documents generally don't) the method will use the component's EditorKit to get it.


Applies to: NetBeans 6.0, the algorithm in NbEditorUtilities.getMimeType(JTextComponent) works fine in 5.0 and 5.5, but the method is not public.
Platforms: All
See also:
Editor Module API

How can I create JEditorPane for a specific document type?

You need to find the right EditorKit first and then set it on your JEditorPane.

Here is an example showing how to do that for a java file.

EditorKit kit = CloneableEditorSupport.getEditorKit("text/x-java");

JEditorPane jep = new JEditorPane();
jep.setEditorKit(kit);

Applies to: NetBeans 6.0
Platforms: All
See also:
CloneableEditorSupport.getEditorKit()

What is MimeLookup?

The MimeLookup is a mechanism for extending editor functionality provided by NetBeans modules.

Most of the editor functionality in NetBeans is organized by mime types of documents that are edited. There are special modules that provide support for editing java, xml, jsp, c++ and many other file types. All those modules need to provide more or less the same features such as syntax coloring, code completion, code folding, popup menu, etc. However, the implementation of those features is different for particular file types.

The editor insfrastructure provides many SPI interfaces that can be implemented by modules providing specific implementation of editor features and the MimeLookup is the way how these implementations can be plugged in to the system.

As its name suggests MimeLookup is a mime-type specific Lookup. This means that modules can register instances in the Lookup dedicated to the mime type of files that they support. For example there are different Lookups for text/x-java and text/xml mime types and both contain FoldManager implementations specific for java and XML languages respectively.

The MimeLookup implementation is split in two parts. The first part is pretty much independent on most of the other NetBeans libraries and provides a simple API and SPI for accessing contents of MimeLookup. The second part is a NetBeans specific implementation of the MimeLookup's registry based on the modules XML layers. This registry is in fact a hierarchical structure of folders under the Editors/ folder on the system filesystem.


Examples

# How to get Lookup for java files?
MimePath mimePath = MimePath.parse("text/x-java");
Lookup lookup = MimeLookup.getLookup(mimePath);

# How to register instances (e.g. EditorKit) in the Lookup for java files?
<folder name="Editors>
  <folder name="text">
    <folder name="x-java">
      <file name="org-netbeans-modules-java-JavaEditorKitImpl.instance"/>
    </folder>
  </folder>
</folder>

Applies to: NetBeans 5.0, 5.5, 6.0
Platforms: All
See also:
What is Lookup?, MimeLookup API

What is MimePath?

Basically, MimePath is an ordered list of mime types.

The reason why we have come up with the concept of MimePath is that we need to support embedded languages. In the simple world where code is written only in one language and stored in files dedicated for that language it is enough to know the mime type of a file in order to know its language and to load appropriate editor features. The world, however, is not simple anymore and the reality requires us to deal with situations when one file contains a mixture of several different languages. An example is a web applications development when people write JSP files that contain snippets of code in JSP, HTML, an expression language, Java, JavaScript and possibly some other languages. The whole JSP file can be broken up into sections containing code in different languages and user expects to get features like coloring and code completion that are appropriate for the mime type of each section. This is called language embedding.

In order to be able to describe the exact 'type' of each embedded block of text Netbeans use an ordered list of mime types that describe languages along the way from the top level language (i.e. the mime type of the file itself) to the embedded block. So, for example a java scriplet in a JSP file can be identified by the list of two mime types text/x-jsp, text/x-java. The list can be encoded in one String using the forward slash character as a separator and that's what MimePath is. In our example the MimePath of java scriplet in a JSP file is text/x-jsp/text/x-java.

The embedding can go indefinitely deep and you can have MimePath like text/x-jsp/text/html/text/el for an expression language used in an HTML attribute inside a JSP file - <a href="${myLink}">...</a>.

Since MimePath is required when you want MimeLookup and since MimeLookup is the way for pluging-in language specific editor features it is possible to provide features tailored specifically for any type of language embedding. If you want to know more about the contents of MimeLookup generally and for compound and embedded mime types, read more in How is MimeLookup composed?.


Applies to: NetBeans 5.0, 5.5, 6.0
Platforms: All
See also:
What is MimeLookup?, MimePath Javadoc, MimeLookup API

How can I change the executable's icon?

In short, the current NetBeans IDE (6.7) only provides limited support for changing application icons. Alternate solutions are described below, but NetBeans itself does not include any way to change the icon of the Windows launcher executable called <your branding name>.exe, nor does it provide a way to specify an .icns file for Mac OS X. There is already an enhancement request for Windows icon support: issue #64612.

'Application Icon' Images

NetBeans only provides GUI support for choosing a 48x48 GIF or PNG image, within the Project Properties dialog on the Build screen. Using this screen produces two files within your project's branding/core/core.jar/org/netbeans/core/startup folder: frame.gif and frame48.gif. However, these files are crudely resized from the selected image. For this reason, and because a 32x32 icon is not generated, it is best to create the image files for the three icon sizes yourself using another editor, and then simply place them into the startup folder mentioned above.

Similar to toolbar icons, these files always use the .gif extension, regardless of their actual format. The frame.gif file is used for the smallest icon size of 16x16, which shows up in three places: the taskbar (Windows/Linux), in the upper-left corner of the application's title bar (Windows/Linux), and in the upper-left corner of most dialog windows (Windows/Linux). Another file called frame32.gif (which is not generated by the NetBeans Project Properties dialog) provides a 32x32 icon that shows up in the Alt-Tab menu on Windows. Lastly, the frame48.gif file provides a 48x48 icon that shows up in the Alt-Tab menu on Linux.

Windows Icons

This refers to the icon of the Windows launcher executable as seen in Windows Explorer or when you make a shortcut to it on your Windows desktop. The Windows executable is found within <your project>\build\launcher\bin\ and is an identical copy of <NetBeans install location>\harness\launchers\app.exe that has simply been renamed to the branding name that you have specified within the Project Properties dialog on the Build screen (which is actually saved as the app.name property in project.properties). Although the NetBeans IDE can't change this icon, you can use a third-party utility program to replace the exe's icon with an .ico of your own.

If you want a simple commandline program to call as part of your Windows build process, the free ReplaceVistaIcon.exe from RealWorld Graphics works well, and can be invoked as simply as:

ReplaceVistaIcon.exe build\launcher\bin\<your branding name>.exe YourIconFile.ico

To do this automatically when building, simply place a copy of ReplaceVistaIcon.exe and <your branding name>.ico into your project's root directory (where build.xml is), and add the following to your suite's Build Script (build.xml) after the import line:

	<condition property="isWindows">
		<os family="windows" />
	</condition>

	<target name="build-launchers" depends="suite.build-launchers">
		<!-- Replace the icon for the Windows launcher exe. -->
		<antcall target="replaceWindowsLauncherIcon"/>
	</target>

	<!-- Windows-only target that replaces the icon for the launcher exe with our own icon. -->
	<target name="replaceWindowsLauncherIcon" if="isWindows" description="Replace the icon for the Windows launcher exe">
		<echo message="Replacing icon of Windows launcher executable."/>
		<exec executable="ReplaceVistaIcon.exe" resolveexecutable="true">
			<arg line="build/launcher/bin/${app.name}.exe ${app.name}.ico"/>
		</exec>
	</target>

If you would prefer to simply do it manually and need a GUI resource editor, try the free programs:

If you need an editor for creating/converting both Windows .ico files and Mac .icns files, try the excellent, free program IcoFX.

Mac Icons

The "Build Mac OS X Application" command in NetBeans uses a default icon from <NetBeans install location>/harness/etc/applicationIcon.icns. You can change this icon after a Mac build by simply replacing the file <your project>/dist/<your branding name>.app/Contents/Resources/<your branding name>.icns with your own .icns file of the same name.

In order to replace it automatically when building, name your .icns file as <your branding name>.icns and place a copy into your project's root directory (where build.xml is), and add the following to your suite's Build Script (build.xml) after the import line:

	<!-- Override to change Mac application icon. -->
	<target name="build-mac" depends="suite.build-mac" description="Build Mac OS X Application">
		<property name="nbdist-contents.dir" value="${dist.dir}/${app.name}.app/Contents"/>
		<property name="nbdist-resources.dir" value="${nbdist-contents.dir}/Resources"/>

		<!-- Replace the icns file. -->
		<delete file="${nbdist-resources.dir}/${app.name}.icns"/>
		<copy tofile="${nbdist-resources.dir}/${app.name}.icns" file="${app.name}.icns" />
	</target>

This is a simplified version of Tonny Kohar's (of http://www.kiyut.com) build script posted on: http://forums.netbeans.org/ptopic10504.html

How do I make a particular node visible in the Explorer, and maybe select it?

In general you cannot. See issue #7551.

If you created the Explorer view (e.g. you created a BeanTreeView or similar and put it in a Swing panel of some sort) then you can use ExplorerManager.setSelectedNodes)] and more rarely TreeView.expandNode to display a given node in your tree (The node must be a descendant of the current root node. You cannot construct a new "similar" Node and hope to select it).

If you did not create the Explorer view then there is no reliable way to find it. However you might try scanningTopComponent.Registry.getOpened() for instances of ExplorerManager.Provider and looking for appropriate nodes that way. Such tricks must be done with care - the fact that you can find the component to do this does not imply that the author of the component intends that it be there forever, remain of the same type, continue implementing ExplorerManager.Provider or anything else. Check nulls, check casts, be prepared for it not to work on future versions.

In the particular case of making a new file wizard, you can and should ask for the file(s) you create to be selected when the wizard finishes, simply by returning them from WizardDescriptor.InstantiatingIterator.instantiate()


Applies to: NetBeans 5.0, 5.5, 6.x

What is "explorer"?

There is thing that is explorer; the name is historical - very old versions of NetBeans had a window named "Explorer" that contained a tree of files and other components. Colloquially, the term is still used to refer to the area in the left side of the main window where the Files and Projects tabs live in the IDE - but NetBeans has long since stopped having names for or frames around tabbed containers. There is an API in NetBeans which contains Swing components that can render Nodes , which is called the Explorer API.

How do I show a Node to my Explorer View?

Once you have a component to show Nodes , you will need to set the root node whose children it will display (some views show the root node, some don't, in some cases you can set whether it does or not).

Presumably you have an ExplorerManager set up for your view - just get that and call setRootContext (someNode) and the view will display it.

What is an ExplorerManager?

You do not directly set the Node that is displayed by an Explorer view component (Swing components that display Nodes ) by calling a method on that component. Rather, you set that kind of information by finding the manager for that component - it's what is in charge of what node is displayed, selected, etc.

The manager may be explicitly set on an Explorer view, but usually this is not necessary. When you add a view component (such as a BeanTreeView ) to a Swing container, it will search backward through its parent, it's parent's parent, and so forth, looking for a component that implements ExplorerManager.Provider (an interface with one method - getExplorerManager()). That ExplorerManager is what will determine what is displayed.

While this may seem like an unnecessary layer of indirection, it is actually quite powerful: It makes it possible to very simply create master-detail views ala Windows Explorer: Just add two views to a JPanel subclass that implements ExplorerManager.Provider . It is very easy to set it up so changing the selection in one causes the other one to show the children of the selected object - just the way selecting a folder in Windows Explorer does.

See also the ExplorerManager javadoc . The FAQ about showing explorer views in the main window includes sample usage of ExplorerManager.

What is an Explorer view?

An explorer view is a GUI component which can display a Node and (optionally) its child nodes. While Nodes are, by definition, a tree structure, explorer views are much more than just JTrees. Here is a list of the components available:

<!-- * ListTableView - similar to a TreeTable, but with a list, not a tree (unused and long unmaintained - may not be working) -->

With the exception of PropertySheetView, all of these classes live in the package org.openide.explorer.view (sources in openide/explorer in NetBeans' CVS).

An explorer view's content is controlled by its ExplorerManager - you don't set the root node directly on the view component, you use its manager. This is so that more than one view can share a single manager, to do master-detail views (for example, the first page of the New Project wizard is one such view - the right hand panel displays children of the left hand panel's selection).

There are a number of advantages to using Nodes and Explorer Views

A common usage is to get a Node for some folder on disk or in the configuration filesystem, optionally create a FilterNode to filter out some child nodes of it or its children, and display that.

How to store external libraries in the NetBeans Hg repository

In the spirit of building on the shoulders of giants, NetBeans takes advantage of external libraries which are not developed on netbeans.org. Those libraries are either open-source software, or binary-only software but with liberal licenses. A few examples: Apache Tomcat; JUnit; JavaHelp (runtime); javac compiler; JSR-88 interface classes.

For convenience, these libraries are stored in the same Hg repository as the source code under CDDL/GPL. They are placed in well-known places in the source tree. The license text is associated with the binary file to make it clear which terms and conditions the users/developers must agree to besides being compliant with the CDDL/GPL itself. Only source code covered by the CDDL/GPL (or BSD, in the case of samples) can be hosted in the http://hg.netbeans.org/main/ repository. As the NetBeans Hg tree is growing, we need to initiate stricter rules and check that all external binary files have a correct associated license. There are also several recommendations on avoiding unnecessary additions of binary files into Hg.

The build system will automatically check if all binary files under <nbmodule>/external are stored correctly with appropriate license and all required information. <nbmodule> means NetBeans project module, e.g. external is on same level as nbproject. Failing to do so will result in a broken build!

Questions:

Here are the rules NetBeans committers must follow when placing external libraries into NetBeans Hg:

License file format

License files should be in the following format:

Name: SomeLib
Version: 1.2.3
Description: Library for management of some blah blah blah.
License: Apache_V20 [see note regarding normalized names]
OSR: 1234 [OSR number, refer to LFI previously; Sun-internal legal]
Origin: http://www.xyz.org [where file(s) were downloaded from]
Files: xyz.jar, xyz-doc.zip, xyz-src.zip [optional; see below for explanation]
Source: URL to source [mandatory for LGPL, otherwise optional]
Comment: needed until NB runs on JDK 6+ [optional: why is this library here?]

Use of SomeLib version 1.2.3 is governed by the terms of the license below:

[TEXT OF THE LICENSE]

As hinted at above, the OSR field refers to a Sun-internal system. Those contributing patches from outside of Sun can leave this field blank. Also note that a single license file may cover multiple JAR files from the same project. For example, if your patch depends on a third-party library distributed under the same license as two JARs, you will only need one license file and can account for both of these JARs in its Files header.

If the Files header is not present, then a license name-x.y.z-license.txt must correspond to a binary name-x.y.z.jar or name-x.y.z.zip. If present, it should list the names of all binaries to which it corresponds.

The header fields are read during the build process and removed. Therefore this information will not appear in the final build or NBMs.

Template-based licenses

If there is template-based license (like BSD one http://www.opensource.org/licenses/bsd-license.php), e.g. the license file has several ad hoc places to be updated accordingly. The template itself should have the license file stored under nbbuild/licenses with well-defined tags __TAGNAME__; these tags will be replaced during the build. Template-based licenses stored along with the binary in Hg must have be in original form as they came with binary:

Example BSD License, as it is stored in nbbuild/licenses:

Copyright (c) __YEAR__, __OWNER__

All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of __ORGANIZATION__ nor the names of its contributors
      may be used to endorse or promote products derived from this software
      without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Example BSD License, as it is stored in Hg along with binary:

Copyright (c) 2007, NetBeans

All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of NetBeans nor the names of its contributors
      may be used to endorse or promote products derived from this software
      without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

NBM build, managing correct license for NBMs

Required licenses should be listed in project.properties. (There still must be a license along with the binary in Hg.) The new entry will be called extra.license.files, where the license files will be relative to project basedir, e.g.

extra.license.files=external/x-1.0-license.txt,external/y-2.0-license.txt
This will create an NBM with two extra licenses besides the usual CDDL. This also maintains compatibility with the current build system.

As a convenient shortcut for the common case that you simply want to copy some files to the target cluster (but cannot use the release directory since third-party binaries are involved), you may use the newly introduced release.* Ant properties which should be specified in project.properties. Each key names a file in the source project; the value is a path in the target cluster. Any such pair will automatically:

Example (from the form module; details):
release.external/beansbinding-0.6.1.jar=modules/ext/beansbinding-0.6.1.jar
release.external/beansbinding-0.6.1-doc.zip=docs/beansbinding-0.6.1-doc.zip
(Note: if you wish for the binary to be in the classpath of the module as a library, you will still need a <class-path-extension> in your project.xml.) You can also use a ZIP entry on the left side and it will be extracted from the ZIP to your cluster:
release.external/stuff-1.0.zip!/stuff.jar=modules/ext/stuff-1.0.jar

Normalized names

There will be a license repository under nbbuild/licenses where all licenses in use should be available. Each license type will be given a unique name: Apache_V11, Apache_V20, etc. This name must be referred to in the License field. This allows us to count licenses and file names and build a 3rd-party README as well as NBMs. Make sure that the license for a new binary is correctly included under nbbuild/licenses. If there is no existing license of the same type, it must be reviewed prior to committing.

NetBeans Samples

If a sample is created for NetBeans itself, it can be packaged into ZIP file and should not be in the external/ folder. To ensure tests correctly skip over it, the owner must add an entry for the binary into nbbuild/antsrc/org/netbeans/nbbuild/extlibs/ignored-binaries and include a brief explanatory comment.

Alternately, it may be preferable to keep the sample files unpacked directly in Hg, and create the ZIP during the module's build process (either directly into the cluster, or into build/classes for inclusion inside the module). This not only prevents tests from warning about it, but can make it easier to update minor parts of a sample and may make version control operations more pleasant.

The sample itself must be covered by the BSD license; the license must be included in every file (excepting binaries such as icons).

Copyright (c) <YEAR>, Sun Microsystems, Inc.

All rights reserved.

Redistribution and use in source and binary forms, with or
without modification, are permitted provided that the following
conditions are met:

* Redistributions of source code must retain the above
  copyright notice, this list of conditions and the following 
  disclaimer.
* Redistributions in binary form must reproduce the above
  copyright notice, this list of conditions and the following
  disclaimer in the documentation and/or other materials
  provided with the distribution.
* Neither the name of Sun Microsystems, Inc. nor the names of
  its contributors may be used to endorse or promote products
  derived from this software without specific prior written
  permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE. 

If sample is not created solely for NetBeans, e.g. bundled in a third-party product and covered by a separate license, it must follow the same rules as for any other binary library.


Common mistakes

A binary file has no associated license. (E.g. xyz.jar is missing xyz-license.txt.)

A binary file has an associated license, but does not maintain the naming convention, or has typos. (E.g. xyz.jar with xy-license.txt.)

Licenses are not pure text. (E.g. they contain HTML.)

A binary file is duplicated in several places. Before adding a new library, please make sure that library is not already available in the Hg tree. If it is, check if the version there is suitable for you; if so, communicate with the owner regarding possible upgrades and/or available packages if they are not available. You might need to move the library to a parent cluster as well. If you do depend on such a third cluster, make sure your module is marked as eager, otherwise it will get disabled.

The names of the binary and its license file will change when the binary is upgraded to a newer version. Update project.properties (or, less commonly, build.xml) to reflect this change.

Before moving from my own repository to NetBeans Hg, I used release/modules/ext/ for storing my binary libraries. They need to be moved into external/ unless the library itself is covered by CDDL, build script, licenses etc., must be updated accordingly!

How do I know if some other modules is relying on the source location of my external binaries? Answer: it's not hard to find out. For example, if you want to know who uses httpserver/external, try this (Unix / Bash syntax):

cd nb-main
for f in */{build.xml,nbproject/*.{properties,xml}}; \
  do fgrep -H httpserver/external $f; done

Implementation work

Interesting files from build:

  1. Current license summary
  2. VerifyLibsAndLicenses test
  3. CreateLicenseSummary test
  4. Unreferenced or overreferenced files

Static verification of Hg

Part of regular build. Only pays attention to Hg-controlled files in the checkout, so can run on a built source tree without becoming confused. Writes results in JUnit format for easy browsing from Hudson.

Things done in IDE build

Generate a third-party JAR & license summary. Find every binary in the IDE build which is either present directly in some */external dir or present inside a ZIP in some */external dir. For every such binary, retrieve the license from nbbuild/licenses. Make a single document listing all of the binaries and licenses.

Verify that no such binary is present in more than one place.

Saved as THIRDPARTYLICENSE-generated.txt in development builds.

Things done in NBM build

nbbuild/templates/projectized.xml (netbeans.org modules only) will look up extra.license.files and use them in Info.xml.

release.* properties honored (see above).

Golden files

nbbuild/build/generated/external-libraries.txt is generated directly from external dirs.

Does not yet take account extra.license.files correctly. Also may not be a complete list of libraries.


Applies to: NetBeans 6.5

What are File Attributes?

FileObjects have attributes. These are ad-hoc key-value pairs which can be associated with a file and persist across shutdown and restart.

Attributes are routinely used in the System Filesystem for providing additional configuration data. In pre-4.0 NetBeans, they were relatively commonly used for user files on disk. They still may be used for user files, but this is now discouraged - the infrastructure has been changed to store all attributes in the userdir rather than sprinking .nbattrs throughout the users disk; using attributes for user files at this point does have negative performance implications.

See FileObject.getAttribute and FileObject.setAttribute .

Filing a bug report

If you think you have found a bug in the NetBeans Platform or IDE which affects your module development, please file it so it can be fixed. Generally exceptions coming from platform code are bugs in NetBeans (unless it is e.g. an IllegalArgumentException thrown after your code called a method with invalid arguments). Other things can of course be bugs if NetBeans is not behaving according to its documentation, or if something just looks wrong.

  1. Reread all relevant documentation to see if you have missed anything important.
  2. If you are unsure whether the behavior is really incorrect, you can ask on dev@openide.netbeans.org. Do not be too shy to file a bug, though; it is just as easy to close an invalid bug report as it is to reply to the mailing list.
  3. If at all possible, figure out how to reproduce your bug. From scratch: the assignee of the bug report cannot see your computer and has no idea what you are working on or why. Try to make a minimal, self-contained test case that anyone could run to see the bug in action. Often a suite project is a good test case - attach a ZIP of sources, including nested module projects. If you know how to write a unit test for the buggy module, that is ideal, but this can require some deeper knowledge of NetBeans internals. Sometimes a bug occurs that just cannot be easily reproduced - it is still fine to file a bug, but include as much diagnostic information as you can and do not be surprised if it does not get fixed.
  4. Read: Issue Reporting Guidelines
  5. For general background you may also want to read: How To Ask Questions The Smart Way
  6. File a bug report and include at least
    1. Some background on what you are trying to accomplish and why.
    2. Some kind of test case to demonstrate the bug.
    3. Instructions for running the test case.
    4. What you would expect to see happen.
    5. What you actually see happen.
  7. Be patient as the bug is assigned and evaluated, and provide additional information if requested. If all goes well it should be fixed for a future NetBeans release. The evaluator may also be able to offer some workarounds for use in current releases.

I need to show a file chooser when my action runs. Can I remember the most recently used directories?

As of NetBeans 6.7, org.openide.filesystems.FileChooserBuilder makes this easy. Pass a Class or unique String key to the constructor of a FileChooserBuilder. The next time the same key is passed, the new file chooser will automatically be rooted on the directory selected the last time.

Can I add a menu item to the context menu of every Java source file?

Yes. In NetBeans 5.0 and later there is a wizard available for NetBeans modules which does this for you. Just run New File | Module Development | Action, as an action type choose Conditionally Enabled. Choose "Data Object" in Cookie Class(es) combobox. On the next step select "File Type Context Menu Item" and choose text/x-java in the File Type Context Menu Item combobox, finish the wizard and you are done. For more information you may press the Help button available at the bottom of each step of the wizard.

In NetBeans 4.1 you just need to insert an action ( *.instance ) into the folder Loaders/text/x-java/Actions/ in your module's XML layer. (Available in NetBeans 4.1 and later only.)

In any version of NetBeans, you can also add a global "tools" action to your module's manifest, which will appear in the Tools submenu of the context menu of any node to which the action applies (i.e. on which it is enabled).


Applies to: NetBeans 4.1+

Related: DevFaqFileEditorContextMenuAddition

Can I add a menu item to the context menu of the Java source editor?

Yes. In NetBeans 5.0 and later there is a wizard available for NetBeans modules which does this for you. Just run New File | NetBeans Module Development | Action, as an action type choose Conditionally Enabled. On the next step choose text/x-java in the Editor Context Menu Item combobox, finish the wizard and you are done. For more information you may press the Help button available at the bottom of each step of the wizard.

In NetBeans 4.1 you just need to insert an action (e.g. *.instance ) into the folder Editors/text/x-java/Popup/ in your module's XML layer.


Applies to: all versions of NetBeans

Related: DevFaqFileContextMenuAddition

How do I get a java.io.File for a FileObject?

FileUtil.toFile(FileObject fo)

What is a FileObject?

FileObjects are virtual files which live inside a
FileSystem . They may represent a file on disk - or anything else walks and talks like a file, or can be made to - such as a file on a remote FTP server, a file entry in a JAR file, an entry in an XML file, etc.

FileObjects differ from java.io.File in certain ways:

They are part of the Filesystems API ; the javadoc for FileObject can be found here .

How do I get a FileObject for a DataObject?

theDataObject.getPrimaryFile()

How do I get a FileObject for a File?

FileUtil.toFileObject (File f)

How can I create a FileObject in memory?

Sometimes it's desirable to work with a file but you don't want to commit it permanently to disk. It's easy to do this in NetBeans by using the in-memory filesystem. The first two lines in the following code will create a new text file and the next three will open it in an editor. You can easily change this to handle other types of files provided that their DataObject's also have an OpenCookie.

    FileSystem fs = FileUtil.createMemoryFileSystem();
    FileObject fob = fs.getRoot().createData(name, "txt");

    DataObject data = DataObject.find(fob);
    OpenCookie cookie = (OpenCookie)data.getCookie(OpenCookie.class);
    cookie.open();

How do I get the Open File item on the File menu into my platform application?

The Open File menu item is a part of the User Utilities module, in the ide cluster. This module can be added to your project using the Libraries page of the module property sheet.

The User Utilities module also adds the Find in Files feature and support for PDF files (they are recognized and can be opened by double-clicking on them).

How does NetBeans recognize files?

A lot of applications show some UI that displays folders of files; also a lot of NetBeans UI is created by showing virtual files in the configuration filesystem.

The basic mechanism is this: Some folder is shown in the UI; files of known types have their own icons, menu items and behavior.

The way NetBeans detects files is this: The "files" being shown are FileObjects - wrappers around java.io.File, or in the case of configuration files, typically wrappers around data stored in some other way, such as inside XML files in modules. What you're actually seeing is Nodes, which are the things that provide actions, localized names, etc. to files or other things.

In between Nodes and FileObjects are DataObject s. A DataObject is like a FileObject, except that it knows what kind of file is being shown, and there are usually different types of DataObject (provided by different modules which implement support for file types - for example, the Image module makes it possible to recognize and open .gif and .png files) for files with different extensions, XML files with different DTDs, etc.

Modules that recognize different file types install DataLoaders - factories for file-type-specific DataObjects.

So what really happens is that, when a folder is expanded, the system asks each known DataLoader, "Do you know what this is?" The first one that says "Yes" gets to create the DataObject for the file (in reality the recognition process is a little more optimized than it sounds here, but it adds up to this description).

In order to actually display something for the each file, the system calls DataObject.getNodeDelegate() for each DataObject, and the Nodes are what you actually see in the UI.

What is a FileSystem?

If you use a Unix-based operating system, this concept will be familiar; if not, it may require some explanation.

NetBeans uses virtual files to refer to the users files on disk, and to refer to its own configuration files. If you used the NetBeans IDE 3.6 or earlier, you may remember that the way you constructed your classpath used to be by "mounting" filesystems - folders on your disk.

Filesystems are gone from the UI, but are alive and well under the hood in NetBeans.

A FileSystem is a hierarchical tree of folders and files. A filesystem has a "root folder", which may contain files and other folders. "Files" (FileObjects ) in a Filesystem may be actual files on disk, or entries in JAR file, or entries in an XML file, or anything else that walks and talks like a file that someone has implemented the Filesystem interface for.

In the NetBeans Platform there are implementations of FileSystem for

Filesystems are used both to represent user files on disk, and also to represent configuration data internal to NetBeans - the System Filesystem . This is one of the reason that it takes only minimal code to create a GUI view of the system filesystem - the same file recognition code that recognizes user files, gives them actions, icons and display names is what recognizes internal configuration data.

Especially in the case of the System Filesystem, it can be useful to think of a Filesystem as a "namespace" in which objects (which may contain data or represent Java objects) live - for the System Filesystem, the fact that the entries in it are referred to as files is incidental.

As of NetBeans 4.0 you will rarely work directly with the FileSystem class.FileUtil.toFileObject is the normal way of getting a file object from a disk file.FileUtil.getArchiveRoot is the normal way of getting file objects from a JAR or ZIP file. In NetBeans 4.x FileSystem implementations are also used for version control integration but the 5.0 CVS support no longer uses this system.


Applies to: NetBeans 4.0, 4.1, 5.0, 5.5, 6.0, 6.1

Files vs. file objects

What exactly is the difference between a filename on disk and a FileObject? How do I convert them?

Raw files on disk are generally represented in Java using java.io.File. These correspond directly to what the operating system thinks of as a file.

Under the Filesystems API, raw files are not usually manipulated directly. Rather, you should usually be using FileObject. Besides the fact that most other APIs that work with files expect FileObject, these have a number of advantages:

  • The filesystem they come from need not correspond to physical files on disk, but could be JAR file entries, or potentially database entries, FTP downloads, etc.
  • The rest of the IDE can interact with them in an object-oriented fashion, including locking and change notification.

However a FileObject must always exist, unlike File.

In case translation from one to the other is necessary:

  • To look for a FileObject representing a File, use FileUtil.toFileObject(File).
  • To look for a File from a FileObject, you may use FileUtil.toFile(FileObject).

How do I get at the file that a particular node represents?

Q: I have a node from somewhere (e.g. a NodeAction ).

I think it corresponds to a file on disk; how can I get that file?

A: Just get the DataObject as a cookie and go from there:

Node n = ...;
DataObject dob = (DataObject) n.getCookie(DataObject.class);
if (dob == null) {
    // not a file node
} else {
    // could also get all files in the data object, if desired:
    FileObject fo = dob.getPrimaryFile();
    // do something with fo
}

In the other direction you can use DataObject.find and then DataObject.getNodeDelegate to get a node representing a file object.

Also see DevFaqFileVsFileObject if you need java.io.File for some reason.

How can I see the system filesystem (Repository.getDefault().getDefaultFileSystem())?

The layer file browser in NetBeans project support shows the default file system.

Open a NetBeans module project in the Projects window. Navigate to Important Files > XML Layer > <this layer in context>. You can examine the IDE's default file system by browsing the <this layer in context> node.

While browsing the filesystem remember that each node has a "Name" property (use the Properties Window to see the properties of each node). You must use the "Name" to refer to the node in the filesystem.

For instance, in default (English) locale the menu bar appears as the node Menu Bar in the filesystem viewer, but its nonlocalizable code name is Menu. So to refer to the menu bar in your layer.xml file you have to use the name of the node, like this:

<folder name="Menu">

instead of

<folder name="Menu Bar">

Applies to: NetBeans 5.5, 6.0, 6.1, 6.5, 6.7

How can I get the position of the caret in the currently selected editor window?

You need to first get the selected node (which if the Editor is selected, should correspond to the file being edited); get the most recent editor pane open on it; and then access the caret:

Node[] n = TopComponent.getRegistry().getActivatedNodes();
if (n.length == 1) {
    EditorCookie ec = (EditorCookie) n[0].getCookie(EditorCookie.class);
    if (ec != null) {
        JEditorPane[] panes = ec.getOpenedPanes();
        if (panes.length > 0) {
            int cursor = panes[0].getCaret().getDot();
            String selection = panes[0].getSelectedText();
            // USE selection
        }
    }
}

Applies to: NetBeans 4.0 and newer

I have a .instance file. How do I get an actual object instance?

Using InstanceCookie (note that if you have an entire folder of .instance files, there's a more efficient way to get all of them):

DataObject dob = DataObject.find (theDotInstanceFileObject);
InstanceCookie ck = (InstanceCookie) dob.getCookie (InstanceCookie.class);
MyObject obj = (MyObject) ck.instanceCreate();

Looking at the UI how do I find a module that implements a menu item?

Looking at text in IDE such as a menu item, window title, node display name, etc. you may want to change it. But first you need to find where in the code this string is produced. It is very easy to find if you add the following switch into your .../etc/netbeans.conf:

-J-Dorg.openide.util.NbBundle.DEBUG=true

If you use this switch all strings loaded from Bundle.properties files using org.openide.util.NbBundle will have two numbers appended to them. The first number identifies the bundle file. Look for this number in the IDE log to find the location of the properties file that provides this string.

Another handy trick: in a built source tree, run

ant index-layer-paths

to see which module (by code name) contributes each layer file (or folder), including menu items and so on. You can also just look at the trunk version of this file here.

How do I get a reference to the system filesystem?

FileUtil.getConfigRoot()
FileUtil.getConfigFile(path)
// usually you don't need to use this
Repository.getDefault()

I have a folder full of .instance files. How do I get any/all of the object instances?

In NetBeans 6, if the folder is in the System Filesystem (as it almost always will be), it is very simple:

Lookup myObjects = Lookups.forPath ("path/to/folder/in/sysfs");
(note the separator is always / with NetBeans filesystems).

In NetBeans 5.x and earlier, to get a folder from the system filesystem and get all of the .instance files of some particular class in it, instantiated as java objects:

FileObject myFolder = Repository.getDefault().getDefaultFileSystem().findResource (
    "MyFolder/MySubFolder");
DataFolder df = DataFolder.findFolder (myFolder);
FolderLookup lkp = new FolderLookup (df);
Collection <? extends MyType> c = lkp.lookupAll (MyType.class);

If you are using NetBeans 5.x, the lookup code above should read:

Lookup.Template template = new Lookup.Template (MyType.class);
Collection c = lkp.getLookup().lookup (template).allInstances();

Why are some packages org.netbeans.api.something and others are org.netbeans.something.api?

There is a naming convention for APIs in NetBeans. Generally when a new API is introduced, it will be under development and not stable for a while. During that period, the naming convention for its package is org.netbeans.modules.something.api. So, if you rely on an API with a name like that, your code could break. Generally it is the responsibility of the author of that API to refactor all modules in NetBeans source repository when the API graduates to "official" status.

An official API uses the naming convention org.netbeans.api.something. APIs named thusly should remain backward compatible.

What is netbeans.exe, who compiles it and why is it there?

netbeans.exe is the Windows launcher for NetBeans. Basically it assembles the class path string for starting up NetBeans, passes the command line arguments, etc., and launches Java with those arguments.

The main reasons for the exe are:

  • Start NetBeans without a console window opening as well as the main window
  • Windows shell quoting is inconsistent across versions of Windows
  • On some versions of Windows, command line length is limited to a shorter length than is sometimes needed for all the command-line arguments that should be passed to java
  • Provide a thing you can double click that has the correct icon

It's nothing terribly exciting, it's just a small C++ app; the sources are in ide/launcher.

Up to NetBeans 6.5 there were actually two executables - nb.exe and netbeans.exe. netbeans.exe will suppress the console window (so you won't see any logging on the command line); nb.exe will show the command line. Under the hood, netbeans.exe invokes nb.exe (so don't rename it).

Starting with NetBeans 6.7 the following changes in the Windows launcher were introduced - WinNB67Launcher.

Where can I find Javadoc for the IDE and Platform?

There is no separate set of Javadoc for the NetBeans Platform. However, as the Platform is just a subset of the IDE, the Javadoc for the IDE will apply.

You can browse the Javadoc online (this link always points to the latest development version).

You can also download the Javadoc for a particular NetBeans release:

Finally, you can go to the update center (Tools > Plugin Manager) in the NetBeans IDE and request the NetBeans API Documentation module, which bundles Javadoc matching your IDE release. Use View > Documentation Indices (Help > Javadoc References in NetBeans 6.x) to see the overview pages for API sets currently used by your open projects. The IDE should also automatically display this Javadoc in code completion popups.


Applies to: NetBeans 5.x, 6.x

Platforms: all

Where is the Platform and How Can I Build It?

In versions of NetBeans prior to 6.0, two major products were available for download: the IDE and the platform. The platform is the foundation on which the IDE is built, or looking at it another way, the platform is what's left over when you remove all the IDE features from the IDE. At any rate, the platform provides user interface components, build scripts, declarative configuration and many other features that can save you a lot of time and effort in creating your own application.

Because platform-based applications are themselves platforms that can be extended, the IDE can also be extended just as the platform can. Since you can remove features from a platform as well as add new ones, the availability of the platform and IDE let you choose between starting small and adding on (platform) or starting large and removing things (the IDE). Some feel the latter approach is better and even facing such a choice can be confusing to new users. If you're a new user, you'd do well to heed this advice and just use the IDE as a platform. It works just as well and is a lot less trouble.

But if you're still here, you may be asking where is the platform? Binary distributions of the platform are not being made available from version 6.0 onward (and issue #124372 filed to bring them back was closed without any reasonable explanation). So if you want a platform binary, you'll have to create one yourself.

Building the platform is not difficult, but it's not intuitive either. To start, you will need to download the platform source ZIP file and unpack it to some directory. Open a command prompt to that directory and change to the nbbuild subdirectory. From there, issue the following command:


   ant -Dcluster.config=platform build-platform

If you're using Java 6, you'll need to add an extra property:


   ant -Dcluster.config=platform build-platform -Dpermit.jdk6.builds=true 

But be aware that it is not guaranteed to build under Java 6 due to language changes or compiler bugs. It is unlikely you will encounter such a problem in the platform build, though it has certainly been known to happen in the IDE build. If you find something that won't compile under Java 6 but does compile under Java 5, file a bug report (preferably with a patch) about it so it can be corrected. Meanwhile, you can use Java 5 to compile -- even when Java 6 is first in your path -- by using the nbjdk.home system property to point to your Java 5 installation:

   ant -Dcluster.config=platform build-platform -Dnbjdk.home=c:/devtools/jdk/jdk-1.5.0_u15

This will build the platform into the netbeans subdirectory (i.e. nbbuild/netbeans). You can zip or tar up the netbeans directory to create a ZIP distribution.

It's also possible to create platforms based on a different subset of the NetBeans project. Hints for doing this can be found here:

Why would you want to build your application on a separate platform instead of the IDE as a platform?

Using the IDE is certainly easier, but there are inherent dangers associated with developing against your own IDE as the platform. In particular, another developer on your team may have a different version of the IDE, have different modules/clusters installed or even have simply named the platform something different in the Platform Manager. This can result in a broken build or the introduction of unwanted features. It also makes doing an automated build, such as through Hudson or CruiseControl, far more difficult.

If you want to avoid these problems, you can check the platform you want to build against into source control and then set the netbeans.dest.dir and harness.dir properties in your suite's nbproject/platform.properties file to point to the platform and harness, respectively. Building from a known version checked out from source control avoids these problems and makes it possible to historically reproduce any build. I show example values for these below:


# NOTE: You must remove the nbplatform.default line which might already exist in this file.
# Also note that editing the properties of your suite via the suite customizer (dialog)
# can add that line back in, so you'll need to watch for this and delete it again in this case.

# where the suite is located; you don't need to change this.  It exists 
# to allow us to use relative paths for the other values
suite.dir=${basedir}

# the path to the NetBeans IDE or platform binary we want to build against 
# (e.g. if building against the IDE, this points to the directory created when 
# you unpack the IDE zip file).  this example assumes your platform directory 
# is parallel to the suite directory, but you can change it to suit your needs
netbeans.dest.dir=${suite.dir}/../platform

# path to the build harness you want to use.  This is typically in the 
# harness subdirectory of your platform, but you could point to a directory
# containing customized build scripts if you want to.
harness.dir=${netbeans.dest.dir}/harness

Update for NBM projects generated by NetBeans 6.7 and later

If you have generated your projects in IDE version 6.7 and later, you have to modify the above described method slightly (6.5.1 and earlier projects compile against newer platform/harness without changes). You can distinguish "newer" project by the presence of cluster.path property in nbproject/platform.properties file or simply by the fact that an attempt to build a suite with above described platform.properties results in error:

.../harness/suite.xml:60: When using cluster.path property, remove netbeans.dest.dir, enabled.clusters and disabled.clusters properties
from platform config, they would be ignored.

In such case you have to replace netbeans.dest.dir, enabled.clusters and disabled.clusters properties with new property cluster.path, e.g.:


# NOTE: You must remove the nbplatform.default line which might already exist in this file.
# Also note that editing the properties of your suite via the suite customizer (dialog)
# can add that line back in, so you'll need to watch for this and delete it again in this case.

# where the suite is located; you don't need to change this.  It exists 
# to allow us to use relative paths for the other values
suite.dir=${basedir}

# just a helper property pointing to the same location as netbeans.dest.dir did before;
# Referenced only in this properties file, has no meaning for NB harness.
platform.base=${suite.dir}/../platform

# classpath-like list of absolute or relative paths to individual clusters 
# against which you want your suite to build; Note that you can use 
# "bare", i.e. not numbered cluster names, which simplifies later transitions
# to newer version of the platform. E.g:
cluster.path=${platform.base}/platform:\
     ${platform.base}/ide:\
     ../otherSuite/build/cluster

# path to the build harness you want to use.  This is typically in the 
# harness subdirectory of your platform, but you could point to a directory
# containing customized build scripts if you want to.
harness.dir=${platform.base}/harness

Note that the content of cluster.path is not limited to clusters from NB platform, you can add clusters from other suites, standalone modules, etc. This allows to reuse non-platform modules in several RCP apps. More on module reuse here, other details about setting up cluster.path can be found in harness/README.

How can I get a list of open editor windows?


Following applies to: 4.x, 5.x, 6.x

To obtain a reference to the currently selected editor:

Node[] arr = TopComponent.getRegistry().getCurrentNodes();
for (int i = 0; i < arr.length; i++) {
    EditorCookie ec = (EditorCookie) arr[i].getCookie(EditorCookie.class);
    if (ec != null) {
        JEditorPane[] panes = ec.getOpenedPanes();
        if (panes != null) {
            // USE panes
        }
    }
}

Following applies to: NetBeans 4.0, 4.1

To obtain references to all opened editors:

TopComponent[] comps = TopComponent.getRegistry().getOpened();
for (int i = 0; i < comps.length; i++) {
    Node[] arr = comps[i].getActivatedNodes();
    for (int j = 0; j < arr.length; j++) {
        EditorCookie ec = (EditorCookie) arr[j].getCookie(EditorCookie.class);
        if (ec != null) {
            JEditorPane[] panes = ec.getOpenedPanes();
            if (panes != null) {
                // USE panes
            }
        }
    }
}

Following applies to: NetBeans 6.x

To obtain references to all opened editors-

Using Arrays
TopComponent[] comps = TopComponent.getRegistry().getOpened().toArray(new TopComponent[0]);
for (int i = 0; i < comps.length; i++) {
    Node[] arr = comps[i].getActivatedNodes();
    for (int j = 0; j < arr.length; j++) {
        EditorCookie ec = (EditorCookie) arr[j].getCookie(EditorCookie.class);
        if (ec != null) {
            JEditorPane[] panes = ec.getOpenedPanes();
            if (panes != null) {
                // USE panes
            }
        }
    }
}
Using Set<E>
Set<TopComponent> comps = TopComponent.getRegistry().getOpened();
for (TopComponent tc: comps) {
    Node[] arr = tc.getActivatedNodes();
    for (int j = 0; j < arr.length; j++) {
        EditorCookie ec = (EditorCookie) arr[j].getCookie(EditorCookie.class);
        if (ec != null) {
            JEditorPane[] panes = ec.getOpenedPanes();
            if (panes != null) {
                // USE panes
            }
        }
    }
}

Reference-
Editor Windows Reactivated

What are editor-specific keybindings and how are they different from global ones?

The editor has its own mechanism for registering keybindings, which is separate from global keybindings (in essence, they belong to the Swing EditorKit for the editor, but there are some registration mechanisms in the editor for this). So if you want to register a keyboard shortcut only against the editor when editing a certain type of file (as opposed to a keyboard shortcut that is a shortcut for an action on the main menu), you'll be using editor-based keybindings.

If there is a global shortcut bound to a key combination, and also an editor-specific one defined for the type of file being edited, the editor wins if the editor has focus.

It is possible to use a ChoiceView graphically during the design of your interface in the Form Editor. As ChoiceView extends JComboBox, you can design the interface with the help of a JComboBox which is the placeholder for your ChoiceView and customize the creation code of the combo to instantiate a ChoiceView instead.

Simply choose "Combo Box" from the "Swing Controls" palette and drop it onto your interface. Then select the combo and select the "Code" tab in the properties window. In the "custom creation code" field type: "new ChoiceView()". Then return to the "Properties" tab an clear the "model" field. This step is absolutely mandatory otherwise it won't work: by default the Form Editor creates a dummy model for you. It is forbidden to set a model on a ChoiceView. If you do anyway you will get errors like:

java.lang.ClassCastException: java.lang.String cannot be cast to org.openide.explorer.view.VisualizerNode 
        at org.openide.explorer.view.NodeRenderer.findVisualizerNode(NodeRenderer.java:232) 
        at org.openide.explorer.view.NodeRenderer.getListCellRendererComponent(NodeRenderer.java:152) 
        at javax.swing.plaf.basic.BasicComboBoxUI.paintCurrentValue(BasicComboBoxUI.java:1202) 
        at com.sun.java.swing.plaf.windows.WindowsComboBoxUI.paintCurrentValue(WindowsComboBoxUI.java:293) 
        at javax.swing.plaf.basic.BasicComboBoxUI.paint(BasicComboBoxUI.java:888) 
        at com.sun.java.swing.plaf.windows.WindowsComboBoxUI.paint(WindowsComboBoxUI.java:199) 
        at javax.swing.plaf.ComponentUI.update(ComponentUI.java:143) 
        at javax.swing.JComponent.paintComponent(JComponent.java:763) 
        at javax.swing.JComponent.paint(JComponent.java:1029) 
        at javax.swing.JComponent.paintChildren(JComponent.java:864) 
        at javax.swing.JComponent.paint(JComponent.java:1038) 
        at javax.swing.JComponent.paintChildren(JComponent.java:864) 
        at javax.swing.JComponent.paint(JComponent.java:1038) 
   ...

Finally switch to the "Source" view and fix the import errors.

I need to package some third party libraries with my module. How do I do that?

Generally if it's a third party library (you didn't write it, you can't or don't want to change it), you will want to use a wrapper module (see DevFaqWrapperModules). An NBM file (a module packaged for delivery over the net) can contain more than one JAR, so all your libraries can be included in a single file that packages your module.

Note you can multi-select JARs in the New Library Wrapper Module wizard.

Advanced stuff

You can add libraries manually to a standard module; or add additional libraries to an existing library wrapper module. The relevant data is in the project.xml for the module. What you would do is add entries similar to this one for each JAR.

<class-path-extension>
    <runtime-relative-path>ext/hexedit.jar</runtime-relative-path>          
    <binary-origin>release/modules/ext/hexedit.jar</binary-origin>
</class-path-extension>

Note if you want these libraries to be usable outside of the module they're declared in, then you must add the relevant packages to the list of public packages for that module.


Applies to: NetBeans 6.5

See also

My project.xml lists more dependencies than I really need. How can I fix it?

As your code evolves, you may find that it no longer needs dependencies on some modules that it used to require. In this case, you can run the fix-dependencies Ant target on your module to remove any unnecessary dependencies from your project.xml.

As with any automated modification, it's a good idea to ensure that this file is up-to-date in source control before running this task, although in an emergency you can use the IDE's local history feature to revert changes.


Applies to: NetBeans 6.5

I want to reuse some of my modules in several RCP applications. How to do it?

I want to use modules from update center in my RCP applications. How to do it?

Since 6.7 you can use use non-netbeans.org modules (yours or 3-rd party) directly in your suite and configure it conveniently via GUI. Go to Properties of your suite project, Libraries tab:

reuse-modules-1.png

If you have sources of modules you want to reuse, click Add Project... button and browse for suite or standalone module project you want to add.

If you want to use 3-rd party binary modules, just unpack them into cluster folder somewhere on your disk. Preferably put the cluster under your suite's root so that you can use relative paths, which makes setup in team environment easier. Then click Add Cluster... button and browse for the cluster folder:

reuse-modules-2.png

You can also add sources and/or Javadoc for binary modules, just like for whole NetBeans Platform.

Once projects and clusters are added to Libraries and checked, they behave just like part of the platform. They will appear in running platform application, will be included in binary distribution, modules from your suite can depend on them, etc.

I cannot use 6.7 or newer platform, what to do?

You can actually use older platform as long as you configure it to use newer harness (either via Tools -> NetBeans Platforms in IDE or by specifying
harness.dir) and you develop in new enough IDE.

If you cannot even use new harness and/or IDE, you have to use suite chaining, build your own platform and depend on it. See harness/README file for details. See also HowToReuseModules.

Project Encoding vs. File Encoding - What are the precedence rules used in NetBeans 6.0?

NetBeans implements the FileEncodingQuery object (FEQ) to determine the language encoding for projects and files. The FEQ is an interface for obtaining information about which encoding should be used for reading from/writing to a particular file. It can be best defined as a layer model that adheres to the following precedence rules (level of importance from top to bottom):

  • file FEQ
  • project FEQ
  • fallback FEQ

For example:

  1. When the client requests the FEQ for the encoding of some object, it first asks the file FEQ. E.g., when the file is XML or HTML, it looks inside the file and returns either the declared encoding attribute, otherwise null. If the file FEQ is not null, the value is returned to the client, otherwise it continues:
  2. If the file resides within a project that has implemented the FEQ, a request is made for the project FEQ. If the project FEQ is not null, the value is returned to the client, otherwise it continues:
  3. If neither the file FEQ nor project FEQ cannot provide any encoding information, the fallback FEQ is used. The fallback FEQ returns the language encoding used by the operating system (i.e. Charset.defaultCharset()).

For JSP pages, the JSP parser is responsible for determining the encoding value. For example: if the file itself doesn't contain the encoding declaration, the parser looks in web.xml. If there is no declaration there either, it returns ISO-8859-1.

What if the project encoding is not set (i.e. for projects that have not implemented the FEQ)?

The fallback FEQ is applied (i.e. the encoding of the system locale). This applies to imported projects and projects created in NetBeans versions 5.x and prior.

Note: This does not have any impact on the global project encoding value, which is still used for the creation of new NetBeans 6.0 projects, and is by default UTF-8. Nor does this affect the encoding value of previously created NetBeans 6.0 projects created during the same session, or opened projects created from previous sessions.

What project or file types have/have not implemented FEQ for NetBeans 6.0?

Project Types

  • Most NetBeans 6.0 project types have implemented FEQ (this includes Ruby and Rails projects).
  • The NetBeans Modules project type uses UTF-8 and it is not possible to change the encoding for this project type.
  • UML does not have a project encoding property for NetBeans 6.0, and uses the encoding of the system locale. For UML Java projects that have been reverse-engineered or have had their code generated, the FEQ is applied to query for file encoding. If no information is returned, the encoding of the system locale is used.

File Types

  • The seeding of encoding for JSP, HTML, and XML files has been completed. For XML it has been completed for most XML-based file types that can be created using the New File wizard, but not for all XML files created by projects for internal data. Other XML files created and used by various projects (e.g. web.xml, sun-config.xml) still use UTF-8; it has currently not been decided whether these files should use the encoding applied to the value of the project encoding or not.
  • The Visual Web index page currently has the encoding value seeded according to the project encoding value.
  • Properties files have a special encoding defined which translates between escape sequences and real characters. During saving, all non-ASCII characters are translated to the corresponding \u.... sequences and than the result is saved using encoding ISO-8859-1 (aka Latin 1). During loading, the decoding process is reverse - the file is first decoded using the ISO-8859-1 encoding and then it is parsed such that the \u.... sequences are recognized and translated back to the corresponding Unicode characters. This special encoding cannot be changed.

See also:

How do I fix problems about 'ide.welcome'?

'ide.welcome' is the map ID of the first help topic shown in the JavaHelp window. It is defined in the 'userguide' module. If you have excluded this module, you need to define this map ID yourself, otherwise you will encounter unexpected/unpleasant behavior:

http://www.netbeans.org/issues/show_bug.cgi?id=153793

How do I identify the "main project"?

Project mainProject = org.netbeans.api.project.ui.OpenProjects.getDefault().getMainProject();

For this, you need to declare dependencies on Project UI API, Project API and File System API.

As an example usage of the above line of code, here is an action that display a JOptionPane containing the path to the main project, if a project is selected:

public final class ShowMainProjectAction extends CookieAction {

    protected void performAction(Node[] activatedNodes) {
        String projectPath = OpenProjects.getDefault().getMainProject().getProjectDirectory().getPath();
        JOptionPane.showMessageDialog(null, projectPath);
    }

    protected int mode() {
        return CookieAction.MODE_EXACTLY_ONE;
    }

    public String getName() {
        return NbBundle.getMessage(ShowMainProjectAction.class, "CTL_ShowMainProjectAction");
    }

    protected Class[] cookieClasses() {
        return new Class[]{Project.class};
    }

    @Override
    protected void initialize() {
        super.initialize();
        // see org.openide.util.actions.SystemAction.iconResource() Javadoc for more details
        putValue("noIconInMenu", Boolean.TRUE);
    }

    public HelpCtx getHelpCtx() {
        return HelpCtx.DEFAULT_HELP;
    }

    @Override
    protected boolean asynchronous() {
        return false;
    }
}

I'm having trouble implementing this filesystem....

Be sure that what you really want to be doing is implement FileSystem . Unless you really need to access objects in a database, remote server, or some other such storage as if they were files, you are probably heading in the wrong direction.

If you do need to implement a FileSystem, you should probably start with AbstractFileSystem - it handles a lot of knotty locking semantics correctly and will save you a lot of time, effort and bugs.

What is an implementation dependency and what/how/when should I use one?

Normally modules interact with one another using public packages: a module can (indeed, must) declare which, if any, of its Java packages are intended to be visible to other modules. When you declare a specification dependency on another module, you only get access to the public packages. This kind of dependency looks like this in the manifest:

OpenIDE-Module-Module-Dependencies: some.other.module > 1.5

(requesting version 1.5 or greater of some.other.module) or like this:

OpenIDE-Module-Module-Dependencies: some.other.module

(requesting any version; not recommended).

Occasionally you may find that the author of a module neglected to expose certain classes in public packages which you know (from reading the source code) that you need to use and know how to use properly. The classes are public but not in declared public packages. It is possible to access these classes if you really have to. But you need to declare a dependency on that exact version of the other module, since such classes might change incompatibly without notice in a newer copy of that module. Since such a change could break your module, the NB module system requires that you declare the implementation dependency so that it can verify before loading your module that it matches the other module. The general idea is that if module B has an implementation dependency on module A, the system should not be able to load B unless it has the exact same version of A that B was compiled against. To make an implementation dependency in the manifest, use

OpenIDE-Module-Module-Dependencies: some.other.module = 3

where the "3" is what that other module declared as its current implementation version:

OpenIDE-Module-Implementation-Version: 3

In order to add an implementation dependency, first add the dependency to the project (e.g. click on "Add Module Dependency" from the "Libraries" node or by click the "Add Dependency..." button in Project->Properties->Libraries panel). Make sure you've checked the "Show Non-API Modules" checkbox when you're looking for the non-API module, otherwise you're not going to find it. Then, after you've added the module as a dependency, edit the dependency (either Project->Properties->Libraries->Select Dependency->Edit or Project->Right click on dependency Libraries node->Edit) and just select the "Implementation Version" radio box in the Edit dependency dialog. If you don't want to "see" all packages within the module, but only a subset, uncheck the "Include Packages in Classpath" checkbox and select the packages you want to see. This works best if the other module uses a nonnegative integer for the implementation version, and if you also check Append Implementation Versions Automatically in the properties dialog.

Implementation dependencies are to be avoided unless you really need access to all the classes in another module, for the following reason: If your module has an implementation dependency on module A, and module A is upgraded, your module probably must be upgraded as well, or the system will not load it (assuming module A's implementation version has changed with the upgrade - it should have). It is a particularly bad idea to use implementation dependencies if you do not know what the other module's author's intentions are for keeping the classes you use available and compatible. It is always possible to make an enhancement request asking for the other module to make the classes you want to use available publicly. Do not use implementation dependencies just to have access to one or two some convenience or utility classes in another module - copy them instead, and file a bug report asking for an API for doing what you're trying to do.

Friend dependencies

Friend dependencies are a little different. A module may have an API which its author is not yet comfortable exposing to just anyone - it might not be fully stabilized yet. In this case, the module with the API can declare some public packages, but also stipulate that only a predefined list of "friend modules" are permitted to use them. The friend modules just declare a regular specification version dependency, but unknown modules are not permitted to use any packages from the API module without an implementation dependency.

(Look at the Versioning panel in the API module's project Properties dialog.)

Always prefer friend APIs to implementation dependencies where there is a choice.

Implementation dependencies, Auto Update, and <verifyupdatecenter>

Implementation dependencies cause special problems for Auto Update. (Some background information is available in NetBeans API & Module Versioning Policy / Numbering Scheme for Updates.)

The problem is that when an implementation version of a module published to an update server changes, any modules declaring implementation dependencies on it must also be published, with dependencies on the new version of the base module. Furthermore, the Auto Update client has just one method for deciding whether an NBM on a server is an "update" relative to what you already have installed: if its specification version is larger. So consider the following snapshot of an update center. (The syntax is not what the actual XML file looks like, just an abbreviated version that shows parts relevant to this example.)

[Monday]

OpenIDE-Module: infrastructure
OpenIDE-Module-Specification-Version: 1.0
OpenIDE-Module-Implementation-Version: 070120

OpenIDE-Module: guifeature
OpenIDE-Module-Specification-Version: 1.0
OpenIDE-Module-Implementation-Version: 070120
OpenIDE-Module-Module-Dependencies: infrastructure = 070120

These two modules were built at the same time and could be installed together into a NetBeans instance. So far so good.

Now consider what happens when the developer of guifeature adds a major new feature and decides to publish a new version, 1.1. The next day's build produces

[Tuesday]

OpenIDE-Module: infrastructure
OpenIDE-Module-Specification-Version: 1.0
OpenIDE-Module-Implementation-Version: 070121

OpenIDE-Module: guifeature
OpenIDE-Module-Specification-Version: 1.1
OpenIDE-Module-Implementation-Version: 070121
OpenIDE-Module-Module-Dependencies: infrastructure = 070121

Again, these two modules could be installed together.

But what if a user connected to the update center on Monday and downloaded both modules, and then connects again on Tuesday looking for updates? infrastructure is still listed as 1.0 so Auto Update ignores it (1.0 is "already installed", after all). guifeature 1.1 is however a possible update. What if you install this update? The module system will refuse to enable guifeature because it requests infrastructure = 070121, whereas you have infrastructure = 070120. Oops!

The solution (short of not using implementation dependencies at all) is to use the NetBeans build harness to compute a specification version. The developer removes OpenIDE-Module-Specification-Version from manifest.mf in the source projects for both modules. manifest.mf for infrastructure instead will get

OpenIDE-Module-Implementation-Version: 1

(only positive integers 1, 2, ... are supported!). And nbproject/project.properties for both modules will get the specification version in a new form:

spec.version.base=1.0.0

The IDE's GUI for module projects lets you do all this without editing metadata files manually; just click the option Append Implementation Versions Automatically in the Versioning panel of the Properties dialog.

(The extra .0 is required for modules in the NetBeans distribution. When sources are branched for a release, spec.version.base is incremented to 1.0.1, 1.0.2, ... for each release on the branch. "Trunk" (development) changes increment the first or second digits, e.g. 1.1.0, 1.2.0, ...)

The effect of using spec.version.base is that our AU snapshots now look like this instead:

[Monday]

OpenIDE-Module: infrastructure
OpenIDE-Module-Specification-Version: 1.0.0.1
OpenIDE-Module-Build-Version: 070120
OpenIDE-Module-Implementation-Version: 1

OpenIDE-Module: guifeature
OpenIDE-Module-Specification-Version: 1.0.0.1
OpenIDE-Module-Implementation-Version: 070120
OpenIDE-Module-Module-Dependencies: infrastructure = 1

[Tuesday]

OpenIDE-Module: infrastructure
OpenIDE-Module-Specification-Version: 1.0.0.1
OpenIDE-Module-Build-Version: 070121
OpenIDE-Module-Implementation-Version: 1

OpenIDE-Module: guifeature
OpenIDE-Module-Specification-Version: 1.1.0.1
OpenIDE-Module-Implementation-Version: 070121
OpenIDE-Module-Module-Dependencies: infrastructure = 1

The update to guifeature is now safe; it can still use infrastructure from Monday. Note the new "build version" tag which is used only for diagnostics, not for dependencies.

If there is actually a change in the signature of anything in infrastructure that might affect guifeature, then the developer merely needs to increment the implementation version in infrastructure/manifest.mf:

[Wednesday]

OpenIDE-Module: infrastructure
OpenIDE-Module-Specification-Version: 1.0.0.2
OpenIDE-Module-Build-Version: 070122
OpenIDE-Module-Implementation-Version: 2

OpenIDE-Module: guifeature
OpenIDE-Module-Specification-Version: 1.1.0.2
OpenIDE-Module-Implementation-Version: 070122
OpenIDE-Module-Module-Dependencies: infrastructure = 2

If the user connects to the update center on Wednesday, the wizard will display both modules as needing to be updated - which is exactly what you want.

How is this system enforced? For one thing, attempts to use inherently unsafe implementation dependencies, or incorrect uses of spec.version.base, should produce warnings during the module build process. So look at the output of Ant once in a while and see if the build harness is telling you something.

There is also a continuous builder at http://deadlock.netbeans.org/hudson/job/nbms-and-javadoc/ which (among other things) tries to build NBMs for all modules in the NetBeans standard distribution plus those experimental "alpha" modules normally published on the update center for development builds. If you commit changes to experimental modules this build will be triggered; failures are mailed to broken_builds@netbeans.org, which all developers of modules in netbeans.org ought to subscribe to.

This builder uses an Ant task <verifyupdatecenter> to detect dependency problems among NBMs. There are two checks:

  1. Can the NBMs just built all be enabled together? (synchronic consistency)
  2. Suppose I had connected to the update center produced by the previous successful build and installed everything, and now I connected again to this build's update center and asked for all updates. Would any updated modules be broken, due to dependencies on new versions of other modules which were not updated? (diachronic consistency)

The second check is what will catch a lot of mistakes in usage of implementation dependencies as described above. Unfortunately it is not feasible to run the second check as part of an offline build process in your own source checkout, as it depends on a build of older sources; so you will need to commit changes and wait for the next build to verify them.

Generally there are two possible solutions to a test failure from this stage:

  1. Remove the implementation dependencies; switch to friend dependencies or public APIs.
  2. Ensure that all implementation dependencies are against positive integers (not dates), and that spec.version.base is used on both sides of the dependency, as described above.

In either case, to fix a test failure you will generally also need to increment the specification versions of modules on both sides of the dependency.


Applies to: NetBeans 5.x, 6.x

Platforms: all

What are *.instance files?

*.instance files are NetBeans parlance for a file which is actually standing in for an instance of an object.

An instance file typically says what class it is an instance of via its class name - for example, com-foo-mymodule-MyObject.instance. A *.instance file may create its instance from any Java class with a default constructor, or by calling a static method on a class.

In NetBeans infrastructure, *.instance files result in InstanceDataObjects. InstanceDataObjects can supply InstanceCookies, which in turn instantiate the object. So, code to actually get an instance of an object declared in the system filesystem (DevFaqSystemFilesystem) would look like this (plus error checking):

public static Object getTheObject(String pathInSystemFilesystem) throws Exception {
    return DataObject.find(
        Repository.getDefault().getDefaultFileSystem().findResource(pathInSystemFilesystem)).
        getLookup().lookup(InstanceCookie.class).instanceCreate();
}

A much easier way to get all instances of objects in a folder exists:

for (WhatISaidToPutHere instance :
        Lookups.forPath("MyFolder").lookupAll(WhatISaidToPutHere.class)) {
    // ...
}

Note that a default constructor is not required in an XML layer; you can also use a static method, using the following syntax:

<file name="ObjectTypes.instance">
  <attr name="instanceCreate" methodvalue="org.netbeans.core.ui.UINodes.createObjectTypes"/>
  <attr name="instanceOf" stringvalue="org.openide.nodes.Node"/>
</file>
(The instanceOf attribute is optional; it lets the system avoid instantiating your object just to see if it is assignable to Node. This is only useful in folders that contain objects of many different types mixed together, which is normally true only in the semi-deprecated Services folder: code looking for instances of one type only would rather not load everything.)

See also: DevFaqDotSettingsFiles


Applies to: NetBeans 6.5, 6.7

How can I add a JSeparator to the main toolbar?

It's easy to add a separator to the menus by editing the module's layer file; in fact, the Action wizard will do this for you. Items in the main toolbar are also configured through the layer file, but you may find that adding a separator as you would for the menu does not work in the toolbar. So how do you add a separator to the toolbar?

You can do this by creating a class like:

package com.example.util.widgets;

public class VerticalSeparator extends JSeparator {
	
    public VerticalSeparator() {
        super(JSeparator.VERTICAL);
    }

    @Override
    public Dimension getMaximumSize() {
        return new Dimension(getPreferredSize().width, super.getMaximumSize().height);
    }

    @Override
    public Dimension getSize() {
        return new Dimension(getPreferredSize().width, super.getSize().height);
    }
}

Then simply reference an instance of this separator in the layer file:

<file name="SeparatorAfterModelToolbarActions.instance">
    <attr name="instanceClass" stringvalue="com.example.util.widgets.VerticalSeparator"/>
    <attr name="position" intvalue="25"/>
</file>

Is there a standard way to provide user documentation for my module?

Yes. See the JavaHelp Integration API which describes how to include JavaHelp documentation in a module under Help > Contents; and you can provide rich context help rather easily, linking into the same documentation.

There is an IDE wizard for creating a help set for your module.


Applies to: NetBeans 5.x, 6.x

Platforms: all

Why doesn't my JavaHelp content show up?

The first thing to check is that you're JavaHelp configuration files are correct. Since these files contain IDs and file paths, it's easy to make a mistake. Unfortunately, the JavaHelp system doesn't provide you with much warning when such an error occurs.

It's also worth noting that the JavaHelp implementation in NetBeans IDE 6.5.x and earlier seems to require the .html file extension.

How do keybindings work?

Keybindings are specified in yet another folder in the system filesystem . The folder Shortcuts/ contains .instance files or .shadow files (shadow files are like symlinks to another file in the system fs) - these map to Actions.

The file name for the action (.instance or .shadow) file in Shortcuts/ is used to specify what keys are bound. This is done using an emacs-like syntax for specifying keybindings - e.g., CA-P equals Ctrl-Alt-P.

For a full listing of the hard-coded and cross-platform prefixes for key definitions, see the javadoc for Utilities.stringToKey() - that and its analogue, Utilities.keyToString() are used to encode and decode these.

There are special modifier characters which map to Command on Mac and Ctrl on PC, Ctrl on Mac and Alt on PC. You should use those unless you're really sure your app will never be used on macintosh or never be used by someone with a non-English macintosh.

Here is an example of what a layer file might look like if you bound the Ctrl+Shift+Equals sequence to the com.tomwheeler.example.fooviewer.FooAction action:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.0//EN"
  "http://www.netbeans.org/dtds/filesystem-1_0.dtd">

<filesystem>
  <folder name="Actions">
    <folder name="View">
      <folder name="FooViewer">
        <file name="com-tomwheeler-example-fooviewer-FooAction.instance" />
      </folder>
    </folder>
  </folder>

  <folder name="Shortcuts">
     <!--
        set up a shortcut key for executing the Foo Action:
        Ctrl + Shift + Equals on Linux and MS Windows, but Command + Shift + Equals on a Mac
     -->
    <file name="DS-EQUALS.shadow">
      <attr name="originalFile" stringvalue="Actions/View/FooViewer/com-tomwheeler-example-fooviewer-FooAction.instance"/>
    </file>
  </folder>
</filesystem>

How do I find out which keybindings are already in use?

For an existing release you can look at e.g. KeymapProfileFor60 to see the specification.

If you are developing a module for NetBeans development builds, you can just look at this file in the section Shortcuts/. This will show all global keybindings being used by modules in the standard IDE as well as experimental update center in http://hg.netbeans.org/main/ and http://hg.netbeans.org/main/contrib/ as of a few hours ago.

Editor-specific keybindings are listed in Editors/*/*/Keybindings/ folders, which is unfortunately harder to browse through.

Be conservative about adding new keybindings; they are a precious resource. Be careful with bindings using Alt, as these often clash with mnemonics, Linux window manager shortcuts, etc. If at all possible, use a multistroke binding: for example, Shortcuts/D-J R C.shadow binds the 3-stroke sequence Ctrl-J R C.

Important: this is taken from the mailing list and haven't been checked by Sun or Netbeans Legal Teams. So use at your own risk

Question:
I would like to use NetBeans Platform for one of our products, but there is a problem with license. AFAIK NBP is licensed under CDDL (which I wish to use), but there is no list of 3rd party components used in NBP. For IDE, there is such a list:
http://www.netbeans.org/about/legal/code_dependency_matrix.html Does exist something similar for NBP? Until then, I am probably not able to use it.

Answer:
In NB 6.0 and 6.1, the Platform includes only the following 3rd party libraries and licenses:

  1. 1. JavaHelp 2.0_05 (GPLv2 with Classpath Exception)
  2. 2. Script-API (GPLv2 with Classpath Exception)
  3. 3. Swing Layout 1.0.x (LGPL)
  4. 4. JNA 3.0.x (LGPL)

#2 and #3 are only required for compatibility with JDK 1.5. If you can afford to require JDK 6 or later, those two libraries are not necessary.

However, the above list applies only if your only dependencies are on the content of the 'platform' cluster (folder). If your application depends on other parts of the NetBeans IDE (e.g. the 'ide', or 'java' cluster) there may be derived dependencies on other 3rd party libraries. Such as scenario would require a more thorough investigation.

How can I track what file the user is currently editing?

The editor keeps a registry of open editors; you can track changes in which editor is active using this method: org.netbeans.api.editor.EditorRegistry.addPropertyChangeListener(myListener);. If you attach any listeners to the Document or anything else in the active editor text component, remember to remove them when the active editor changes.

DataObject Registry Listening - Sample code

DataObject.Registry registries = DataObject.getRegistry();
registries.addChangeListener(new ChangeListener() {
    public void stateChanged(ChangeEvent e) {
        System.out.println("ChangedListener: o = " + e.getSource().getClass());
        System.out.println("ChangedListener: o.source = " + e.getSource());
    }
});
DataObject[] objects = registries.getModified();
for (int i = 0; i < objects.length; i++) {
    DataObject dataObj = objects[i];
    System.out.println("data object name = " + dataObj.getName());
    System.out.println("data object pimary file name = " + dataObj.getPrimaryFile().getName());
    Set fss = dataObj.files();
    Iterator iter = fss.iterator();
    while (iter.hasNext()) {
        FileObject fo = (FileObject) iter.next();
        System.out.println("\tset file object: " + fo.getName());
    }
}

Libraries needed

  • Datasystems API
  • File System API
  • Nodes API
  • Utilities API

How can I be notified when a file is modified and saved??

The DataObject.Registry in LoadersAPI gives you a set of modified DataObjects. You can also add a listener and be notified when the set of modified objects changes.

As this operates on DataObjects you will first need to get a DataObject for your FileObject using DataObject.find() . Or you can take the modified DataObjects and do dataObject.getPrimaryFile().

Why should I use D- for Ctrl and O- for Alt - I thought C stood for Ctrl and A stood for alt?

(Wondering what this is about? See the general FAQ item on keybindings).

There should be no Alt-bound keyboard shortcuts on the mac ever - it is used on international keyboards as the compose key (for a long time, we didn't know it, but Norwegian and French users could not type } or { in NetBeans - kind of limits the usefuless of a Java IDE).

All standard shortcuts should be bound with wildcard keys - e.g., in the layer, not AS-P for Alt-Shift-P, but OS-P, which will map to Alt-Shift-P on PC and Ctrl-Shift-P on mac. For Ctrl/Command, in the layer put DS-P instead of CS-P to bind conditionally to ctrl on PC and command on mac.

All Alt-bound keybindings in the IDE are specified with O so that they are rebound to Ctrl on mac, because they will interfere with typing in a lot of locales (the real way to think about it is "the mac does not have an Alt key" - it does but it is a composition key - you can't use it).

Any alt-bound keybinding on mac is a bug. If you use the logical syntax for keybindings, your app will always work intuitively on any platform.

Note that the mapping handling does skip key combinations that simply can't work on Mac - for example, Command-H and Command-Q are always consumed by the OS, so D-H and D-Q map to Ctrl-H and Ctrl-Q, respectively, everywhere.

What is a Lookup?

Lookup is a mechanism for finding instances of objects. It is pervasively used in NetBeans APIs. The general pattern is that you pass a Class object and get back an instance of that class or null. See the Javadoc for links to articles describing its inspiration and purpose.

The simplest way to think of Lookup is that it is a Map where the keys are Class objects and the value for each key is an instance of the key class.

There is the global lookup which is used to find objects (often, but not always, singletons) that are registered throughout the system. Also, many types of objects have a method getLookup() that enables other code to get things specific to that object. In particular, Nodes and Project objects have a Lookup.

The primary purpose of Lookup is decoupling - it makes it possible to use generic objects to get very specific information, without having to cast objects to a specific type. Confused yet? It's simple. Take the example of OpenCookie - it has one method, open() that will open a file in the editor.

Say that I want to write some code that will open the selected file when the user does something. It could be an Action, a button, or maybe my code has just created a file and I want to open it. This is what I will do:

Node[] n = TopComponent.getRegistry().getActivatedNodes();
if (n.length == 1) {
   OpenCookie oc = n[0].getLookup().lookup(OpenCookie.class);
   if (oc != null) {
      oc.open();
   }
}

One can even write this code more simply, without the Nodes API at all, using Utilities.actionsGlobalContext():

OpenCookie oc = Utilities.actionsGlobalContext().lookup(OpenCookie.class);
if (oc != null) {
    oc.open();
}

The power of all this is in the level of decoupling it provides: My code that wants to open the file does not have to know anything at all about what happens when the file is opened, or what kind of file it is, or what module supports opening it. And the module that supports opening it does not need to know anything about who is going to open it. They both simply share a dependency on the abstract interface OpenCookie. So either one can be replaced without affecting the other at all.

A good example of this is in the POV-Ray tutorial. It launches an external process that generates a .png file. When the process ends, it wants to open it, so it does the following:

FileObject fob = FileUtil.toFileObject(new File(pathWePassedToProcess));
if (fob != null) {  //the process succeeded
   DataObject dob = DataObject.find(fob);
   OpenCookie oc = dob.getCookie(OpenCookie.class);
   if (oc != null) { //the Image module is installed
      oc.open();
   }
}

The fact is that it is the Image module that makes it possible to open .png files in NetBeans. But the POV-Ray tutorial does not need to know or care that the Image module exists, or what it does - it simply says "open this".

The common pattern you'll see for Lookup usage is one where there are three components:

For global services, the model is more simple - typically there will be some singleton object, implemented as an abstract class:

public abstract class GlobalService {
   public abstract void doSomething(Something arg);
   public static GlobalService getDefault() {
     GlobalService result = Lookup.getDefault().lookup(GlobalService.class);
     if (result == null) {
        result = new NoOpGlobalService();
     }
     return result;
   }
   private static class NoOpGlobalService extends GlobalService {
      public void doSomething(Something arg) {}
   }
}

Some other module entirely actually registers an implementation of this interface in the default Lookup. StatusDisplayer is a good example of this pattern.

What if multiple objects of the same type should be available?

A Lookup is not limited to containing one singleton of any type. If there may be more than one of a given type in a Lookup, the syntax is slightly different:
Collection<? extends SomeIface> c = Lookup.getDefault().lookupAll(SomeIface.class);

Note: In NetBeans versions prior to 6.0 you need to use Lookup.Template as the lookupAll method is not present yet.

The Lookup.Result can be listened on for changes in the result of the query. It is often useful to think of a Lookup as a space in which objects appear and disappear, and your code can respond as that happens (the following code uses the NB 6.0 lookupResult method - just use the pattern above with the Lookup.Template for NetBeans 5):

class ObjectInterestedInFooObjects implements LookupListener {
   final Lookup.Result<Foo> result;  //result object is weakly referenced inside Lookup
   ObjectInterestedInFooObjects() {
        result = someLookup.lookupResult(Foo.class);
        result.addLookupListener(this);
        resultChanged(null);
    }
    public void resultChanged(LookupEvent evt) {
        Collection<? extends Foo> c = result.allInstances();
        // do something with the result
    }
}

Another question is, on the side that's providing the lookup, if you have a collection already, how can you expose that in a Lookup. For that, you can create your own AbstractLookup and use InstanceContent to provide the collection of objects that belong in your Lookup.

Objects in a Lookup often are not instantiated until the first time they are requested; depending on the implementation, they may be weakly referenced, so that if an object is not used for a while, it can be garbage collected to save memory. So Lookup additionally enables lazy instantiation of objects, which is useful for performance reasons.

How can I find out what is in a Lookup?

Do not do any of these things in production code!

The simplest way is to call Lookup.toString(). If you want the output in a more readable form, do the following and print/format the resulting collection as you wish:

NetBeans 5.x Code NetBeans 6 and up
Lookup.Template tpl = new Lookup.Template ( Object.class); Lookup.Result result = theLookup.lookup (tpl); Collection c = result.allInstances(); for (Iterator i=c.iterator(); i.hasNext();) { Object o = i.next(); //do what you want } Collection<? extends Object> c = theLookup.lookupAll(Object.class); for (Object o : c) { //do what you want }

What is the difference between getCookie(Class), SharedClassObject.get(Class) and Lookup.lookup(Class)?

All of these are really historical variations on the same theme. In all cases, you pass a Class object and get back null or an instance of that class. You can see the progression in genericness:

SharedClassObject is the oldest version of the Lookup pattern in NetBeans APIs, dating to circa 1997 (because of various performance issues, eventually all usages of SharedClassObject should be deprecated and removed from the APIs). You'll see that form used in SystemOption for storing settings, and most of the singleton Action objects in the actions API. All objects returned by it will be instances of SharedClassObject.

getCookie() (circa 1999) is specific to Nodes and DataObjects. It uses the same pattern, but all objects returned by it will implement the empty Node.Cookie marker interface.

The down-side to both of the above is that they specify the return type. In the case of Node.Cookie, in practice, this meant that anything that might possibly need to be provided by a DataObject or Node needed to implement this silly marker interface, forcing it to have a dependency on the Nodes API, or a wrapper Cookie class had to be created to provide the underlying object, which just added useless classes and noise.

Lookup is the most modern and generic version of this pattern, and probably the final one. It offers two advantages:

  1. Its return type is java.lang.Object, so it can be used directly with anything
  2. Having objects own a lookup rather than directly providing a lookup(Class c) method makes it easier to replace or proxy the Lookup of some object

What is the "default lookup"?

The default lookup is Lookup.getDefault(). It is the registry for global singletons and instances of objects which have been registered in the system by modules. Note that in JDK 6, ServiceLoader operates on the same principle. The default lookup searches in two places:

Objects contained in lookup are instantiated lazily when first requested.

Here is the usual usage pattern:

1. A central "controller" module defines some interface, e.g.

package controller.pkg;
public interface MyService {
    void doSomething();
}

2. Each module which wants to implement that service depends on the controller module which defines the interface, and creates and registers an implementation:

@ServiceProvider(service=MyService.class)
public class MyImpl implements MyService {
    public void doSomething() {....}
}

It is also possible to declaratively mask other people's implementations and declaratively order implementations so some will take precedence.

3. The controller finds all implementations and uses them somehow:

for (MyService s : Lookup.getDefault().lookupAll(MyService.class)) {
    s.doSomething();
}

More About Lookup


Applies to: NetBeans 6.7

Using Event Bus in NetBeans

Dne Monday 26 November 2007 17:37:48 Rob Ratcliff napsal(a):
> For the bus we developed, we could subscribe by a specific type, for all
> subclasses of a type or for certain message header attributes of an
> event. We also had a bus per "session" (the GUI could display multiple
> sessions/workspaces using tabs -- equivalent to a JMS topic)  so that
> only events related to that session would be delivered. And, like I
> mentioned earlier, there was support to register as a "GUI" listener or
> a "business" listener so that events would automatically be delivered in
> the correct thread to avoid EDT lockup and rendering issues.
>
> I'd be interested in hearing what you and others think about these types
> of capabilities and how they compare to the NetBeans paradigms.

I've been thinking about this for a while and I believe that there is event bus like system in NetBeans. It is Utilities.actionsGlobalContext()

We have our event bus and it is accessible via Utilities.actionsGlobalContext(). Indeed it may not be perfect, but it plays exactly the role described in the presentation. Menu, Toolbar, etc. listen on it, while somebody else updates it.

Indeed, there could be some improvements. We do not support merging of events or network access, but if one really cares, there is a way to plug into the system. All one needs to do is to implement ContextGlobalProvider One sample implelemention is in openide/windows and second in imagine.dev.java.net.

I've heard a complain that...

> This is a central listener, not an event bus

... however this boils down to a question: How do you envision an event bus? It is a place to contain events or objects that somehow appear in the system. It allows anyone to selectively listen on what is happening in the bus

So in fact event bus is a central listener. Just like Utilities.actionsGlobalContext().

Indeed it could be improved. Is there anyone who would like to contribute in improving our actionsGlobalContext? If so, what should be done?

Hi Jaroslav,

I think it'd be useful to define exactly what an event bus is (like you 
mentioned),  what use cases it supports and how NetBeans supports these 
use cases currently and how it might support these in the future.

I used an EventBus approach in my last project  for receiving 
asynchronous data events from the Network (such as position updates, 
network status events) and internal events such as service status 
(network disconnected) and other state change events such as "sensor 
network reconfigured"...essentially when it made more sense to use a hub 
and spoke communication model rather than a point-to-point.  There could 
be multiple instances of the EventBus, which used a  EDT type of model 
(dispatcher thread/queue) and supported subscriptions by type (any event 
derived from a base class)  or property of the header. 

Since the "Lookup Library" allows you to uncouple senders from receivers, and allows receivers to be notified of changes, I consider it as a small event bus.

I consider "local lookups" as a small event bus, where you can listen to different "event topics". In the previous case, it would probably be enough to dedicate on Lookup for the network events and create various types holding enough information about the events. The you could add/remove/change the content of the lookup and deliver events about such changes.

The instances 
could be looked up globally or injected into a given component. It 
supported "business" and "GUI"  subscriptions to automatically deliver 
the event in the correct thread. If I did it again,  I'm  thinking I'd 
use a JMS style API that supported a Hibernate style OQL subscription.
(I have some more details here: 
http://developers.sun.com/learning/javaoneonline/j1sessn.jsp?sessn=TS-3723&yr=2007&track=2)

The EventBus talk given at JavaOne 2006 had some great use case examples:
EventBus
https://eventbus.dev.java.net/HopOnTheEventBus-Web.ppt

These frameworks provide some other use cases and API examples:

D-Bus
http://www.freedesktop.org/wiki/Software/dbus
http://www.freedesktop.org/wiki/IntroductionToDBus

JUIPiter
 http://juipiter.sourceforge.net

Bradlee Johnson's ReflectionBus
 http://sourceforge.net/projects/werx/

Jasper-Potts - Why Spaghetti Is Not Tasty: Architecting Full-Scale 
Swing Apps, 2007 JavaOne Conference, TS-3316
http://developers.sun.com/learning/javaoneonline/j1sessn.jsp?sessn=TS-3316&yr=2007&track=2

(Also see the JMS API and the OMG COS Notification Service API.)

I don't have much time to spend a lot of time coding on the side right 
now, but I'd be happy to help define requirements and use cases if that 
would be useful to you.

Thanks!
Rob

How can I add support for Lookups on nodes representing my file type?

DataObject does not yet support a getLookup() method, but is expected to do so in the future.

You can simulate this behavior in the meantime by using InstanceContent and AbstractLookup. Simplified typical usage:

public SomeObject {
   private InstanceContent content = new InstanceContent();
   private final AbstractLookup lkp = new AbstractLookup(content);
   
   public someMethod() {
      ic.set (someCollection...);
   }

   public Lookup getLookup() {
      return lkp;
   }
}

This is how you create a lookup with dynamic content of your choosing. See also Tom Wheeler's TodoListManager for an example of some code that illustrates how to do this.

How do I use Java Generics with Lookup?

As of NetBeans 6, a number of convenience methods have been added to lookup, and support for Java generics has been added to Lookup. The following are differences:

NB 5.x Code NB 6 Code
Lookup.Result r = lkp.lookup( new Lookup.Template(X.class))Lookup.Result<? extends X> r = lkp.lookupResult(X.class)
Collection c = r.allInstances()Collection<? extends X> c = r.allInstances()
Lookup.Template t = new Lookup.Template(X.class); Lookup.Result r = lkp.lookup(t); Collection c = r.allInstances();Collection<? extends X> c = lkp.lookupAll(X.class);

The new style also works well with for-loops and avoids casts:

for (SomeService s : Lookup.getDefault().lookupAll(SomeService.class)) {
    // ...
}
// ...
SomeSingleton s = Lookup.getDefault().lookup(SomeSingleton.class);
if (s != null) {
    // ...
}

How can I override an instance in the Lookup?

As a result of NetBeans design for extensibility, you'll find a lot of code like this:

DialogDisplayer displayer = DialogDisplayer.getDefault();

in which an API is defined (DialogDisplayer) as an abstract class or interface and an implementation is indirectly made available through a static method like {getDefault(). This approach gives you a default implementation of DialogDisplayer, but also lets you "plug in" a different one of your own design.

How do you do that? First, here's the implementation of the {getDefault() method:

public static DialogDisplayer getDefault() {
    DialogDisplayer dd = (DialogDisplayer) Lookup.getDefault().lookup(DialogDisplayer.class);

    if (dd == null) {
        dd = new Trivial();
    }

    return dd;
}

As you see, it will attempt to find some instance of DialogDisplayer from the default Lookup (in other words, one that has been registered via META-INF/services/). If it cannot find one, it will return the default implementation (an instance of Trivial, which is an inner class of DialogDisplayer).

Therefore, it seems that you could override the default simply by registering your own implementation of DialogDisplayer). If you tried it, you'd find it doesn't work (or at least may not work consistently) because there are already other instances registered and they'll likely take precedence over yours.

So, how do you mask out any other implementations so that yours will be used? In the file where you register the new implementation (META-INF/services/org.openide.DialogDisplayer in this case), you will prefix the other implementation with a pound sign and a minus sign before listing your own on a different line. For example, here's what the file should look like:

#-org.netbeans.core.windows.services.DialogDisplayerImpl
com.tomwheeler.example.SpecialDialogDisplayerImpl

More information about this and other Lookup-related topics, including how to set the order of registered services, can be found in the Utilities API documentation.

How do I implement my own lookup or proxy another one?

It is not uncommon to be subclassing an class, such as TopComponent or Node which has a method getLookup(), and to need to add to or filter the original Lookup's contents. There are a number of convenience factories and classes which make it easy to do this:

If you need to customize a Node's lookup, read the FAQ item on how to do that.

How do I lazy-load an item in the Lookup?

A node is typically used to represent some business object and it's a common idiom to place that business object in the node's lookup so that, for example, a context-sensitive action can operate on it. Sometimes fully initializing that business object can involve an expensive operation that would be wasted effort if the user never invoked the action that used it anyway.

So how can you defer loading or initializing the business object until it is truly needed?

There are probably several ways, but two common ones are:

Override the beforeLookup(Lookup.Template<?> template) method

If you are using the AbstractLookup class to create the lookup, you can override the beforeLookup(Lookup.Template<?> template). By doing this, you will be notified just before a lookup query is processed and you could check to see if the template would match the objects for which you've deferred loading, giving you an opportunity to load them now and add them to the InstanceContent used by the AbstractLookup.

Use InstanceContent.Convertor to create a placeholder object

The InstanceContent.Convertor class can be registered in an AbstractLookup such that it provides a typesafe placeholder until the actual object type is requested, and at that point, the convertor can create and return the actual object.

Consider the following example in which you have a Token class which represents a database record ID and a business object class AnExpensiveClass which will be populated from the database based on the supplied token's ID.

Token.java

public final class Token {
      
    private final long id;

    public Token(long id) {
        this.id = id;
    }

    public long getId() {
       return id;
    }
}

LazyLoadingDelegate.java

import org.openide.util.lookup.InstanceContent;

public class LazyLoadingDelegate implements InstanceContent.Convertor<Token, AnExpensiveClass> {

    @Override
    public AnExpensiveClass convert(Token token) {
        // this will be called when something actually requests an instance 
        // of AnExpensiveClass from the lookup.  We just need to create and
        // return an instance based on the supplied token (i.e. assume that 
        // the AnExpensiveClass constructor will load data from the database 
        // and populate the instance we're returning).
        return new AnExpensiveClass(token);
    }

    @Override
    public Class<? extends AnExpensiveClass> type(Token token) {
        return AnExpensiveClass.class;
    }

    @Override
    public String id(Token token) {
        return String.valueOf(token.getId());
    }

    @Override
    public String displayName(Token token) {
        return "my lazy loading delegate";
    }
}

Code that creates a Lookup and registers the InstanceContent:

    ic = new InstanceContent();
    al = new AbstractLookup(ic);
        
    Token token = new Token(12345);
    ic.add(token, new LazyLoadingDelegate());

And your context-sensitive action will look like normal; it does not need to know about the lazy loading (code not relevant to lazy loading has been removed for the sake of brevity):

public final class ExpensiveClassAction extends CookieAction {

    @Override
    protected void performAction(Node[] activatedNodes) {
        AnExpensiveClass expensiveClass = activatedNodes[0].getLookup().lookup(AnExpensiveClass.class);
        // now you have the actual do AnExpensiveClass instance, so do something with it...
    }

    @Override
    protected Class[] cookieClasses() {
        return new Class[]{AnExpensiveClass.class};
    }

    @Override
    protected boolean asynchronous() {
        return true;
    }
}

If there is more than one of a type in a Lookup, which instance will I get?

As noted in the overview of Lookup, a Lookup can contain more than one instance of a given class; Lookup is often used for singletons, but not exclusively for singletons. For example, in the Projects API , there is a class called ProjectFactory that recognizes different types of user projects on disk; each module that provides a project type registers another factory in the system.

So the inevitable question is, if there are two instances of X in a Lookup, and I call lookup(X.class), which one do I get?

The answer is, it's undefined - don't do that. The next inevitable question is, but how can that be?

A Lookup makes no assumptions about what's in it, or what you might want to put in it, or how many of anything there should be. That contract is an agreement between whoever tells you that you should get an instance of X from some Lookup and you. If they document that there will only be one, use Lookup.lookup(Class); if they document that there can be more than one, use Lookup.lookup(Lookup.Template) and iterate the results.

In practice this is a non-problem - anything you are going to try to find in a Lookup is going to document whether it is supposed to be a singleton or not.

Q: After adding my class to lookup I get a ClassNotFoundException when trying to look it up, why?

A: You might have tried to place the interface and the implementation class in different modules but used the same package name. NetBeans prohibits two or more modules to define classes in the same package. Choose a distinctive package name (or package name prefix) for each module.

Why use this strange convention - wouldn't a Map be good enough?

Other platforms do use string-keyed maps for this sort of thing, but there are some weaknesses with that approach:

  1. it is impossible to enforce dependencies . With Lookup, a module's code cannot request an object unless it can access the object's class, and it won't be able to access the object's class unless it declares a dependency on the API module that defines it. (A <T> Map<Class<T>,T> would do the same job as Lookup.)
  2. The class of values in a map can change without notice - so if you have (SomeIface) foo = (SomeIface) globalMap.get("foo"), some new version of the module that provides "foo" can change the return type, causing ClassCastException s; with Lookup, you cannot ever get an object that is not of the type you passed in the request - so Lookup's approach is more robust. (Again, a generics-aware Map might be able to solve this.)
  3. Lookup supports listening to changes in the result.
  4. Lookup supports multiple instances for one key. (Sort of like <T> Map<Class<T>,List<T>> )

There are some other capabilities of Lookup (such as getting classes of results without instantiating them, and naming result items) but these are rarely used in practice.

Lookup is very powerful, yet simple and generic; people quickly learn to love it, once they realize what it can do.

What uses Lookup?

There are a number of places Lookup is commonly found/used in NetBeans. Generally, if you have found some class and you are wondering where on earth you get an actual instance of one of those, the answer is probably "from something-or-other's Lookup".

Common cases:

How can I create declarative MIMEResolver and add new file type?

There is a wizard available for NetBeans modules which does this for you. Just run New File | Module Development | File Type. Fill in the MIME Type text field and choose whether to recognize file by extension or XML root element. If you want more sophisticated recognition, choose "by Filename Extension" and edit created resolver xml after you finish the wizard. In the next step type in "Class Name Prefix" your preferred prefix and finish the wizard.

Description of declarative MIME resolve can be found in this document. In most cases it should be enough to resolve files only by their extensions as the wizard does (see ext element). Other types of resolution can be more time expensive, so use them only exceptionally. Useful can be file name matching, file content matching or magic matching for binary files. Also consider existence of exit element intended for negative matching which can skips next conditions.


Applies to: NetBeans 6.1+, pattern and name elements to 6.7+

Related: DevFaqFileRecognition

How do I change the closing action of the MainWindow?

When you click the close button in the top right corner the application closes. If you want to do something before the application closes (e.g. show a dialog with OK and Cancel options) or prevent it from closing, this is possible.

Make a class in your module that extends org.openide.modules.ModuleInstall. There is a Module Installer template that will create this class for you.

Override the closing method and insert your special logic. If you return false the application will not exit.

How do I make a file template which actually creates more than one file?

For example, say you want to make a template which will appear in File | New File which will prompt the user for a name and location but then actually create several related files.

Just use an arbitrary empty file as the template, and declare it to have an instantiatingWizardURL attribute with an instance of WizardDescriptor.InstantiatingIterator. The wizard iterator can specify any sequence of Swing panels you like to ask the user whatever questions you like, and at the end it can do whatever you like to create the new files. Return the created files in instantiate().

Here is an example of a wizard that creates a number of files. This is the layer file that declares it (look at emptyLibraryDescriptor).

You may wish to reuse a standard GUI panel for picking a folder and name, as in Templates.createSimpleTargetChooser.

The NetBeans 5.0 module development support has a (meta-)wizard New Wizard. Choose New File for Registration Type and follow the wizard steps.


Applies to: NetBeans 5.0, 5.5, 6.X

How can I fix memory leaks?

The first problem is to identify what is the root problem causing memory to not be used effectively. The usual approach for this is to analyze the complete contents of memory when the problem appears, using one of a number of appropriate tools, and ideally then find a solution.

Below are some hints on how to analyze the content of memory:

jmap and built-in dumpers in JDK

Obtain the dump.

If the problem causes OutOfMemoryError, it is possible to customize the JVM to provide a memory dump automatically whenever an OutOfMemoryError is thrown. FaqNetBeansAndOOME describes what options can be used for this. If you are developing modules, it is a very good idea to set the option -J-XX:+HeapDumpOnOutOfMemoryError.

If the memory leak is not so aggresive to fill all the available memory and cause an OutOfMemoryError, it is still possible to use jmap to generate the same dump. Running full GC before you create this dump can be a good idea as it can strip the size of dump file and remove some unimportant objects from the snapshot. You can do this by turning memory toolbar on (do a right click in toolbar area and check Memory). Repeating this several times can even collect large amounts of data held in various caches throug soft or weak references and make it easier to browse the dump.

Analyze the problem.

Once you have the dump of the heap in a file, it is possible to open it using the NetBeans profiler. This has a number of analysis features and is integrated with the IDE, e.g. to browse sources.

Alternately, you can use the JDK's tool jhat. It will start simple web server and you can use a web browser to see the data. There are many functions starting with lists of classes with numbers of objects and their size, navigation between references, finding of reference chains from GC root to certain objects. JavaScript can be used to express more complex queries.

Other tools

INSANE is a home-grown tool that is useful for analysis of memory content and also can be used in automated tests - so once you have fixed a memory leak, you can write a test that will fail if the memory leak is ever recreated. NbTestCase.assertGC is all you need to know.

DTrace can be used to monitor object allocation and garbage collection. Nice article about using DTrace with the HotSpot provider: Java and DTrace

Tips and tricks

Common leaking objects

There are some typical classes where it should be easily possible to tell what the appropriate number of their instances in memory should be, and if these are leaking there is a serious problem:

Leaks vs. retained memory

There are two different ways how memory can be wasted: leaks and improper retention of memory.

Leaks are cases when repeated invocation of certain activity creates new set of objects that cannot be reclaimed after activity is finished. The biggest problem is accumulation of these objects that leads to increased memory usage and after a long enough time leads to OutOfMemoryError. The nature of this error is that it leaves data structures of an application in undefined state so anything executed after this moment may lead to unexpected results.

Retained memory is memory occupied by objects that were created to serve some purpose but these objects are held longer than necessary. This may mean that some action has to be performed that flushes these objects or they will remain in memory until the end of the session. An example of the former is LRU caches (often holding last component in UI, files or projects). A common example of the latter is resources like parsed bundles or images statically referenced in classes that use them.

-J-Dnetbeans.debug.heap can make profiling easier as it more quickly releases references to collapsed nodes.

If you have the Timers module enabled (normally it is in dev builds), click its button in the Memory toolbar to get a summary of interesting live objects and statistics.


Applies to: NetBeans 6.5

Platforms: All

Is it safe to programmatically modify a file which is open in the editor?

It is not safe to modify a FileObject (via getOutputStream which is open and modified in the editor. In fact, it is not possible: calling FileObject.lock() will fail. If you modify the java.io.File (bypassing the Filesystems API) you may cause a conflict.

If the file is not modified in the editor (easily checkable via DataObject.isModified() then after your output stream is closed the file will be reloaded with the new contents.

If the file is modified you can make changes to the open editor buffer: use EditorCookie to acquire the Swing Document and make changes through that. It may be considered impolite to then save the file if it was modified before.


Applies to: NetBeans 4.0 and newer

Why am I getting a ClassCastException when the class is clearly of the right type?

Q: I am getting an exception when I run my module, such as

java.lang.ClassCastException: Implementation cannot be cast to Interface
        at Factory.newInstance (Factory.java:123)

But Implementation implements Interface, so why is this a CCE?

A: Usually this is because the Interface that Implementation actually implements was loaded from a different class loader than what Factory sees.

That is very likely the immediate cause of the CCE. The root cause is not always obvious, but it is likely to be that some code uses Thread.currentThread().getContextClassLoader() to load a class by name. In NB by default the context class loader just looks around in loaded modules (lacking any better information), so it is possible for the following situation to arise:

module A: Interface, Factory
module B > A: Implementation implements Interface
module C: Interface, Factory
module D > A: Implementation implements Interface

where Factory does something like:

Interface i = (Interface) Class.forName("Implementation", true,
    Thread.currentThread().getContextClassLoader()).newInstance();

(This is a common design pattern for XML parsers, etc.)

Now if A's Factory happens to get D's Implementation (or C's gets B's) then you get a CCE at runtime.

An especially silly variant of this problem, known to occur at least in Xerces, is that Implementation actually resides in the same JAR as Interface and Factory, and is the standard impl almost everyone uses unless overridden somehow - yet Factory loads it by name from the CCL rather than simply loading it directly using e.g. new Implementation().

The usual workaround is to wrap the problematic call(s) in a dynamic block:

ClassLoader orig = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(SomeReferenceClass.class.getClassLoader());
try {
  Factory.load(...);
} finally {
  Thread.currentThread().setContextClassLoader(orig);
}

Note: NetBeans forbids ambiguous delegations. (Issue 118020) If a class could be loaded from two (or more) places, it will not be loaded at all. This does not solve your problem but it at least ensures it gets reported more reliably and with a descriptive message rather than an odd ClassCastException.


Applies to: NetBeans 6.5, 6.7

How do module dependencies and class loading work?

The nuts and bolts of module dependencies are as follows:

  • Modules can load classes from modules they depend on. They have to declare a dependency on them.
  • NetBeans does not care about things like the CLASSPATH environment variable - it knows how to find modules in an installation of NetBeans, and enforces dependencies between them.

What this means is that if

  • Module B tries to use a class from module A, but module B does not explicitly state that it depends on A, or...
  • Module B tries to use a class from module A, and it does declare a dependency on Module A, but the package that class is in is not in the list of packages A says other modules can touch...
then a NoClassDefFoundException will be thrown at runtime. (If you even get that far - the module build harness will refuse to even compile module B in such cases.)

An exception to the second item is that if Module B declares an implementation dependency on module A, then it will have access to the full set of classes. Normally you should not need to do this, and anyway it will then be hard to upgrade B independently of A.

Modules can also load classes from libraries - JAR files that are packaged with the module (see DevFaqHowPackageLibraries). Some points to remember about libraries:

If you are using the IDE's module development support, you will manage module dependencies in the properties dialog for your module (or the Libraries node in the Projects tab). This just modifies yourmodule/nbproject/project.xml. The data saved there is then used to generate the appropriate manifest entries for you.

If you are writing a module that will use some third party libraries, you probably want to read DevFaqWrapperModules and also DevFaqWhenUseWrapperModule.

For more details, see the reference documentation about classloading in NetBeans.


Applies to: NetBeans 6.5

Can two or more modules contain the same package?

Yes, NetBeans (as of 6.1) does permit multiple modules to load from a single package. However, this should be considered poor style and avoided whenever possible. In particular, the Java runtime forbids package-private accesses between classes defined by different class loaders (e.g. classes contained in different modules).


Applies to: NetBeans 6.1+

How can code in one module be notified when other modules are loaded or unloaded?

Let's begin by stating that you probably do not need to know when other modules are loaded or unloaded. The module system takes care of dependency management for you, so your module should never be loaded unless all of its stated dependencies are loaded too.

The normal means of communicating between modules about available services (which you could consider indirect dependencies) is using the Lookup API. If what you really wanted was to know when a service became available, you do not need to listen to module load or unload events as such; which module hosts the service is not of direct interest. Instead:

  1. Define a service some.Interface in some module.
  2. Implement that interface using some.Implementation in some other module.
  3. Register that implementation: ---%<--- src/META-INF/services/some.Interface some.Implementation ---%<--- (In NetBeans 7.0+, you can simply use the @ServiceProvider annotation.)
  4. In some module consuming the service, use import some.Interface; // ... private static final Lookup.Result<Interface> services = Lookup.getDefault().lookupResult(Interface.class); static { services.addLookupListener(new LookupListener() { public void resultChanged(LookupEvent ev) { // some module was loaded or unloaded! } }); } // ... for (Interface service : services.allInstances()) { // use a currently available service }

If you simply want to run some code when your module loads or unloads, registering an instance of ModuleInstall will do the trick. There is even a wizard in the IDE for setting this up.

But in the very rare case that you want to be notified when other modules are loaded or unloaded, it is possible because:

  1. You can use Lookup.Result to listen to changes in the contents of a Lookup, even the global lookup.
  2. Every module installs an instance of ModuleInfo into the default Lookup so the module system (or other code) can find out details about the module including its code name base, version numbers and display name.

By using these two facts together, it is possible to listen to changes in the installed modules by running code like this at some point in the application's lifecycle:

final Lookup.Result<ModuleInfo> result = Lookup.getDefault().lookupResult(ModuleInfo.class);
result.addLookupListener(new LookupListener() {
    public void resultChanged(LookupEvent event) {
        // it seems a module was installed or removed
    }
});

Once you detect that a module has been created you may also want to register a PropertyChangeListener and listen to ModuleInfo.PROP_ENABLED. (A module present in the installation will provide a ModuleInfo but isEnabled might be false if it is not currently loaded.)


Applies to: NetBeans 6.5, 6.7

Can I obfuscate a module?

If you want to protect a NetBeans module from disassembly, you can obfuscate it. For example you can use ProGuard, an open-source obfuscator.

  1. Copy proguard.jar somewhere on disk, referenced by proguard.jar.path.
  2. Edit the build.xml of your module and override some targets as in the following excerpt:
<!-- Replace the non-obfuscated jar with the obfuscated one when compiling -->
<target name="netbeans-extra" depends="obfuscate">
    <copy file="${suite.dir}/build/obfuscated/${module.jar}" tofile="${cluster}/${module.jar}"/>
</target>

<!-- Overridden debug target that depends on netbeans-debug -->
<target name="debug" depends="netbeans-debug,-jdk-presetdef-nbjpdastart">
    <ant antfile="${harness.dir}/run.xml" target="debug"/>
</target>

<!-- netbeans-debug DOES NOT depends on netbeans-extra (then DOES NOT depends on obfuscate) -->
<target name="netbeans-debug"
        depends="init,jar,module-xml-regular,module-xml-autoload,module-xml-eager,javahelp,module-auto-deps,release,verify-class-linkage">
    <genlist outputfiledir="${cluster}" module="${module.jar}">
        <fileset dir="${cluster}">
            <patternset refid="module.files"/>
        </fileset>
    </genlist>
</target>

<!-- Overridden to delete also the obfuscated jar -->
<target name="clean" depends="files-init,testuserdir-delete">
    <delete failonerror="false" includeemptydirs="true">
        <fileset dir="build">
            <exclude name="testuserdir/"/>
        </fileset>
    </delete>
    <delete dir="${netbeans.javadoc.dir}/${code.name.base.dashes}"/>
    <delete file="${netbeans.javadoc.dir}/${code.name.base.dashes}.zip"/>
    <delete failonerror="false"> <!-- #59457: OK if cluster does not exist currently -->
        <fileset dir="${cluster}">
            <patternset refid="module.files"/>
        </fileset>
    </delete>
    <delete file="${cluster}/update_tracking/${code.name.base.dashes}.xml"/>
    <delete file="${suite.dir}/build/obfuscated/${module.jar}"/>
</target>

<!--  Just a cut and paste of how the proguard obfuscator works.
      This is not supposed to work below.  In fact, this seems to work
      on jars, not .class files, so it will have to be placed in a
      post jar target, which I haven't identified yet -->
<target name="obfuscate" depends="init">
    <taskdef resource="proguard/ant/task.properties"
             classpath="${proguard.jar.path}" />

    <echo message="Obfuscating ${cluster}/${module.jar}..."/>
    <mkdir dir="${suite.dir}/build/obfuscated"/>
    <proguard printmapping="${suite.dir}/build/obfuscated/${code.name.base.dashes}.map"
              renamesourcefileattribute="SourceFile" ignorewarnings="true">

        <!-- Specify the input jars, output jars, and library jars. -->
        <injar  file="${cluster}/${module.jar}" />
        <outjar file="${suite.dir}/build/obfuscated/${module.jar}" />

        <libraryjar path="${module.run.classpath}" />
        <libraryjar file="${nbjdk.home}/jre/lib/rt.jar" />

        <!-- Keep some useful attributes. -->

        <keepattribute name="InnerClasses" />
        <keepattribute name="SourceFile" />
        <keepattribute name="LineNumberTable" />
        <keepattribute name="Deprecated" />
        <keepattribute name="*Annotation*" />
        <keepattribute name="Signature" />

        <!-- Preserve all public classes, and their public and protected fields and methods. -->

        <keep access="public">
            <field  access="public protected" />
            <method access="public protected" />
        </keep>


        <!-- Preserve all .class method names. -->

        <keepclassmembernames access="public">
            <method type      ="java.lang.Class"
                    name      ="class$"
                    parameters="java.lang.String" />
            <method type      ="java.lang.Class"
                    name      ="class$"
                    parameters="java.lang.String,boolean" />
        </keepclassmembernames>

        <!-- Preserve all native method names and the names of their classes. -->

        <keepclasseswithmembernames>
            <method access="native" />
        </keepclasseswithmembernames>

        <!-- Preserve the methods that are required in all enumeration classes. -->

        <keepclassmembers extends="java.lang.Enum">
            <method access="public static"
                    type="**[]"
                    name="values"
                    parameters="" />
            <method access="public static"
                    type="**"
                    name="valueOf"
                    parameters="java.lang.String" />
        </keepclassmembers>

        <!-- Explicitly preserve all serialization members. The Serializable
             interface is only a marker interface, so it wouldn't save them.
             You can comment this out if your library doesn't use serialization.
             With this code serializable classes will be backward compatible -->

        <keepnames implements="java.io.Serializable"/>
        <keepclassmembers implements="java.io.Serializable">
            <field  access    ="final"
                    type      ="long"
                    name      ="serialVersionUID" />
            <field  access    ="!static !transient"
                    name      ="**"/>
            <field  access    ="!private"
                    name      ="**"/>
            <method access    ="!private"
                    name      ="**"/>
            <method access    ="private"
                    type      ="void"
                    name      ="writeObject"
                    parameters="java.io.ObjectOutputStream" />
            <method access    ="private"
                    type      ="void"
                    name      ="readObject"
                    parameters="java.io.ObjectOutputStream" />
            <method type      ="java.lang.Object"
                    name      ="writeReplace"
                    parameters="" />
            <method type      ="java.lang.Object"
                    name      ="readResolve"
                    parameters="" />
        </keepclassmembers>

        <!-- Your application may contain more items that need to be preserved;
             typically classes that are dynamically created using Class.forName -->

    </proguard>
</target>

In this way when running and when creating the NBM (as well from a suite) the module will be obfuscated. When debugging your module you use the non-obfuscated JAR, so you can step through source as well.


Applies to: ??? (unverified)

How do I create a patch for a preexisting NetBeans module?

If you need to patch an existing module, you can place a JAR file relative to the original. For example, to patch ide5/modules/org-openide-example.jar you make a JAR like ide5/modules/patches/org-openide-example/mypatch.jar. The mypatch part of your JAR file patch can be named anything you like. The JAR file should only contain those classes you want to patch. It does not need a manifest, though an empty manifest is harmless.

The patch must be in the same cluster as the original. (Issue 69794) If you want to create an NBM containing a patch, you must ensure it will be installed in the same cluster (use the nbm.target.cluster property), but note that you cannot test such a dummy module as part of a module suite (since this property is interpreted only by Plugin Manager). If you are distributing a complete application including a patch to the NB Platform, you will need to either manually preinstall the patch JAR in your copy of the Platform; or override your build-zip target to include the JAR in the final ZIP (in which case testing using Run Project will not have the patch active).


Applies to: NetBeans 6.x

Installing things declaratively as opposed to programatically

Long ago, in a galaxy far far away, most objects in NetBeans were created during startup. That works fine for a small application. It is disaster for a large application - with each new component in the system, startup time gets longer, garbage collections get more frequent and memory requirements rise.

Because of this, today, most of the APIs you will use to install things into the system involve a text entry (DevFaqWhenToUseWhatRegistrationMethod), such as putting something in an XML file (DevFaqModulesLayerFile), not running Java code. Ideally a module should do nothing on startup. Let's say that again, forcefully: Ideally a module should do nothing on startup.

The main ways to do this are using @ServiceProvider or using annotations which create XML layer entries that declare information about the things your module is installing. Then, when they are needed to do actual work, your objects will be instantiated.

If you really need to run some code on startup, see DevFaqWhenToUseWhatRegistrationMethod about ModuleInstall.


Applies to: NetBeans 6.7

What are the ways a module can influence the system?

There are four basic ways a module can install configuration data or objects. Three of the ways are declarative (DevFaqModulesDeclarativeVsProgrammatic); these mechanisms are preferred.

If you are writing a module that has an API you want other modules to plug in to, you probably want to read DevFaqWhenToUseWhatRegistrationMethod.

@ServiceProvider

For global services, singletons and such, this is the preferred way. In NetBeans 6.7+, you can simply use the @ServiceProvider annotation.

What exactly you register is a contract between you and whatever module is providing the interface and will, presumably, do something with what you put there. What's really happening is that you are adding your implementation of this interface to the default lookup (see DevFaqLookupDefault).

Any module can specify interfaces that it would like other modules to register instances of. For example, the basic Project support module asks that each module that implements a project type (the things you see in the New Project wizard in NetBeans) register their ProjectFactorys there.

To get an instance of something registered this way, call

TheInterface i = Lookup.getDefault().lookup(TheInterface.class);

If there can be more than one registered object of this type, you can get them all as follows:

for (TheInterface i : Lookup.getDefault().lookupAll(TheInterface.class)) {...}

Registering objects in the System Filesystem

The system filesystem (see DevFaqSystemFilesystem) allows for more detailed information in registering objects. It is a virtual filesystem composed of XML fragments (see DevFaqModulesLayerFile) from all (well, most) of the modules in the system. The top layer of the system filesystem is $USERDIR/config which is where changes that are written at runtime are put.

The system filesystem is composed of folders. Some folders have special meanings to the system; what folders exist and are meaningful depends on what modules you have installed. For example, the core window system defines the folder Menu/, which contains subfolders - one for each menu in the main window's menu bar. If you add a file to the folder Menu/File called com-foo-mymodule-MyAction.instance, an instance of com.foo.mymodule.MyAction will be created, and a menu item will be put on the menu for it.

For more details on registering objects, defining an order in which they should appear, etc., see the DevFaqModulesLayerFile. In the short form, a module registers a layer by including a line in its manifest:

OpenIDE-Module-Layer: com/foo/mymodule/resources/layer.xml
which points to an actual XML file by that name inside the module JAR file. A layer file is an XML file defining a mini-filesystem:
<filesystem>
    <folder name="SomeFolder">
        <file name="SomeFile"/>
    </folder>
</filesystem>

Starting with NetBeans 6.7, more or more layer registrations can be made by using various source code annotations. If you use these exclusively, you will not need to declare a layer in your module's sources at all.

Registering objects in the module's manifest

Some types of objects used to be installed by adding a section to the module manifest. This is now deprecated.

Programmatic registration - ModuleInstall classes

The module system allows you to provide a ModuleInstall class, which runs some code during startup or when the module is loaded, and can run cleanup code when it is uninstalled or disabled. This is the least desirable way to do things, because running code on startup means slowing down startup. Before you use such a class, be sure there is no declarative way to do what you're trying to do; see: DevFaqModulesDeclarativeVsProgrammatic

To have some code run on startup/installation/uninstallation/etc., add a line like the following to your module's manifest file:

OpenIDE-Module-Install: org/netbeans/modules/paintcatcher/PaintCatcherModule.class
This line should be part of the group of lines at the top of the manifest, with no blank lines before it. It is a pointer to a class file inside the module. The class file must extend the class org.openide.modules.ModuleInstall. There is a wizard in the development support to create and register such a class for you.
Applies to: NetBeans 6.5, 6.7

What is a layer file, or "module layer"?

Layer files are small XML files provided by modules, which define a virtual filesystem (DevFaqFileSystem). The layer file defines folders and files that will be merged into the system filesystem (DevFaqSystemFilesystem) that makes up the runtime configuration information NetBeans and its modules use.

Layer files help to make it possible for modules to be dynamically installed. If you've read about FileObjects (DevFaqFileObjects) and FileSystems (DevFaqFileSystems), you know that you can listen for changes in folders and files in a filesystem. That's exactly what the components of NetBeans whose content is composed from folders in the system filesystem do. So if a module is added at runtime, the system filesystem fires changes; the UI notices that the contents of the folder has changed and updates the UI to reflect the changes.

If you created your module using the IDE, you may already have an XML layer in your module, and you can expand the node for it under Important Files in your module project to see and modify its contents. The way it is declared is simple:

OpenIDE-Module-Layer: com/foo/mymodule/resources/layer.xml

Starting with NB 6.7, some Java source code annotations generate layer entries for you (you do not need to have a layer.xml in your module's source tree).


Applies to: NetBeans 6.5, 6.7

How do I run some code when my module starts/loads/unloads?

To run some code when your module is loaded, and basically every time the IDE starts and your module is enabled, simply create a subclass of org.openide.modules.ModuleInstall and override the restored() method. Bear in mind that this is being executing during the time the IDE/platform is starting up. You should limit the work you do here to that which is absolutely necessary.

Once the class is created, you must declare it in your module's manifest.mf file, like so:

OpenIDE-Module-Install: org/netbeans/modules/editor/EditorModule.class

Likewise, to execute code when the IDE is shutting down, you can override the close() method. This method of ModuleInstall is called when the IDE is shutting down, contrary to the closing() method, which is called to alert the module that the IDE is about to shut down. However, another module may veto the shutdown by returning false from the closing() method, so the close() method is best for performing any cleanup work for your module.

You can simply use File > New File > Module Development | Module Installer to create the ModuleInstall class and its registration in the manifest.


Applies to: NetBeans 6.5, 6.7

Where can I find more documentation on certain APIs?

The NetBeans Javadoc has some additional documentation about using certain APIs. Unfortunately, the index page does not link to these and so they can be difficult to find. Here are direct links to these documents from the most recent builds:

I want to make some programmatic changes to the edited file. How can I do it so one Undo undoes it all?

Create a Runnable that will do all of the code generation/munging you want to do. Pass it to org.openide.text.NbDocument.runAtomic(doc, runnable). Or BaseDocument.runAtomic() can be used (the Document in the editor should be an instance of BaseDocument - it will be for Java files and most other things).

DLLs or SOs can be placed in the folder release/modules/lib/ in a module project's sources (look in the Files tab). This will make them appear in the final NBM or application in a lib subdirectory beneath where the module's JAR resides. Then just use System.loadLibrary as usual.

API Reference: JNI in modules


Applies to: NetBeans 6.5

Common calls that should be done slightly differently in NetBeans than standard Swing apps (loading images, localized strings, showing dialogs)

There are a few cases where NetBeans has convenience classes or facilities that you should use, instead of doing them the way you may be used to. They are:


Applies to: NetBeans 6.5

I want to use one version of the Platform with another version of the build harness. Can I?

Yes, you can use a pristine platform download (or platform built from sources) and use an external harness from another platform version without sacrificing repeatable builds. Just as the in-IDE module development support defaults to using the harness included with the IDE, ignoring the harness bundled with the platform, so you can configure your module or suite to use a specific harness location. As described in harness/README set up a relative path for the platform, but make the harness separate, e.g.

suite.dir=${basedir}
netbeans.dest.dir=${suite.dir}/../nb_sources/nbbuild/netbeans
# Rather than:
#harness.dir=${netbeans.dest.dir}/harness
# use:
harness.dir=${suite.dir}/../special-harness

Applies to: NetBeans 6.5

How to specify post-install code in NBM

NBM allows to declare its own custom code in NBM archive. This code is called-back by Autoupdate/Updater at the end of installation of NBM into IDE.

your_module.nbm
    |   
    +- Info
    |   |
    |   +--- info.xml
    |
    +- netbeans
        |
        +--- modules...
    |
    +-main
        |
        +--- main.properties
        +--- <custom code>

If Autoupdate/Updater detects main directory in the NBM archive then main.properties descriptor contains information about the own code. Updater runs specified Java code according to these properties.

The properties expected in main.properties are:

PropertyValue
mainClassname of the main class, run after module installation from the NBM
relativeClassPathclasspath elements, may contain more elements
jvm.parametersproperties for JVM, arguments inserted before the main class name
mainClass.argumentsmore arguments for the main class, added after the main class name

The run command is built on top of properties above.

[#1] Problem: There was a bug: variable %IDE_USER% contained as same value as %IDE_HOME% i.e. both links to the platform cluster directory and %IDE_HOME% didn't contain user directory as should be. It was fixed in NetBeans 6.5 platform.

The properties can contain several special variables which Autoupdate replaces by real values:

VariableValue
%IDE_HOME%platform directory
%IDE_USER%user directory [1]
%FS%file separator char
%JAVA_HOME%the current Java home

Example

To see that samplepostinstall project in action

  1. download NBM(info)
  2. run NetBeans IDE (6.0 or newer)
  3. invoke Tools|Plugins and switch to Download tab
  4. add the downloaded NBM
  5. install it and then watch post-install hook what will be executed while installing that plugin


I'm not author of this feature, it's only my investigation.

Do not hesitate to contact me on mailto:jrechtacek@netbeans.org if you have any question.

My module uses some libraries. I've tried setting CLASSPATH but it doesn't work. Help!

Setting $CLASSPATH or %CLASSPATH% on the command line will not affect anything - NetBeans uses its own class loader system to find classes from modules.

What you need is for your libraries to be a module; see DevFaqWrapperModules.


Applies to: NetBeans 6.5

Can I test changes to the IDE without going through the license check and so on?

If you set the system property netbeans.full.hack to true, the following IDE behaviors will be disabled to make it quicker or more reliable to test other functionality:

  • Auto Update background check (to see if updates are available); you can still use AU via Tools > Plugin Manager
  • prompting about still-running tasks when shutting down
  • license dialog
  • import of old user directory
  • IDE registration dialog
  • dialog suggesting that you submit usage statistics
  • welcome screen displayed by default and RSS feed refreshed
  • blocking dialog when some modules could not be loaded
  • use of ~/NetBeansProjects/ for newly created projects (java.io.tmpdir will be used instead)
  • resizing gesture submit dialog (? SubmitStatus.resize)

This property is set by default when you:

  • run the IDE from sources using ant tryme
  • run the IDE from a netbeans.org module project using Run Project (ant run)
  • run a functional test using NbModuleSuite or a unit test using NbTestCase

If you need to test one of the suppressed behaviors (e.g. you are working on the license dialog), just do not set this property. For the ant tryme and ant run cases, add

tryme.args=
to nbbuild/user.build.properties or ~/.nbbuild.properties.

How do I set up a NetBeans Platform in the IDE

By default, a NetBeans Platform application will use the developer's copy of the IDE as the platform. This is certainly easy, but there are also drawbacks to using the current IDE as a platform. With that in mind, lets check out, and reference our own copy of the Netbeans source code. This way we can also use breakpoints to step through the Netbeans source code, make changes, and create patches!

At a high level the steps are as follows. First get the Netbeans source code checked out. This part is interesting because what you end up with is a complete copy of the Netbeans source repository on your local file system. The second thing you need to do is build the Netbeans platform using the source repository that you just checked out. This is important because without building the platform you will not have the dependencies required by the platform modules. The next step is to create a new platform reference. Of course the platform to reference will be the one that you just checked out and built. Then finally, in your module suite's project properties, select the platform reference that you just created.

So, in more detail then...

1. Check Out Netbeans Source Code

First get the source code from the Mercurial repository. In the following example the source code is checked out to a local ~/netbeans-repository/ directory. In this example the tilde is used to represent the home directory of your file system.

So far, so good, but you still need to build the source code so that you have a complete Netbeans platform, along with all the jar dependencies.

2. Build The Netbeans Source

Building the Netbeans source is very easy, and very satisfying to watch! Just open up your favorite terminal client and navigate to your local repository.

cd ~/netbeans-repository/main/

Then simply run ant.

ant -Dpermit.jdk6.builds=true

Note, I am choosing to build Netbeans using JDK1.6 so I have to explicitly tell Netbeans that I understand that only JDK1.5 is supported.

It took about 25 minutes for the build to finish on my machine.

3. Create A New Platform Reference In Netbeans

In order to work with the Netbeans platform that you just built it needs to be added as a platform in the IDE.

4. Reference The New Platform

Now just select the platform in your module suite's Project Properties. There you will see a Netbeans Platform dropdown box where you can select the platform that you set up.

Note: I did have to go through and resolve some of the cluster dependencies. That just means that I had to check the dependencies that Netbeans said that other modules needed. Once you get this far it will be very obvious what to do.

Appendix A. Netbeans Platform And Using JDK1.6

In order to use JDK1.6 with the Netbeans source code we need to tell the Netbeans platform that we understand that only JDK1.5 is supported. What you need to do is create a "user.build.properties" file and put it in the nbbuild directory.

touch ~/netbeans-repository/main/nbbuild/user.build.properties

Inside the user.build.properties file put the following line.

permit.jdk6.builds=true

This tutorial applies to: versions 6.7 and earlier of the NetBeans Java IDE.

> I want to add some special
> functionality to the initial handling of xml files with a xul extension, but
> then allow users to use the existing NB functionality for editing,
> validation etc.
>
> Did you solve this without patching?

In 5.0, it can be done without a patch. It does, however, require an impl dependency on xml-core. I'd really like this to be simpler, and a supported API.

See below for issues with pre-release 6.0

Anyway, here's how I do it for an xml flavor called SCXML:

1. in the manifest:

Name: com/nuance/tools/xhmi/ScxmlDataLoader.class
Install-Before: org.openide.loaders.XMLDataObject, 
org.netbeans.modules.xml.core.XMLDataObject
OpenIDE-Module-Class: Loader

2. The loader:
import java.io.IOException;
import org.netbeans.modules.xml.core.XMLDataLoader;
import org.openide.filesystems.FileObject;
import org.openide.loaders.DataObjectExistsException;
import org.openide.loaders.MultiDataObject;
import org.openide.loaders.UniFileLoader;
import org.openide.util.NbBundle;

public class ScxmlDataLoader extends UniFileLoader
{
   
    public static final String REQUIRED_MIME = "application/scxml+xml";
   
    private static final long serialVersionUID = 1L;
   
    public ScxmlDataLoader()
    {
        super("com.nuance.tools.xhmi.ScxmlDataObject");
    }
   
    protected String defaultDisplayName()
    {
        return NbBundle.getMessage(ScxmlDataLoader.class, "LBL_Scxml_loader_name");
    }
   
    protected void initialize()
    {
        super.initialize();
        getExtensions().addMimeType(REQUIRED_MIME);
    }
   
    protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException
    {
        return new ScxmlDataObject(primaryFile, this);
    }
   
    protected MultiDataObject.Entry createPrimaryEntry (MultiDataObject obj, FileObject primaryFile) {
        return new XMLDataLoader.XMLFileEntry (obj, primaryFile); //adds smart templating
    }
   
    protected String actionsContext()
    {
        return "Loaders/" + REQUIRED_MIME + "/Actions";
    }
}


3. The data object:

import java.io.IOException;
import org.netbeans.modules.xml.core.XMLDataObjectLook;
import org.netbeans.modules.xml.core.cookies.DataObjectCookieManager;
import org.netbeans.modules.xml.core.sync.DataObjectSyncSupport;
import org.netbeans.modules.xml.core.sync.Synchronizator;
import org.netbeans.modules.xml.core.text.TextEditorSupport;
import org.netbeans.spi.xml.cookies.CheckXMLSupport;
import org.netbeans.spi.xml.cookies.DataObjectAdapters;
import org.netbeans.spi.xml.cookies.ValidateXMLSupport;
import org.openide.filesystems.FileObject;
import org.openide.loaders.DataObjectExistsException;
import org.openide.loaders.MultiDataObject;
import org.openide.nodes.CookieSet;
import org.openide.nodes.Node;
import org.openide.text.DataEditorSupport;
import org.xml.sax.InputSource;

public class ScxmlDataObject extends MultiDataObject implements 
XMLDataObjectLook
{
    private transient final DataObjectCookieManager cookieManager;
    private transient Synchronizator synchronizator;

    public ScxmlDataObject(FileObject pf, ScxmlDataLoader loader) throws DataObjectExistsException, IOException {
        super(pf, loader);
        CookieSet cookies = getCookieSet();
        cookieManager = new DataObjectCookieManager (this, cookies);

        cookies.add((Node.Cookie) DataEditorSupport.create(this, getPrimaryEntry(), cookies));
       
        InputSource is = DataObjectAdapters.inputSource(this);
        cookies.add(new CheckXMLSupport(is));
        cookies.add(new ValidateXMLSupport(is));
       
        // editor support defines MIME type understood by EditorKits registry        
        TextEditorSupport.TextEditorSupportFactory editorFactory =
            new TextEditorSupport.TextEditorSupportFactory (this, org.netbeans.modules.xml.core.XMLDataObject.MIME_TYPE);
        editorFactory.registerCookies (cookies);

    }
   
    protected Node createNodeDelegate() {
        return new ScxmlDataNode(this);
    }
   
    ////////// XMLDataObjectLook interface /////////////////
    public DataObjectCookieManager getCookieManager() {
        return cookieManager;
    }
   
    public synchronized Synchronizator getSyncInterface() {
        if (synchronizator == null) {
            synchronizator = new DataObjectSyncSupport (ScxmlDataObject.this);
        }
        return synchronizator;
    }
}

4. The layer file:
<filesystem>
    <folder name="Loaders">
        <folder name="application">
            <folder name="scxml+xml">
                <folder name="Actions">
                    <file name="org-openide-actions-OpenAction.instance"/>
                    <attr name="org-openide-actions-OpenAction.instance/org-openide-actions-FileSystemAction.instance" boolvalue="true"/>
                    <file name="org-openide-actions-FileSystemAction.instance"/>
                    <attr name="org-openide-actions-FileSystemAction.instance/sep-1.instance" boolvalue="true"/>
                    <file name="sep-1.instance">
                        <attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
                    </file>
                    <attr name="sep-1.instance/org-openide-actions-CutAction.instance" boolvalue="true"/>
                    <file name="org-openide-actions-CutAction.instance"/>
                    <attr name="org-openide-actions-CutAction.instance/org-openide-actions-CopyAction.instance" boolvalue="true"/>
                    <file name="org-openide-actions-CopyAction.instance"/>
                    <attr name="org-openide-actions-CopyAction.instance/sep-2.instance" boolvalue="true"/>
                    <file name="sep-2.instance">
                        <attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
                    </file>
                    <attr name="sep-2.instance/org-openide-actions-DeleteAction.instance" boolvalue="true"/>
                    <file name="org-openide-actions-DeleteAction.instance"/>
                    <attr name="org-openide-actions-DeleteAction.instance/org-openide-actions-RenameAction.instance" boolvalue="true"/>
                    <file name="org-openide-actions-RenameAction.instance"/>
                    <attr name="org-openide-actions-RenameAction.instance/sep-3.instance" boolvalue="true"/>
                    <file name="sep-3.instance">
                        <attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
                    </file>
                    <attr name="sep-3.instance/org-openide-actions-SaveAsTemplateAction.instance" boolvalue="true"/>
                    <file name="org-openide-actions-SaveAsTemplateAction.instance"/>
                    <attr name="org-openide-actions-SaveAsTemplateAction.instance/sep-4.instance" boolvalue="true"/>
                    <file name="sep-4.instance">
                        <attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
                    </file>
                    <attr name="sep-4.instance/org-openide-actions-ToolsAction.instance" boolvalue="true"/>
                    <file name="org-openide-actions-ToolsAction.instance"/>
                    <attr name="org-openide-actions-ToolsAction.instance/org-openide-actions-PropertiesAction.instance" boolvalue="true"/>
                    <file name="org-openide-actions-PropertiesAction.instance"/>
                </folder>
            </folder>
        </folder>
    </folder>
    <folder name="Services">
        <folder name="MIMEResolver">
            <file name="ScxmlResolver.xml" url="resources/ScxmlResolver.xml">
                <attr name="SystemFileSystem.localizingBundle" stringvalue="com.nuance.tools.xhmi.Bundle"/>
            </file>
        </folder>
    </folder>
    <folder name="Templates">
        <folder name="Other">
            <file name="ScxmlTemplate.scxml" url="resources/ScxmlTemplate.scxml">
                <attr name="SystemFileSystem.localizingBundle" stringvalue="com.nuance.tools.xhmi.Bundle"/>
                <attr name="template" boolvalue="true"/>
            </file>
        </folder>
    </folder>

5. the MIME resolver:
<MIME-resolver>
    <file>
        <ext name="scxml"/>
        <resolver mime="application/scxml+xml"/>
    </file>
</MIME-resolver>

6.0

In pre-release 6.0, this does not quite work. This is because getCookie() in org.netbeans.modules.xml.core.XMLDataObjectLook does not use generics, while getCookie() in org.openide.loaders.MultiDataObject does use generics. There is a bug filed against this. You can work around this by edting xml/core/src/org/netbeans/modules/xml/core/XMLDataObjectLook.java, and patching the line to:

public <T extends org.openide.nodes.Node.Cookie> T getCookie (Class<T> c);

then rebuilding the xml/core module with 1.5.

One should also note that 6.0 has the "Schliemann" module for language support. If your needs are simple ( i.e. you don't want to use templates etc.), it may be easier to start from scratch with that.

My module uses some class from NetBeans' APIs. It compiles, but I get a NoClassDefFoundError at runtime. Why?

Normally this should not happen because the module build harness tries to protect you from such cases. Still, if it does happen, it could mean

  1. your module is trying to use a class, but your module does not declare a dependency on the module that provides that class ... or
  2. you are declaring a dependency on the right module, but you are accessing a class that is not in one of the packages that module says are public (for use by other modules) ... or
  3. your module is not a "friend" of the module that provides the class.

If the problem is #1, you need to declare a dependency on the module where the class is (remember that all of NetBeans APIs are modules, and in separate jars - so if it's the IO API, that's a module org.openide.io, if it's the Window System, that's a module org.openide.windows... and so forth).

Setting dependencies is easy - open the Properties for your project, and choose the Libraries page. (Or just get the context menu for the Libraries node under the project in the Projects window.) Click Add and a small dialog opens - just type the name of a class you need to use, and it will filter the list to find the module that provides that class - so you don't have to memorize a huge list of mappings from classes to modules.

If it's problem #2, then you are already declaring a dependency, but get full access to all classes in a module, you need to declare an implementation dependency (DevFaqImplementationDependency). Be sure you really need to use the class you're trying to use, in this case - it will make your module hard to upgrade because generally it will need to be paired with the exact version of the other module's JAR that it was built with - if that module is upgraded, your module may end up being disabled.

Problem #3 may happen if you change your modules name. If some module declared yours as a friend it will no longer recognize it.

Checking for errors eagerly

For a nice way to resolve all module dependencies at once, to force all of the errors to be exposed simultaneously, just add the following to the command line when starting NetBeans:

-J-Dnetbeans.preresolve.classes=true

The message displayed states that when using this flag, you should not use the -J-Xverify:none flag (often specified in the IDE configuration file), so you may need to edit the .conf file to remove the -Xverify option before using the pre-resolve option.

More tips

For help on working with class paths, please see

http://bits.netbeans.org/dev/javadoc/org-openide-modules/org/openide/modules/doc-files/classpath.html


Applies to: NetBeans 6.x

Platforms: all

Why do my nodes in the Explorer always have an expand-box by them, even though they have no children?

Nodes are not asked for their child nodes until the user tries to expand them - to do otherwise would be very bad for performance. If your Node is not supposed to have child nodes, use Children.LEAF as the children object passed to the constructor. That will eliminate the expand handle.

How do I get a Node for a DataObject?

Very simply:

theDataObject.getNodeDelegate()

How can I prevent (or override) the node deletion dialog?

By default, you will be prompted to confirm your intention whenever you try to delete a node from within an explorer manager view (for example, the projects tab). You can prevent this dialog from being shown, which is handy if the node is not important enough to warrant confirmation or if you want to instead show your own confirmation.

To do this, call setValue("customDelete", Boolean.TRUE) on the node on which you want to suppress confirmation. This can be done at any time before the destroy() method is invoked.

The above will suffice if you just want to suppress the aforementioned dialog which is sufficient for most customization cases. But if you need total control over node deletion, you can implement the ExtendedDelete interface.

How do I select/deselect Nodes?

Applications which manage sets of data items often offer to users the capability of selecting and deselecting all the items currently on the screen with a single menu (or key shortcut). In some cases even a "Invert selection" option could be useful which selects all unselected nodes an vice versa.

Implementing such a feature with the OpenIDE API is quite a simple task. We first define a subclass of SystemAction which listens for changes in the selection of the current TopComponent and tracks the currently active ExplorerManager:

public abstract class ExplorerManagerAction extends SystemAction
  {
    private ExplorerManager activeExplorerManager;

    public ExplorerManagerAction()
      {
        TopComponent.getRegistry().addPropertyChangeListener(new PropertyChangeListener()
          {
            public void propertyChange (PropertyChangeEvent event)
              {
                if (TopComponent.Registry.PROP_ACTIVATED.equals(event.getPropertyName()))
                  {
                    Object value = event.getNewValue();

                    if (value instanceof ExplorerManager.Provider)
                      {
                        activeExplorerManager = ((ExplorerManager.Provider)value).getExplorerManager();
                        setEnabled(true);
                      }

                    else
                      {
                        activeExplorerManager = null;
                        setEnabled(false);
                      }
                  }
              }
          });
      }

    final public void actionPerformed (ActionEvent actionEvent)
      {
        if (activeExplorerManager != null)
          {
            try
              {
                performAction(activeExplorerManager);
              }
            catch (PropertyVetoException e)
              {
                // ...
              }
          }
      }

    abstract protected void performAction (ExplorerManager explorerManager)
      throws PropertyVetoException;

    public HelpCtx getHelpCtx()
      {
        return HelpCtx.DEFAULT_HELP;
      }

    protected void initialize()
      {
        super.initialize();
        putValue("noIconInMenu", Boolean.TRUE);
      }

    protected boolean asynchronous()
      {
        return false;
      }
  }

Now in order to implement the specific node selection actions we just have to subclass and provide a concrete implementation of the performAction() method which takes an ExplorerManager as parameter.

For the "Select All" action we have:

public final class SelectAllAction extends ExplorerManagerAction
  {
    protected void performAction (ExplorerManager explorerManager)
      throws PropertyVetoException
      {
        explorerManager.setSelectedNodes(explorerManager.getRootContext().getChildren().getNodes());
      }
    public String getName()
      {
        return NbBundle.getMessage(SelectAllAction.class, "CTL_SelectAllAction");
      }
  }

For the "Deselect all" action we have:

public final class DeselectAllAction extends ExplorerManagerAction
  {
    protected void performAction (ExplorerManager explorerManager)
      throws PropertyVetoException
      {
        explorerManager.setSelectedNodes(new Node[0]);
      }
    public String getName()
      {
        return NbBundle.getMessage(DeselectAllAction.class, "CTL_DeselectAllAction");
      }

At last for the "Invert selection" action we have:

public final class InvertSelectionAction  extends ExplorerManagerAction
  {
    protected void performAction (ExplorerManager explorerManager)
      throws PropertyVetoException
      {
        List nodes = new ArrayList(Arrays.asList(explorerManager.getRootContext().getChildren().getNodes()));
        nodes.removeAll(Arrays.asList(explorerManager.getSelectedNodes()));
        explorerManager.setSelectedNodes((Node[])nodes.toArray(new Node[0]));
      }
    public String getName()
      {
        return NbBundle.getMessage(InvertSelectionAction.class, "CTL_InvertSelectionAction");
      }
  }

The above code for "Select All" and "Invert selection" only works for "flat" node structures with a root and a single level of children. For more complex structures we just need to replace explorerManager.getRootContext().getChildren().getNodes() with a piece of code that recursively explores the node tree contents.

To complete our work, this is the XML code to put in the layer.xml in order to add actions in the menu, the toolbar and to define the proper key bindings:

<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd">
<filesystem>
    <!-- Declares the relevant actions. -->
    <folder name="Actions">
        <folder name="Select">
            <file name="my-package-action-SelectAllAction.instance"/>
            <file name="my-package-action-DeselectAllAction.instance"/>
            <file name="my-package-action-InvertSelectionAction.instance"/>
        </folder>
    </folder>
    <!-- Adds the actions to the Select main menu. -->
    <folder name="Menu">
        <folder name="Select">
            <file name="my-package-action-SelectAllAction.shadow">
                <attr name="originalFile" stringvalue="Actions/Select/my-package-action-SelectAllAction.instance"/>
            </file>
            <attr name="my-package-action-SelectAllAction.shadow/my-package-action-DeselectAllAction.shadow" boolvalue="true"/>
            <file name="my-package-action-DeselectAllAction.shadow">
                <attr name="originalFile" stringvalue="Actions/Select/my-package-action-DeselectAllAction.instance"/>
            </file>
            <attr name="my-package-action-DeselectAllAction.shadow/my-package-action-InvertSelectionAction.shadow" boolvalue="true"/>
            <file name="my-package-action-InvertSelectionAction.shadow">
                <attr name="originalFile" stringvalue="Actions/Select/my-package-action-InvertSelectionAction.instance"/>
            </file>
            <attr name="my-package-action-InvertSelectionAction.instance/it-tidalwave-bluemarine-catalog-tagstamper-action-separatorBefore.instance" boolvalue="true"/>
        </folder>
    </folder>
    <!-- Declares the shortcuts. D- maps to "command" on Mac OS X and to "ctrl" on Linux and Windows. -->
    <folder name="Shortcuts">
        <file name="D-A.shadow">
            <attr name="originalFile" stringvalue="Actions/Select/my-package-action-SelectAllAction.instance"/>
        </file>
        <file name="D-D.shadow">
            <attr name="originalFile" stringvalue="Actions/Select/my-package-action-DeselectAllAction.instance"/>
        </file>
        <file name="D-I.shadow">
            <attr name="originalFile" stringvalue="Actions/Select/my-package-action-InvertSelectionAction.instance"/>
        </file>
    </folder>
    <!-- Adds the actions to the Select toolbar -->
    <folder name="Toolbars">
        <folder name="Select">
            <file name="my-package-action-InvertSelectionAction.shadow">
                <attr name="originalFile" stringvalue="Actions/Select/my-package-action-InvertSelectionAction.instance"/>
            </file>
            <attr name="my-package-action-InvertSelectionAction.shadow/my-package-action-DeselectAllAction.shadow" boolvalue="true"/>
            <file name="my-package-action-DeselectAllAction.shadow">
                <attr name="originalFile" stringvalue="Actions/Select/my-package-action-DeselectAllAction.instance"/>
            </file>
            <attr name="my-package-action-DeselectAllAction.shadow/my-package-action-SelectAllAction.shadow" boolvalue="true"/>
            <file name="my-package-action-SelectAllAction.shadow">
                <attr name="originalFile" stringvalue="Actions/Select/my-package-action-SelectAllAction.instance"/>
            </file>
        </folder>
    </folder>
</filesystem>

-- Main.fabriziogiudici - 06 Jul 2006

PENDING: Review/cleanup

How do I serialize my nodes?

When you serialize your nodes, you save them to disk so that when the application restarts, they can be used again in the application in the state that they were when the application shut down.

From Serialization and traversal in the NetBeans Javadoc:

"If you need to store (serialize) a node for any reason, this is generally impossible due to the welter of Java-level references connecting it to the rest of the system. Rather, you must use a special serializable handle which represents the node by its position in the hierarchy, and permits finding the original node again after deserialization (if it still exists). To create a handle, just call Node.getHandle(), and to restore the node call Node.Handle.getNode().

Creation of a usable handle is implemented in AbstractNode, and you should not need to override it. However, note that a handle consists of a handle for the root node of the target node's hierarchy together with a path (by system name) down to the target node; so if you are creating a root node, and want it or its children to be serializable, then you should create a specific implementation of Node.Handle capable of reconstructing your root from scratch, and return it from Node.getHandle().

The methods in NodeOp such as NodeOp.findPath(...) may also be used for general-purpose navigation along the hierarchy, should this be necessary."

Some concrete examples:

Creating Node Subclasses

Nodes are useful for many things beyond just representing files. If you just need a placeholder Node, you do not need a subclass - just instantiate an AbstractNode - despite its name, AbstractNode is not an abstract class. For example:

AbstractNode nue = new AbstractNode (Children.LEAF);
nue.setDisplayName ("Please wait...");
nue.setIcon (Utilities.loadImage ("path/in/jar/to/image.gif"));
return nue;

If you are creating Node s, you will typically deal with one of four things

Note that if you just want to write context sensitive code, not provide your own Nodes, you may be able to do it without a dependency on the Nodes API, using Utilities.actionsGlobalContext().

How can I add a "View" capability for data my node represents

Let's say that you've added support for a new file type in your application. You want to be able to provide an action by which users can "view" the file, which might open it up in the source editor (for text-based files) or a custom editor you've created in Swing. How can you add this view action?

It turns out that there are a few ways:

  1. Create a ViewCookie for your node and in display the contents in the cookie's view() method.
  2. Create a subclass of NodeAction and displays the node's contents in its performAction() method.
  3. Create a subclass of Node.Cookie that my node should return in its lookup and then create a CookieAction that acts upon this.

The first approach (ViewCookie) is the simplest of the three, though it can really only operate on a single node. If you just need something quick and easy, then it is probably your best bet.

The second approach (NodeAction) will work but is discouraged since someone creating a FilterNode on your node might inadvertently disable your action.

The third approach (Node.Cookie/CookieAction) is the most difficult of the three but also the most versatile. Your CookieAction can be enabled for multiple classes and can also operate on several nodes at once.

See also:

Computing Node Children Asynchronously

If you have a Node that needs to provide child Nodes, and computing the objects the child nodes represent is slow or expensive (i.e. you need to parse a file, connect to a database, or do some sort of I/O), you do not want to compute the child nodes in the event thread (which is what happens by default).

NetBeans 6.0 introduces org.openide.nodes.ChildFactory and Children.create(ChildFactory factory, boolean asynchronous). Simply subclass ChildFactory and implement protected boolean createKeys(List <T> toPopulate) to build the list of objects that will be represented by the child nodes. Implement protected Node createNodeForKey(T key) to create a Node - it will be passed each object in the list of child objects. createKeys will be called on a background thread.

Typically you'll want to make the model object from createKeys available on the Node you create. So a simple implementation of createNodeForKey would look something like:

    protected Node createNodeForKey(T key) {
        AbstractNode result = new AbstractNode (Children.LEAF, Lookups.singleton (key));
        result.setDisplayName (key.getName()); //or whatever
        result.setIcon (Utilities.loadImage ("path/in/jar/to/image.gif"));
        return result;
    }

ChildFactory can also simplify creating Nodes synchronously, and has the convenience that by using generics, your code can be type safe with respect to key objects. Generally it can be used anywhere Children.Keys would be used (it uses Children.Keys under the hood).

I need to customize the content of my Node/Project/Whatever's Lookup. How do I do it?

If it's just adding something, use

return new ProxyLookup(
    new Lookup[] { 
      super.getLookup(), 
      Lookups.fixed(
            something, somethingElse) 
      });

If there's only one object, substitute Lookups.singleton ( someObject ).

If you need to change the content of the lookup on the fly, it's a little more complicated, but not too much. Use the above ProxyLookup technique if there's a Lookup returned by the superclass and you still want to use its content. What you'll use to change content on the fly is the combination of AbstractLookup (which, as fate would have it, is not actually abstract), and InstanceContent, which is a grab bag of stuff you can add to and remove from.

The result will look something like this:

class MyNode extends AbstractNode {
  private final InstanceContent lookupContents;
  public MyNode() {
    this(new InstanceContent());
  }
  private MyNode(InstanceContent ic) {
    super(Children.LEAF, new AbstractLookup(ic));
    this.lookupContents = ic;
  }
}

When you need to change the contents of your lookup, you can call InstanceContent.add() or and InstanceContent.remove(), e.g.:

lookupContents.add(someObject);
lookupContents.remove(someObject);

Your lookup will be updated to include all items in the InstanceContent.

Decorating an entire tree of Nodes

Say you have a reference to the root of a tree of Node instances, and you want to add icons or actions to those nodes. First, what you do not do is call setDisplayName or any other setter on that Node (unless you created it - the point here is that it is rude and can have bad side effects to call setters on random Nodes somebody else created - setters in APIs are bugs - the fact that Node has them is a historical artifact, not proper design).

If you own the component that will display the Nodes, this sort of thing is very easily done by subclassing FilterNode and overriding the appropriate methods (e.g. getActions(), getIcon(), etc.), wrapping the original node inside your FilterNode. Now let's say that the Node you want to decorate builds out its children in a lazy fashion, that is, only when the user expands the tree in some tree view. How would you decorate that node and all of its children, without traversing the entire tree and effectively undoing the benefits of the lazy population of the tree?

Fortunately, while this sounds rather challenging, it turns out to be surprisingly easy and simple to achieve. The trick is to subclass the FilterNode.Children class and override the copyNode() method. Below is a short example:

class NodeProxy extends FilterNode {

    public NodeProxy(Node original) {
        super(original, new ProxyChildren(original));
    }

    // add your specialized behavior here...
}

class ProxyChildren extends FilterNode.Children {

    public ProxyChildren(Node owner) {
        super(owner);
    }

    protected Node copyNode(Node original) {
        return new NodeProxy(original);
    }
}

As you can see, NodeProxy is intended to wrap around another Node and provide some additional appearance or behavioral changes (e.g. different icons or actions). The fun part is the ProxyChildren class. While very short and simple, it provides that critical ability for our NodeProxy to act as a decorator for not only the root node, but all of its children, and their children, and so on, without having to traverse the entire tree at once.

While FilterNode should NOT be used to insert additional nodes at the beginning or end of the list (see its JavaDoc), it can be easily used to filter out some of the children nodes. For instance, this refinement of ProxyChildren overrides the createNodes() method and conditionally selects the children nodes by submitting them to a custom accept() method:

   class ProxyChildren extends FilterNode.Children {

        public ProxyChildren (Node owner)  {
            super(owner);
          }
        
        @Override
        protected Node copyNode (Node original){
            return new NodeProxy(original);
          }
        
        @Override
        protected Node[] createNodes (Object object) {
            List<Node> result = new ArrayList<Node>();
            
            for (Node node : super.createNodes(object)) {
                if (accept(node)) {
                    result.add(node);
                  }
              }
            
            return result.toArray(new Node[0]);
          }

        private boolean accept (Node node) {
            // ...
          }
      }

Below a complete example of a FileFilteredNode that can be used to show a file hierarchy where only a subset of files is shown, selected by means of the standard java.io.FileFilter class:

class FileFilteredNode extends FilterNode {

    private final FileFilter fileFilter;
   
    static class FileFilteredChildren extends FilterNode.Children {
        private final FileFilter fileFilter;
   
        public FileFilteredChildren (Node owner, FileFilter fileFilter) {
            super(owner);
            this.fileFilter = fileFilter;
          }

        @Override
        protected Node copyNode (Node original) {
            return new FileFilteredNode(original, fileFilter);
          }

        @Override
        protected Node[] createNodes (Object object) {
            List<Node> result = new ArrayList<Node>();

            for (Node node : super.createNodes(object)) {
                DataObject dataObject = (DataObject)node.getLookup().lookup(DataObject.class);

                if (dataObject != null) {
                    FileObject fileObject = dataObject.getPrimaryFile();
                    File file = FileUtil.toFile(fileObject);

                    if (fileFilter.accept(file)) {
                        result.add(node);
                      }
                  }
              }

            return result.toArray(new Node[0]);
          }
      }

    public FileFilteredNode (Node original, FileFilter fileFilter) {
        super(original, new FileFilteredChildren(original, fileFilter));
        this.fileFilter = fileFilter;
      }
  }

Note that if you're showing the filtered nodes in a tree view according to the code above, you might find expansion handles on leaf nodes. This thread from the dev@openide list discusses some solutions to this problem.

Can I create a console or server (non-GUI) app with the NetBeans Platform?

While most documentation explains the NetBeans Platform in terms of Java desktop applications, it is possible to build a non-GUI application on the NetBeans Platform. This might be useful, for example, when creating a platform-based application which will distribute computationally expensive work among a group of machines.

This is done by simply starting with the NetBeans Platform and removing all but the most essential components. NetBeans architect Jaroslav Tulach calls this subset of the NetBeans platform the "runtime container" and wrote an application which uses it to control his television.

Here are the steps for creating a runtime container application:

  1. Create a new suite
  2. Exclude all clusters from the suite
  3. Re-enable the platform cluster, but disable all but the following modules:
    • Bootstrap
    • File System API
    • Module System API
    • Startup
    • Utilities API
  4. Add a new module to the suite
  5. Create and register a ModuleInstall class
  6. The restored() method is effectively your application's main method.
  7. You may optionally override the close() method of your ModuleInstall to clean up resources upon shutdown.

You will also need to supress the splash screen by passing --nosplash argument when starting the app.


Applies to: NetBeans 6.5, 6.7

How can I change my TopComponent to not be a singleton?

The "New Window Component" wizard in the NetBeans IDE generates a singleton TopComponent. That's fine for some uses, but often you will want to create multiple instances of your TopComponent.

The good news is that you won't have to write any code -- you'll just have to delete some of the code that was generated for you.

In your TopComponent's .java source file:

Next, open the settings file that the wizard generated for your TopComponent. This is typically named something like FooTopComponentSettings.xml. Locate the instance XML element (NOT one of the instanceof elements and remove method="getDefault" from the end of that line.

Finally, you will need to change any code, such as from the action which opens the TopComponent, which called the getDefault() method. It should now simply create a new instance of your TopComponent instead.

NOTE: These instructions should apply to NetBeans 5.0 through 6.5. You may need to adapt them slightly for newer versions.

How do I embed output window tab to another component?

You have to create IOContainer which provides access (for IOProvider) to your component where you want to embed OW tab (IO tab). Then you need to pass IOContainer instance to IOProvider.getIO(String name, Action actions, IOContainer ioContainer). IOContainer is created by IOContainer.create(IOContainer.Provider). The following code demonstrates how to add OW to custom TopComponent.:

    IOContainer ioc = IOContainer.create(new IOC());
    InputOutput io = IOProvider.getDefault().getIO("test", new Action[0], ioc);
    io.getOut().println("Hi there");
    io.select();

    // implement IOContainer.Provider in TopComponent where OW tab will be added
    class IOC extends TopComponent implements IOContainer.Provider {
        JComponent ioComp;
        CallBacks ioCb;

        public IOC() {
            setLayout(new BorderLayout());
            setDisplayName("Test");
        }

        @Override
        public int getPersistenceType() {
            return PERSISTENCE_NEVER;
        }

        public void add(JComponent comp, CallBacks cb) {
            if (ioComp != null) {
                remove(ioComp);
                if (ioCb != null) {
                    ioCb.closed();
                }
            }
            ioComp = comp;
            ioCb = cb;
            add(comp);
            validate();
        }

        public JComponent getSelected() {
            return ioComp;
        }

        boolean activated;
        public boolean isActivated() {
            return activated;
        }

        @Override
        protected void componentActivated() {
            super.componentActivated();
            activated = true;
            if (ioCb != null) {
                ioCb.activated();
            }
        }

        @Override
        protected void componentDeactivated() {
            super.componentDeactivated();
            activated = false;
            if (ioCb != null) {
                ioCb.deactivated();
            }
        }

        public boolean isCloseable(JComponent comp) {
            return false;
        }

        public void remove(JComponent comp) {
            if (comp == ioComp) {
                ioComp = null;
                ioCb = null;
            }
        }

        public void select(JComponent comp) {
        }

        public void setIcon(JComponent comp, Icon icon) {
        }

        public void setTitle(JComponent comp, String name) {
        }

        public void setToolTipText(JComponent comp, String text) {
        }

        public void setToolbarActions(JComponent comp, Action[] toolbarActions) {
        }
    }

Applies to: NetBeans 6.7

How can I open a particular file at a particular line number?

Here is the basic idea (there are variations depending on your needs, so read the Javadoc):

File f = ...;
int lineNumber = ...;
FileObject fobj = FileUtil.toFileObject(f);
DataObject dobj = null;
try {
    dobj = DataObject.find(fobj);
} catch (DataObjectNotFoundException ex) {
    ex.printStackTrace();
}
if (dobj != null)
    LineCookie lc = (LineCookie) dobj .getCookie(LineCookie.class);
    if (lc == null) {/* cannot do it */ return;}
    Line l = lc.getLineSet().getOriginal(lineNumber);
    l.show(Line.SHOW_GOTO);
}

Applies to: NetBeans 5.x, 6.0, 6.1

For NetBeans 6.5 you should use something like:

File f = ...;
int lineNumber = ...;
FileObject fobj = FileUtil.toFileObject(f);
DataObject dobj = null;
try {
    dobj = DataObject.find(fobj);
} catch (DataObjectNotFoundException ex) {
    ex.printStackTrace();
}
if (dobj != null)
    LineCookie lc = (LineCookie) dobj .getCookie(LineCookie.class);
    if (lc == null) {/* cannot do it */ return;}
    Line l = lc.getLineSet().getOriginal(lineNumber);
    l.show(Line.ShowOpenType.OPEN, Line.ShowVisibilityType.FOCUS
}

See the JavaDoc for Line.ShowOpenType and Line.ShowVisibilityType to see different options of showing the line (with focus, without focus, opening the editor if not open, etc.).

How can I open a file in the editor in read-only mode?

You will need to make a special file editor which refuses to take a write lock:

public final class ROEditor extends DataEditorSupport {
    private ROEditor(DataObject d) {
        super(d, new E(d));
    }
    public ROEditor(FileObject fo) throws DataObjectNotFoundException {
        this(DataObject.find(fo));
    }
    private static final class E extends DataEditorSupport.Env {
        public E(DataObject d) {
            super(d);
        }
        protected FileObject getFile() {
            return getDataObject().getPrimaryFile();
        }
        protected FileLock takeLock() throws IOException {
            throw new IOException("No way!");
        }
    }
}

Demo of usage:

JFileChooser jfc = new JFileChooser();
if (jfc.showOpenDialog(null) != JFileChooser.APPROVE_OPTION) {
    return;
}
File f = jfc.getSelectedFile();
FileObject fo = FileUtil.toFileObject(f);
try {
    new ROEditor(fo).open();
} catch (DataObjectNotFoundException e) {
    e.printStackTrace();
}

I want my action to appear between to existing items/in a specific place in the menu. Can I do that?

Yes. Use ordering attributes in the layer file for your module.

If you are using the IDE's module project, the new Action template will let you specify a location for the action in the wizard and generate the right attribute for you.

Can I work on just one or two modules from the NetBeans source base by themselves?

Introduction

Normally to work on modules versioned in the NetBeans main Mercurial repository you need to clone the entire repository. (For modules in contrib, you need contrib cloned as a subdirectory of main.) For people interested in just playing with patches to one or two modules this can be onerous, however. In NetBeans 6.1 there was no alternative.

As of NetBeans 6.5, you can work on "orphan" modules from the netbeans.org source base. There are two issues to consider:

  1. Mercurial currently does not let you clone or check out just a subdirectory of a repository, so you will need to get module sources some other way (we are still considering some possibilities).
  2. Since "upstream" modules (that the module of interest depends on) are not available in source form, you need to have a recent development build of NetBeans available to compile against.

Issue 143236 describes the enhancement in NetBeans 6.5 that permits this development mode.

Quick usage guide

  1. Create an nb_all dir wherever you like. It must have at least the nbbuild dir from the netbeans.org source tree.
  2. Create nbbuild/user.build.properties and in it set the property netbeans.dest.dir to the full path to a NetBeans IDE installation you would like to both compile against and build into (you should not use your real development IDE, rather a copy).
  3. Run: ant -f nbbuild/build.xml bootstrap
  4. Add subdirs for any netbeans.org module projects you would like to work on. (The modules may be already present in the target platform. If they are not, you need to check out sources for any transitive dependencies not in the target platform too.)
  5. Using a 6.5+ IDE, open the desired projects and work normally.

What works

Source projects should open without error and without displaying error badges, assuming all dependencies are available in either source or binary form.

You can build the projects normally. The modules will be built into the target platform (overwriting any existing copy of the module).

You can use Run and Debug to start the target platform with a test userdir after building the modules, set breakpoints etc.

You can Test the source projects normally.

Code completion should work against APIs present in other modules. If those modules are available in source form, you will get popup Javadoc automatically, and can navigate to sources. If not, you can still add popup Javadoc capability for all published APIs:

  1. Download "NetBeans API Documentation" from AU.
  2. Open NetBeans Platform Manager.
  3. Select the "default" platform and note the location of NetBeansAPIDocs.zip in the Javadoc tab.
  4. Create a new platform; select the same dir as you specified for netbeans.dest.dir.
  5. In the new platform, add NetBeansAPIDocs.zip to the Javadoc tab.

Caveats

  • If you want to work on unit or functional tests, you need to have all test-to-test dependencies available as source projects, because we do not distribute test libraries. Sometimes the transitive dependency tree can get a bit big. For example, if the functional tests use org.netbeans.junit.ide.ProjectSupport, then you need to check out java.j2seproject (in whose unit test dir this class resides), then its dependencies in turn: projectapi, projectui, openide.filesystems, and openide.util. Test-to-module dependencies (e.g. nbjunit, jellytools, ...) can however be satisfied from the target platform's binaries.
  • If you add new source modules to the tree, you will need to both restart NetBeans and delete the nbbuild/nbproject/private/ dir in order to reset all caches and ensure that the new sources are recognized.
  • Various targets in nbbuild/build.xml not used in the above scenarios may or may not work usefully, though this should not affect routine module development.
  • The target platform needs to be new enough to support any API calls you are making from source modules into binary modules. If the platform is older, you could see error badges. Besides getting a newer platform, this can be corrected by adding sources of the new version of the API module to the tree.
  • Note that in NetBeans 6.7 the bootstrap ant target will not work if you just copy nbbuild from the netbeans.org source tree into nb_all. Other than nbbuild you also need to copy directories:
    1. ide/launcher
    2. javahelp
    3. apisupport.harness

Applies to: NetBeans 6.5

How do I create my own tab in the output window and write to it?

NetBeans contains classes that make writing to the output window very simple - you don't have to worry about components, you just get an instance of a thing called InputOutput, which has methods getOut() and getErr() that return OutputStreams. There is a utility class, IOProvider that can supply InputOutput objects - you pass it a string name that should be shown on the output tab, and a boolean (whether or not it should reuse an existing tab with the same name if there is one). So, hello world code for the output window looks like this:
InputOutput io = IOProvider.getDefault().getIO ("Hello", true);
io.getOut().println ("Hello from standard out");
io.getErr().println ("Hello from standard err");  //this text should appear in red
io.getOut().close();
io.getErr().close();

It is important to close the output streams when you are done with them - output is written to a memory mapped file, which cannot be deleted if the stream is still open - and the tab title will remain boldfaced until the streams are closed, which helps indicate to the user that the process has finished.

-- Main.timboudreau - 10 Jun 2006

Note: For platform based applications to correctly use InputOutput and IOProvider an Output Window implementation must be available and enabled. Follow the below steps to be sure you include everything to allow the output window and tabs to be used and shown.

  1. Open your module projects properties. (Right click the project and select properties).
  2. Select libraries
  3. Check to see if 'I/O APIs' is in the dependency list.
  4. If it is not it needs to be added.

To add 'I/O APIs'

  1. Choose 'Add' from 'Module Dependencies'
  2. Select 'I/O APIs' from the list
  3. Press OK

To force 'Output Window' (the implementation of the tabbed output window) to be enabled,

  1. Choose 'Add' from 'Required Tokens'
  2. Pick =org.openide.windows.IOProvider=
  3. Press OK
Note: this shall not be necessary in the current 6.0 trunk version..

Relevent to 6.0: If the dependencies do not show up in the selection list check the 'Module Suite' to make sure they have not been excluded from the platform.

  1. Right click on the module suite
  2. Click Properties
  3. Go to Libraries
  4. Locate the platform 'Clusters and Modules'
  5. Make sure I/O API is checked
  6. Make sure Output Window is checked
  7. Click OK

Hint: It is sometimes helpful to call InputOutput.select() to make sure the tab is made visible in the output window.

How do I route the output from an external process to the output window?

Writing to the output window is tricky - typically you need to launch an external process via Runtime.exec(). The code that does this should not be running on the event thread. Then you need a couple of threads to monitor the standard out and error out of the process, and pipe any output to the output window. The following code is a rough example:


public void launchProcess (String commandline) {
        if (EventQueue.isDispatchThread()) {
               throw new IllegalStateException ("Cannot be called from EDT");
        }
        final Process process = Runtime.getRuntime().exec (cmdline);

        //Get the standard out
        InputStream out = new BufferedInputStream (process.getInputStream(), 8192);
        //Get the standard in
        InputStream err = new BufferedInputStream (process.getErrorStream(), 8192);

        //Create readers for each
        final Reader outReader = new BufferedReader (new InputStreamReader (out));
        final Reader errReader = new BufferedReader (new InputStreamReader (err));

        InputOutput io = IOProvider.getDefault().getIO(scene.getName(), false);

        io.select();
        io.getOut().println(cmdline); //XXX
        io.getOut().println(); //XXXd

        OutHandler processSystemOut = new OutHandler (outReader, io.getOut());
        OutHandler processSystemErr = new OutHandler (errReader, io.getErr());

        //Get two different threads listening on the output & err
        RequestProcessor.getDefault().post(processSystemOut);
        RequestProcessor.getDefault().post(processSystemErr);

        try {
            //Hang this thread until the process exits
            process.waitFor();
        } catch (InterruptedException ex) {
            ErrorManager.getDefault().notify(ex);
        }
        processSystemOut.close();
        processSystemErr.close();
        if (process.exitValue() == 0) {
            //Get a localized string
            String successMessage = (NbBundle.getMessage(getClass(), "MSG_Success",
                outFile.getPath()));
            StatusDisplayer.getDefault().setStatusText (successMessage);
        } else {
            //Get a localized string
            String successMessage = (NbBundle.getMessage(getClass(), "MSG_Failure",
                outFile.getPath()));
            StatusDisplayer.getDefault().setStatusText (successMessage);
        }
}

    //The runnable that will handle an output stream, piping it to the output window:
    static class OutHandler implements Runnable {
        private Reader out;
        private OutputWriter writer;
        public OutHandler (Reader out, OutputWriter writer) {
            this.out = out;
            this.writer = writer;
        }

        public void run() {
            while (true) {
                try {
                    while (!out.ready()) {
                        try {
                            Thread.sleep(200);
                        } catch (InterruptedException e) {
                            close();
                            return;
                        }
                    }
                    if (!readOneBuffer() || Thread.currentThread().isInterrupted()) {
                        close();
                        return;
                    }
                } catch (IOException ioe) {
                    //Stream already closed, this is fine
                    return;
                }
            }
        }

        private boolean readOneBuffer() throws IOException {
            char[] cbuf = new char[255];
            int read;
            while ((read = out.read(cbuf)) != -1) {
                writer.write(cbuf, 0, read);
            }
            return read != -1;
        }

        private void close() {
            try {
                out.close();
            } catch (IOException ioe) {
                ErrorManager.getDefault().notify(ioe);
            } finally {
                writer.close();
            }
        }
    }

See also issue #57000.

Other strategies for authentication and authorization

There are cases in which you want to exercise great control over who is allowed to use your application. You might, for example, be required to check the user's network credentials, validate client-side certificate or check a license server before the platform application is even launched.

A platform application is typically started from an executable launcher (Windows) or shell script (Unix). This invokes the org.netbeans.core.startup.Main.main method. However, as described in the Module System documentation, you can use the netbeans.mainclass system property to specify a different class to run at startup.

This main class must be present in the startup classpath (you can put it alongside core.jar in platform8/core or similar) and must have a main method. The main method can then invoke whatever authorization logic you like. If it fails, you'll probably want to show a dialog to the user and call System.exit. If it passes, you can then simply invoke org.netbeans.core.startup.Main.main yourself to continue the normal NetBeans startup procedure.

If you simply want to enable a single module based on some criteria (for example, the existence of a license file), you can use ModuleInstall.validate().

I want to set some flags or CLI arguments for running my NB RCP/Platform based application (such as disable assertions). How do I do that?

To disable assertions or set some other VM property for your application, there are two places to pay attention to. First, $APP_HOME/etc/*.conf in your distribution should set things for users of your application - do this for things that should be set for any user.

You also will probably want to test these settings - and *.conf is not going to be used when you launch your application by running your project from Ant (nor the NetBeans IDE). So to handle this, you can set any of the properties documented in $NB_HOME/harness/README. For example, to disable assertions when testing your application from the IDE, edit your module suite's nbproject/project.properties to include run.args.extra=-J-da or similar.

See $NB_HOME/harness/README in your copy of NetBeans for the full list of properties that affect how NetBeans-based-applications are run when developing them in the IDE.


Applies to: NetBeans 6.5

How can I profile NetBeans?

There are many possibilities how to profile Java applications and that can be applied to NetBeans profiling. For different task it can be good to select different ways because each of them has its strengths and weaknesses.

See also: DevFaqMemoryLeaks

To be able to profile an application it is usually needed to start it with a modified command that typically adds some (JVMPI or JVMTI) libraries, some classes to (boot)classpath, specifies options for profiling and often initializes profiling support before the application starts to run its code.

NetBeans profiler

The NB module development support is integrated with the NB Profiler. Just select a module and click Profile to start.

Want to cover some typical activities like:

  • action execution (invoked from menu or by shortcut)
  • window/dialog opening/closing
  • use of editor including tracking what happens in background
  • startup

Analyzer

It is a sampling profiler working on Solaris and Linux (with limited functionality) that collects data during runtime. These data are later available for offline processing.

It provides some capabilities that are not available in other Java profilers namely timeline view. This view shows timeline for each thread visualizing if the thread actually executes some code or not.

Download and install Analyzer tool

Performance Analyzer that is part of Sun Studio tools and can be downloaded from the developers' site.

Run the Analyzer

  • Set the environment. PATH should contain bin directory of Analyzer installation. LD_LIBRARY_PATH should similarly contain lib dir (and also /usr/lib/lwp if you want to run it on Solaris 2.8). Optionally you can also set MAN_PATH. Set the _NB_PROFILE_CMD:
export _NB_PROFILE_CMD='collect -p 1 -j on -S off -g NetBeans.erg  -y 38 -d /export/home/radim/analyzer

-p num stands for sampling period (on, hi, lo are also accepted), -j on turns on Java profiling, -y num determines the signal to trigger profiling on/off. -y num,r means that profiling will be resumed at the begining. Use man collect to get detailed explanation of all options.
  • mkdir /export/home/radim/analyzer (It is only need first time. Next experiments will be added.)
  • Install & start the IDE
  • Send signal 38 to Java process to start data collecting (kill -38 $pid)> Or use another signal like PROF (this works well on Linux).
  • Perform the analyzed activity
  • Send the signal again to stop profiling (there can be more evaluated periods during one run).
  • Shut down the IDE.
  • Run the analyzer to evaluate the experiment in GUI environment: analyzer /export/home/radim/analyzer/NetBeans.x.er

Profiling hints

Startup: start with profiling enabled, send a signal when startup is completed. When sampling every 1ms it takes ~70 seconds instead of 40.

Other tools

Quite simple way how to measure time spent in some code is to wrap the code with

long t0 = System.nanoTime();
try {
  ... measured code
} finally {
  long t1 = System.nanoTime();
  System.out.println("action took "+(t1-t0)/1000000+"ms");
}

JVMTI is powerful interface that allows to write custom libraries that will track behavior of application.

DTrace is a comprehensive dynamic tracing framework for the Solaris™ Operating Environment. It is one of the few tools that allows to track activities running deeply in the system and analyze the system. Because there are also probes provided by Java VM and function like jstack it is also possible to map observed actions to parts of Java code in running application.

Tips and trick

Node pop-ups: interesting starting point is o.o.awt.MouseUtils$PopupMouseAdapter.mousePressed()

How to measure performance/responsiveness?

See What is UI responsiveness for overview.

Older Performance web page contains few links to documentation of one possible approach how to measure and profile responsiveness. This is based on use of modified event queue and patches classes from JDK.

Recently we changed the support a bit to avoid modifications of core JDK's classes and and use small utility library available in Hg. This is used in current automated testing and can be used for manual checks too. To run such test:

  1. Build performance project.
  2. Copy the JAR file to netbeans/platform7/core
  3. Start the IDE with -J-Dnetbeans.mainclass=org.netbeans.performance.test.guitracker.Main -J-Dguitracker.mainclass=org.netbeans.core.startup.Main
  4. ... watch process output when you perform an action

Applies to: NetBeans 6.5

How do I change the default behavior of PropertySheet editors?

Issue: How do I specify the kind of renderer which will represent the look of property value cell (in the same manner as it usually does for JTable)? For example, I want a string property not to be shown in grey if it's not editable.

Solution: If you specify a custom inplace editor it will also be used for rendering.


Issue: How can I provide a new kind of inplace editor? For example, I want to have a property which should be shown at Property Sheet like a combo-box or a spinner control.

Solution: See the docs for the InplaceEditor interface.


Issue: How do I specify that a value is not editable in-place?

Solution: Provide a custom inplace editor that provides a disabled component for the inplace editor. Or mark it non-editable, but supply a custom editor that does edit it.


Issue: How do I specify that a property has a custom editor?

Solution: See the docs for the PropertyEditor interface.


Issue: How can I copy text from a non-editable property?

Solution: Not implemented yet.


Issue: How do I access the Node the property belongs to?

Solution:

class MyEditor implements ExPropertyEditor {
  PropertyEnv env;

  public void attachEnv(e) {
    env = e;
  }

  public void anyMethod() {
     Object[] arr =  env.getBeans();
     // now arr contains either the real bean objects if invoked on Object
     // or it contains Node that the properties belong to
  }
}
Q: I want to have the properties of my custom nodes displayed in the Properties view when they are selected in my tree view. How do I go about doing that?

A: It is simply a matter of listening for the selected nodes property change and then setting the activated nodes on the parentTopComponentwhich contains your tree view.

public class MyComponent extends TopComponent implements PropertyChangeListener {
    private ExplorerManager explorerManager;

    public MyComponent() {
        explorerManager = new ExplorerManager();
        explorerManager.addPropertyChangeListener(this);
    }

    public void propertyChange(PropertyChangeEvent evt) {
        if (evt.getSource() == explorerManager &amp;&amp;
                ExplorerManager.PROP_SELECTED_NODES.equals(evt.getPropertyName())) {
            setActivatedNodes(explorerManager.getSelectedNodes());
        }
    }
}

Note that the example above is not a complete TopComponent implementation with a tree view and nodes. It is simply demonstrating how to have the selected node's properties shown in the Properties view.

How do I display different groups of properties on buttons in the property sheet the way Matisse does?

This is only really useful if you have a lot of properties - and having lots of properties is usually not a great idea, as the user has to search for the things they want to change.

Nonetheless, if you want to group different sets of properties on different buttons, it is quite simple. Node.PropertySet extends java.beans.FeatureDescriptor. It inherits the methods putValue (key, value) and getValue(key, value) which allow you to add ad-hoc key/value pairs to any PropertySet. What you do is pass a String with the text that should be on the button, assigned to the key "tabName":

somePropertySet.putValue ("tabName", NbBundle.getMessage (getClass(), "KEY_Something"));
(the above code gets you a localized string - you can also pass a hard-coded one if you are sure your UI will never need to be translated).

All PropertySets that have the same value will be included under the same button/tab in the property sheet.

Can I bind one key to more than one action?

The simple answer is no: The global keymap (get Keymap from Lookup) is a master keymap for the whole application, and like all keymaps accepts only one action per binding. If you want multiple actions to be run, you must create a "wrapper" action that runs them all in turn (or in parallel).

What about binding a key differently in different windows?

You may bind a key differently in different windows, by using the normal Swing techniques of binding keystrokes to components. In fact, some work went into implementing the global map so that it would work across arbitrary components; it is overridden by local bindings, such as navigation keys on dialogs or Explorer trees, or various editing keys in the Editor.

Before you bind a key performing a high-level specific action, such as Ctrl-N for New File, to a different action in a local component (e.g. window), think carefully whether this is really the right approach. In many cases the UI of your extension and the IDE as a whole will be better served by leaving the key binding alone, and instead providing an appropriate cookie, action performer, or other callback associated with your component, so that the action (and potentially other code unknown to you) will function naturally. If you must rebind a global key, consider whether it is appropriate to determine the current key binding for the action (if any) in the global keymap, and use this keystroke to rebind - so user customizations will remain intact.

CallbackSystemActions such as Find or Delete can easily have different bindings in each component, using ActionMap.

How Can I Replace the Window Manager?

Perhaps your users are a bit confused by the ability to close, slide or dock windows or maybe you're trying to retain the behavior of some existing application's window system. There are times, however rare, in which you want to replace the typical NetBeans Window Manager org.netbeans.core.windows.WindowManagerImpl with a different one.

Before doing this you should know that starting with NetBeans 6.5, it will be easy to change certain behaviors of the window system. So needing to replace the window manager is rare already and will be needed even less often in the future.

But if you still want to do it, you can:

  • Create an implementation of the org.openide.windows.WindowManager interface
  • Register your implementation into the default lookup and replace any others

Of course, there's a lot of work involved in creating your own WindowManager implementation, but you can have a look at the org.openide.windows.DummyWindowManager class for starters. It's a simple implementation that opens all TopComponents in their own frame but which can also make windows invisible which is handy for testing.

The DummyWindowManager is used as a last resort when no other window manager is present; you will not need to register it in the default Lookup as described earlier. If you want to use it, keep in mind these two tips:

  • Do not include the Core - Windows or Core modules in your application. Including Core will result in an error message from the NonGui class because it seems to expect an implementation of the NbTopManager.WindowManager class which you cannot (easily) provide.
  • No windows will be shown by default on startup. Use a ModuleInstall class' restored() method to display your TopComponent.

When should I use RequestProcessor.getDefault() and when should I create my own RequestProcessor?

RequestProcessor.getDefault() is tempting to use, but it is also dangerous. This FAQ item will tell you when not to use it.

RequestProcessor has a constructor argument for its throughput. That says how many threads this RequestProcessor is allowed to use at the same time. When you call new RequestProcessor("Useful name for thread dump", 3) you are creating a thread pool that can have 3 threads available to run things on simultaneously.

The throughput of RequestProcessor.getDefault() is Integer.MAX_VALUE. Think about what that means: it can potentially create thousands of threads; but your OS cannot necessarily handle thousands of threads, and you probably don't have thousands of CPUs. Which means the OS does extra work time-slicing between the threads and things get slower, not faster.

RequestProcessor.getDefault() is useful for one-off operations - you have some situation that happens once in a great while, and, say, while constructing some object, you need to do some work in the background; that work will probably never need to be done again for the life of the Java VM. That's a perfect case for RequestProcessor.getDefault().

Now here is the anti-example: You are creating a Node that represents a file. It needs to mark itself with an error badge and color its text in red if the file contains errors. You can't read the file when you create the Node - that takes to long. So when the node is created, it runs a background task to check its status, and updates its icon and display name after it has read the file. Now imagine you did this with RequestProcessor.getDefault(). What happens when the user expands a folder that contains 1000 of your files? 1000 threads get created, and the whole application gets very, very slow. For that, you are much better off creating one RequestProcessor and using it for all your nodes. The FAQ entry about RequestProcessor.Task shows how to do this correctly.

If you create your own RequestProcessor, please always use a name. If you get a deadlock it makes debugging much easier.

How can I operation occasionally on a background thread, but reschedule it if something happens to delay it?

There are a lot of reasons you might want to reschedule a background operation. For example, you want to re-parse a file 3 seconds after the user stops typing, so you can show errors. But at 2 seconds she starts typing again. You don't want that task to run a second from now anymore. You can either cancel the task, or even simpler, call task.schedule(3000) every time a key is pressed. If it was already scheduled, it will be rescheduled for 3 seconds from now again.

Or imagine you have the situation described in the FAQ about RequestProcessor.getDefault() - a node for a file needs to read the file after it is created to mark itself if the file has errors. RequestProcessor.Task makes this sort of thing easy.

public class FooDataNode extends DataNode implements PropertyChangeListener, Runnable {
  private boolean error;
  private static final RequestProcessor THREAD_POOL = new RequestProcessor("FooDataNode processor", 1);
  private final RequestProcessor.Task task = THREAD_POOL.create(this);

  FooDataNode(FooDataObject obj) {
    super(obj, Children.LEAF);
    obj.addPropertyChangeListener(WeakListeners.propertyChange(this, obj));
    task.schedule(100);
  }

  public void propertyChange(PropertyChangeEvent evt) {
    DataObject obj = (DataObject) evt.getSource();
    if (DataObject.PROP_MODIFIED.equals(evt.getPropertyName()) && !obj.isModified()) { //file was saved
      task.schedule(100);
    }
  }

  @Override
  public String getHtmlDisplayName() {
    return error ? "<font color=\"!nb.errorForeground\">" + getDisplayName() : null;
  }

  public void run() {
    boolean old = error;
    error = doesTheFileHaveErrors();
    if (old != error) {
      fireDisplayNameChange(null, null);
    }
  }

  private boolean doesTheFileHaveErrors() {
    assert !EventQueue.isDispatchThread();
    //parse the file here
    return true; //whatever the value should be
  }
}

How do I suppress warning messages about loading resources from the default package?

As described in the Module System API documentation, the module classloader refuses to load classes from the default package. This is actually a fairly common restriction in multi-classloader systems like the NetBeans Platform (such as Eclipse RCP and various application servers). The module system will load resources (such as properties files and images) from the default package, but will log warning messages about doing so.

If you're unable to move the resources (e.g. a third-party library requires them to be there), then you can suppress this warning as described in the Module System API documentation by setting the org.netbeans.ProxyClassLoader.level system property to a value of 1000 or higher.

How can I scan a classpath to find all classes of a particular type?

The process is simpler than you might think. You will use the Javac API to analyze files.

So first, you'll want to get the classpath - for example

ClassPath path = project.getLookup().lookup(
    ClassPathProvider.class).findClassPath(someFile, ClassPath.SOURCE);

(or if you can directly access the project, get the classpath some other way).

Then you'll recursively iterate all of the children of the FileObjects that are the classpath roots. For each one with the extension .java, you will call

JavaSource src = JavaSource.forFileObject(fo);
to get the JavaSource for that FileObject. The JavaSource is something you can pass a task to, and it will run the compiler against it and you can write a visitor or scanner that visits every element of the compilation tree.

So you will implement CancellableTask<CompilationController> to create a task that can analyze a source file. The first thing that task will do is ask the compiler to completely resolve all of the types (this can be slow):

compiler.toPhase(Phase.RESOLVED);
Then we get the type declarations from the source we are currently analyzing:
List <? extends Tree> types = 
      compiler.getCompilationUnit().getTypeDecls();
Now we iterate the types found and get a /TypeMirror/ for each. TypeMirror.toString() gives a fully qualified class name, so we just need to compare it against the string we're looking for:
for (Tree tree: types) {
  if (cancelled) return;
  TypeMirror mirror = compiler.getTrees().getTypeMirror(
     TreePath.getPath(compiler.getCompilationUnit(), tree));
  ...

See the full source code below for how to do this. Note that it is very important for performance that you implement CancellableTask and not just Task, run this code on a background thread, regularly check if the cancelled flag has been set and abort if so (your UI or whatever is running this code should know if it is no longer needed - for example, if you are writing a Swing panel, cancel the task in removeNotify()).

public class TypeFinder implements CancellableTask<CompilationController> {
    private volatile boolean cancelled;
    private final ClassPath classpath;
    private final String fqn;
    private Callback callback;

    public TypeFinder(String fqn, ClassPath path) {
        this.classpath = path;
        this.fqn = fqn;
    }

    public interface Callback {
        public void foundFileObject(FileObject fo, String className);
    }

    public void findTypes(Callback callback) {
        //Don't ever do this kind of IO-heavy work on the event thread
        assert !EventQueue.isDispatchThread();
        this.callback = callback;
        //recursively iterate all children
        for (FileObject fo : classpath.getRoots()) {
            analyze(fo);
        }
    }


    private void analyze(FileObject fo) {
        if (fo.isFolder()) {
            for (FileObject child : fo.getChildren()) {
                analyze(child);
            }
        } else if ("java".equals(fo.getExt())) { //NOI18N
            JavaSource src = JavaSource.forFileObject(fo);
            try {
                src.runUserActionTask(this, true);
            } catch (IOException ex) {
                Logger.getLogger(TypeFinder.class.getName()).log(Level.INFO,
                        "Problem scanning " + fo.getPath(), ex); //NOI18N
            }
        }
    }

    public void reset() {
        cancelled = false;
    }

    @Override
    public void cancel() {
        cancelled = true;
    }

    @Override
    public void run(CompilationController compiler) throws Exception {
        if (cancelled) {
            return;
        }
        compiler.toPhase(Phase.RESOLVED);
        if (cancelled) {
            return;
        }
        List <? extends Tree> types = 
                compiler.getCompilationUnit().getTypeDecls();
        for (Tree tree: types) {
            if (cancelled) {
                return;
            }
            TypeMirror mirror = compiler.getTrees().getTypeMirror(
                    TreePath.getPath(compiler.getCompilationUnit(),
                    tree));
            if (tree instanceof ClassTree && match(mirror, compiler.getTypes())) {
                callback.foundFileObject(compiler.getFileObject(),
                        mirror.toString());
            }
        }
    }

    boolean match(TypeMirror mirror, Types types) {
        boolean result = false;
        if (mirror != null && 
            !"java.lang.Object".equals(mirror.toString())) { //NOI18N
            
            result |= fqn.equals(mirror.toString());
            if (!result) {
                List<? extends TypeMirror> l = 
                        types.directSupertypes(mirror);
                
                for (TypeMirror tm : l) {
                    result |= match(tm, types);
                    if (cancelled) return result;
                    if (result) break;
                }
            }
        }
        return result;
    }
}

Can I sign NBMs I create?

Yes, though there is not yet any GUI support for this.

1. Make a module project.

2. Generate a keystore, e.g.

cd .../path/to/module/
keytool -genkey -storepass specialsauce -alias myself -keystore nbproject/private/keystore

and answer the questions posed.

To make NetBeans build script sign the NBM module. The keystore and key password needs to be the same. At keytool, when the question below is asked, just press ENTER key, to make keystore and key alias the same password.

Enter key password for <myself>
  (RETURN if same as keystore password):

3. Edit nbproject/project.properties to contain e.g.

keystore=nbproject/private/keystore
nbm_alias=myself

4. Edit nbproject/private/private.properties to contain e.g.

storepass=specialsauce

You could also pass -Dstorepass=specialsauce on the command line. If you specify a keystore but ${storepass} is undefined, you will be prompted for the password during the build.

5. Build the NBM for the module. (Context menu of the project.) It should be signed.

6. Try installing the NBM. (Expand build folder in Files view and double-click it.) It will not be trusted initially (and so the checkbox to really install it will initially be unchecked), since NetBeans does not know about your signature. But you can click View Certificate to examine the certificate. If you allow installation of this module, NetBeans will remember you approved this certificate and it will not ask you for confirmation next time.

Some notes:

1. You can probably get a root-authorized certificate from VeriSign or the like, and the Auto Update wizard should treat this as more trusted. Not yet investigated (please update this FAQ entry if you experiment with this).

2. Keeping the keystore and its password in the private dir ensures that you will not accidentally commit either to source repository or include it in a source ZIP made with the Project Packager module. It may be safe to put the keystore in a shared directory (e.g. nbproject) if you are sure that the storepass is too hard to guess.


Applies to: NetBeans 6.5

There sure are a lot of modules in the source tree. What are they for?

If you've unpacked or checked out the NetBeans sources, you'll see more then 600 directories. Almost every one of these directories is a module. Although the directory names indicate the purpose of each, sometimes it's still not clear what each does.

The easiest way to find out about a module in the source tree is to open its manifest file, then look for the entry named OpenIDE-Module-Localizing-Bundle. The file referenced there (located deeper inside the module directory) typically contains the module's display name, descriptions and other information. You could automate the extraction of these values through a simple shell or perl script, but for your convenience, I've included the short description of each one below:

ant.browsetask=Adds an Ant task <nbbrowse> to run inside NetBeans to open a web browser.
ant.debugger=Enables debugging on Ant scripts.
ant.freeform=Special project type for projects with pre\u00EBxisting Ant scripts.
ant.grammar=Code completion for textual editing of Ant scripts.
ant.kit=Support for Ant build scripts.
antlr=Antlr Developement Libraries
api.debugger=Enables debugging with the AAA debugger implementation.
api.debugger.jpda=JPDA Debugger API
api.debugger=NetBeans Debugger APIs.
api.java.classpath=Classpath APIs
api.java=APIs for Java development support modules
api.mobility=Mobility Core API module.
api.progress=Task progress visualization APIs.
apisupport.apidocs=Local documentation for the NetBeans APIs.
apisupport.feedreader=Feed Reader Application
apisupport.feedreader=Wrapper for JDOM library
apisupport.feedreader=Wrapper for ROME Fetcher Library
apisupport.feedreader=Wrapper for ROME Library
apisupport.feedreader=Bundles a demonstration application using the NetBeans Platform.
apisupport.harness=Lets you build external plug-in modules from sources.
apisupport.paintapp=Sample NetBeans platform application.
apisupport.project=Defines an Ant-based project type for NetBeans modules and module suites.
apisupport.project=Some short description
apisupport.refactoring=Additional refactoring support for NetBeans module projects.
api.visual=Visual Library API
api.web.webmodule=APIs for web module development support modules.
api.xml=This module contains XML tools API and SPI.
applemenu=Enables proper support for the Apple \
asm=Assembler support
autoupdate.services=Support for searching for module updates on Update Center and for downloading and installing modules
autoupdate.ui=Supplies UI of Auto Update Services
beans=Support for creating JavaBeans(TM) components.
bpel.core=BPEL Core.
bpel.debugger.api=Enables debugging on BPEL files.
bpel.debugger.bdi=BPEL Debugger RMI.
bpel.debugger=BPEL Debugger.
bpel.debugger.ui=BPEL Debugger UI.
bpel.editors.api=BPEL Editors API.
bpel.editors=BPEL Editors.
bpel.help=BPEL Help.
bpel.kit=BPEL development support.
bpel.mapper=BPEL Mapper.
bpel.model=Object model for BPEL 2.0.
bpel.project=Composite Application Base Project.
bpel.project=BPEL Project.
bpel.refactoring=BPEL Refactoring.
bpel.samples=BPEL Samples.
bpel.validation=BPEL Validation.
classfile=Provides read-only access to Java class files.
clearcase=Clearcase Versioning System
cnd.antlr=Supports the C/C++ Code Model - contains ANTLR parser generator library
cnd.api.model=API that represents C/C++ code
cnd.api.project=A bridge between C/C++ project system and C/C++ code assistance
cnd.apt=APT presentation for files with preprocessor
cnd.callgraph=C/C++ Call Graph
cnd.classview=C/C++ Class View
cnd.completion=Code completion for C, C++, and Fortran languages
cnd.debugger.gdb=Supports debugging of native programs with gdb
cnd.discovery=C/C++ Discovery API/SPI
cnd.dwarfdiscovery=C/C++ Dwarf-based Discovery Provider
cnd.dwarfdump=Reading dwarf debugging information
cnd.editor=C/C++ Editor
cnd.folding=C/C++ APT-based Folding
cnd.gotodeclaration=C/C++ Go To Declaration
cnd.highlight=Provides error highlighting for the C/C++ languages.
cnd.kit=C/C++ development support.
cnd.lexer=Lexical analysis for C/C++ Pack languages
cnd.makeproject=Supports C/C++ projects
cnd.modeldiscovery=C/C++ Model-based Discovery Provider
cnd.modelimpl=Implementation of C/C++ Code Model API
cnd.model.services=Code Model Services
cnd.modelui=UI for Implementation of C/C++ Code Model API
cnd.modelutil=Miscellaneous utilities used by C/C++ Code Model
cnd.navigation=C/C++ Code Navigation
cnd.qnavigator=Provides navigator content for C/C++ files
cnd.refactoring=C/C++ Experimental Refactoring
cnd.remote=Support remote developement
cnd.repository.api=Api for the CND repository
cnd.repository=Persistence mechanism for Code Assistance features
cnd=Enables development of C and C++ programs in the IDE
cnd=Enables editing of C, C++, and Fortran files in the IDE.
cnd.utils=C/C++ Utilites
collab.channel.chat.java=Support for developer-friendly instant messaging chat (Java).
compapp.casaeditor=Composite Application Service Assembly editor.
compapp.configextension=JBI descriptor configuration extensions.
compapp.help=Composite Application Help Topics.
compapp.kit=Composite application development support.
compapp.manager.jbi=Composite Application JBI Manager.
compapp.projects.base=Composite Application Project.
compapp.projects.jbi=Composite Application JBI Project.
compapp.projects.wizard=Supplies the generic wizard interface for CAPS projects in the IDE.
core.execution=Implementation of the Execution engine.
core.ide=Makes the IDE from the platform.
core.kit=NetBeans Platform
core.multiview=MultiView Windows framework and APIs
core.nativeaccess=Uses native bindings via JNA library to provide advanced visual effects for window system.
core.output2=A simple text area based output window implementation
core.startup=Loads and enables modules.
core.ui=User interface of the platform.
core.windows=Implementation for windowing support.
css.editor=Editor support for editing CSS files
css.visual=CSS authoring support module for visual CSS editing
dbapi=Database support APIs
db.core=Core database support.
db.dataview=SQL query editable resultset view
db.drivers=JDBC database drivers
db.kit=Database browser, visual and text SQL editor.
db.mysql.sakila=Provides Sakila sample database for NetBeans MySQL support
db.mysql=Provides MySQL-specific db support for NetBeans
dbschema=Enables you to capture and view the structure of a database in the IDE.
db.sql.editor=Supports editing SQL files in the IDE
db.sql.visualeditor=Visual Query Editor
db=Views and modifies the structure of the connected database.
debugger.jpda.ant=Lets you use the NetBeans JPDA debugger from Ant.
debugger.jpda.heapwalk=Provides heap walking functionality in Java Debugger.
debugger.jpda.projects=JPDA Debugger integration with Java projects.
debugger.jpda=Enables debugging with the JPDA debugger implementation.
debugger.jpda.ui=JPDA Debugger.
defaults=Contains font, color and shortcut defaults for IDE.
deployment.wm=Windows Mobile Deployment
derby=Integration with the Java DB database.
diff=Provides the diff action to view file differences.
editor.bookmarks=Contains support for bookmarks handling in the edited files
editor.bracesmatching=Support for highlighting matching braces
editor.codetemplates=Contains support for creation and using of code templates
editor.completion=Contains support for Code Completion in Editor
editor.errorstripe.api=The API for the right hand side bar showing errors, hints, etc.
editor.errorstripe=The right hand side bar showing errors, hints, etc.
editor.fold=Contains support for Code Folding in Editor
editor.guards=Provides support for manipulating garded sections in a document.
editor.indent=Contains indentation APIs and SPIs.
editor.kit=Editting support for various types of files.
editor.lib2=Contains core editor APIs and SPIs.
editor.lib=Contains Editor functionality independent on the IDE
editor.macros=Support for editor macros
editor.mimelookup.impl=The default implementation of MimeDataProvider.
editor.mimelookup=The MIME lookup API.
editor.plain.lib=Contains plain editor library implementation
editor.plain=Contains plain text editor implementation
editor.settings=Contains support for editor settings
editor.settings.storage=Implements Netbeans editor settings storage
editor=Enables editing of files in the IDE.
editor.structure=Contains Editor support functionality for tag based editors
editor.util=Contains various support classes for editor related modules
el.lexer=Lexical Analysis for Expression Language
etl.editor=Data Editor for editing and creating extract-transform-load collaboration documents.
etl.project=Data Integrator Application Projects.
extbrowser=Enables integration of external web browsers with the IDE.
extbrowser=Webclient module enables embedding of external web browsers into the IDE.
extexecution=Supports execution of external processes
favorites=Support for organizing favorite files.
form.kit=Enables you to visually design Java desktop (AWT and Swing) applications.
glassfish.common=Shared support module for GlassFish V3 server integration
glassfish.eecommon=shared code for glassfish servers
glassfish.javaee=GlassFish V3 server support for JavaEE projects.
glassfish.jruby=GlassFish V3 server support for Ruby on Rails projects
gototest=An action to quicky \
groovy.editor=Support for editing Groovy files
groovy.grailsproject=Support for Grails projects
groovy.grails=Interface to in-process or ex-process Grails runtime
groovy.gsp=Support for Groovy Server Pages (GSP)
groovy.kit=Wrapper module for all Groovy and Grails functionality
groovy.refactoring=Groovy refactorings
groovy.samples=Groovy and Grails sample projects
groovy.support=Enables editing and running of scripts written in Groovy language.
groovy.support=Groovy script execution support
gsf.api=API for defining custom languages in the IDE
gsfpath.api=APIs for handling paths in the Common Scripting Language Framework
gsf=Generic support for language integration in the IDE
gsf=Adds support for structural views of Java \
gsf=Java Source Infrastructure
hibernatelib=Wrapper module for Hibernate 3.2.5 jars
hibernate=Hibernate Support
hibernateweb=Hibernate Support for Web Projects.
html.editor.lib=Contains HTML editor library implementation
html.editor=Contains HTML editor implementation
html.lexer=Lexical analysis for html language
html=Supports creation, editing, and viewing of HTML files.
httpserver=Provides infrastructure for testing applets, RMI applications, and so on.
i18n.form=Enables internationalization of files created with the IDE's Form Editor.
i18n=Simplifies internationalization of applications.
ide.branding.kit=NetBeans IDE content and branding.
ide.branding=Provides NetBeans IDE specific branding
ide.kit=IDE Platform
identity.kit=Plugin for securing web services and clients using Sun Java System Access Manager.
identity.samples=Identity Sample Projects
iep.editor=Intelligent Event Processor Editor
iep.help=Intelligent Event Processor Help Topics.
iep.project=Intelligent Event Processing Module Project
iep.samples=Intelligent Event Processing Samples.
image=Supports viewing of image files.
installer=Provides integration services between the NetBeans installer and the Plugin Manager
j2ee.ant=Lets you use j2eeserver from Ant.
j2ee.api.ejbmodule=APIs for ejb jar development support modules.
j2eeapis=J2EE Application Deployment and Management API Library
j2ee.archive=Java EE Binary Archives support
j2ee.clientproject=Support for Application Client (CAR) Module Projects.
j2ee.common=Utilities for J2EE projects
j2ee.core.utilities=Core Java EE Utilities.
j2ee.ddloaders=J2EE Deployment Descriptors files loaders
j2ee.dd=Deployment Descriptor API.
j2ee.dd=J2EE Deployment Descriptor API.
j2ee.dd.webservice=Web Services Deployment Descriptor API.
j2ee.earproject=Supports development of composite Java EE applications.
j2ee.ejbcore=Support for Enterprise JavaBeans (EJB) Development.
j2ee.ejbjarproject=Support for Enterprise JavaBeans (EJB) Module Projects.
j2ee.ejbverification=EJB Verification
j2ee.genericserver=Generic J2EE Server Plugin
j2ee.jboss4=Plugin for JBoss Application Server
j2ee.jpa.verification=Detects and solves problems with usage of the Java Persistence API
j2ee.kit=J2EE / Java EE application support
j2ee.metadata=Java EE Metadata
j2ee.persistenceapi=API for supporting Java Persistence API
j2ee.persistence.kit=Java Persistence API support
j2ee.persistence=Support for the Java Persistence Technology
j2ee.platform=Java EE Documentation
j2ee.samples=Java Enterprise Samples from the GlassFish samples project
j2eeserver=Supports Java EE application servers
j2eeserver=JSR88/77 test server plugin
j2ee.sun.appsrv81=Map Java classes to database schema
j2ee.sun.appsrv81=GlassFish and Sun Java System Application Server integration
j2ee.sun.appsrv=Sun Java System Application Server  Common APIs
j2ee.sun.dd=Sun Java Sytem Application Server J2EE Deployment Descriptor API.
j2ee.sun.ddui=Sun Java Sytem Application Server (or Glassfish) JavaEE Deployment Descriptor Loaders.
j2ee.sun.ddui=Sun Java Sytem Application Server J2EE Deployment Descriptor GUI.
j2ee.toplinklib=Java Persistence API and TopLink Essentials Library
j2ee.weblogic9=Plugin for BEA WebLogic Server
j2ee.websphere6=Plugin for IBM WebSphere Application Server, Version 6.0 and 6.1
j2me.cdc.kit=Support for Connected Device Configuration development (JSR 36 and JSR 218)
j2me.cdc.platform.bdj=Java ME CDC BD-JRay Platform Support
j2me.cdc.platform.nsicom=Java ME CDC NSIcom VM Platform Implementation
j2me.cdc.platform=Java ME CDC Platform
j2me.cdc.project.bdj=Java ME CDC BD-J Plugin Implementation
j2me.cdc.project.execuiimpl=Implementation of executable classes chooser in CDC profiles
j2me.cdc.project.execui=Internal API for executable classes chooser in CDC profiles
j2me.cdc.project.nsicom=Java ME CDC NSIcom Plugin Implementation
j2me.cdc.project=Supports Java ME CDC Projects, such as for mobile client-side Java.
java.api.common=API implementations common to all the project types.
java.debug=Navigator for Java AST
javadoc=Supports Javadoc creation and searches.
java.editor.lib=Contains java editor library implementation
java.editor=Contains java editor implementation
java.examples=Provides Java SE application samples.
java.freeform=Support of Java development in Freeform project.
java.guards=Provides Java Guarded Sections implementation
java.helpset=Java Support Documentation
javahelp=Permits JavaHelp help sets to be added to the IDE.
java.hints.analyzer=Javadoc Analyzer
java.hints.analyzer=Task List window implementation
java.hints=Hints Provider for Java
java.j2seplatform=General-purpose Java platform and library definitions.
java.j2seproject=Supports plain Java projects, such as for client-side Java SE.
java.kit=Support for development in Java.
java.lexer=Lexical analysis for java language
java.navigation=Adds support for structural views of Java \
java.platform=Infrastructure and APIs for configuring and searching Java platforms.
java.project=Support for defining Ant-based project types involving Java sources.
javascript.hints=Additional source code hints for JavaScript
javascript.kit=An umbrella module covering all modules required for JavaScript support: editing, refactoring, hints, etc.
javascript.libraries.dojo=Installs the Dojo JavaScript Library
javascript.libraries.jquery=Installs the jQuery JavaScript Library
javascript.libraries.prototype=Installs the Prototype JavaScript Library
javascript.libraries.scriptaculous=Installs the Scriptaculous JavaScript Library
javascript.libraries=JavaScript Library Manager
javascript.libraries.yahooui=Installs the YahooUI JavaScript Library
java.source=Java Source Infrastructure
java.sourceui=UI classes for Java source files
javawebstart=Support for Java Web Start
jconsole=JConsole module
jellytools=A library used for GUI-testing NetBeans IDE.
jemmy=Jemmy test library.
jmx.common=Common classes for JMX and JConsole NetBeans modules
jmx=JMX Wizard module
jsp.lexer=Lexical analysis for JSP language
jumpto=An action to quicky \
jumpto=Open Type allows you to jump to type declarations in other files
junit=Creates tests suitable for the JUnit framework.
languages.bat=Support for .bat files editing.
languages.css=Support for editing CSS files.
languages.diff=Support for editing .diff files.
languages.javascript=Support for editing JavaScript files.
languages.manifest=Support for editing .manifest files.
languages.php=PHP editor.
languages.refactoring=Refactorings for Generic Support for Integration of Programming Languages into NetBeans IDE
languages.sh=Support for editing .sh files.
languages=Generic Support for Integration of Programming Languages into NetBeans IDE
languages.yaml=Support for editing YAML files.
lexer.editorbridge=Enables use of the lexer module with the current editor
lexer.nbbridge=Allows to search for language descriptions by using MimeLookup
lexer=Enables lexical analysis
lib.cvsclient=A CVS client library, that substitutes the client side of the native CVS executable.
libs.aguiswinglayout=Free Layout for AGUI Profile based on org.jdesktop.layout.GroupLayout
libs.bytelist=JRuby ByteList Library
libs.cglib=This module bundles Code Generation Library
libs.commons_fileupload=This plugin bundles Commons FileUpload.
libs.commons_logging=This module bundles Apache Commons Logging.
libs.commons_net=This plugin bundles Commons Net.
libs.freemarker=This module bundles Freemarker.
libs.glassfish_logging=This module bundles Glassfish Commons Logging.
libs.httpunit=HttpUnit Test.
libs.ini4j=Bundles ini4j.jar.
libs.jakarta_oro=This plugin bundles Jakarta ORO.
libs.javacapi=The javac public API
libs.javacimpl=The javac implementation classes.
libs.javacup=Java CUP 11a integration
libs.jna=Bundles JNA library.
libs.jsch=Bundles JSch (SSH implementation).
libs.jsr223=This module bundles the Scripting APIs
libs.junit4=Bundles the JUnit 4.x testing library.
libs.jvyamlb=YALM Library Library (jvyamlb)
libs.lucene=Bundles Apache Lucene (a Search Engine).
libs.ppawtlayout=Free Layout for Personal Profile based on org.jdesktop.layout.GroupLayout
libs.springframework=Bundles the Spring Framework.
libs.svnClientAdapter=Bundles tigris.org's svnClientAdapter.jar.
libs.svnjavahlwin32=Bundles subversion client for windows
libs.xerces=Bundles Apache Xerces (an XML parser).
libs.xmlbeans=XMLBeans development and runtime libraries
lib.terminalemulator=A terminal emulator library written in Java.
lib.uihandler=Collects Information about UI Gestures
loadgenerator=Generic load generation infrastructure
localhistory=Implemets Local History for the IDE
masterfs=Merges multiple filesystem providers into a single logical tree.
maven.kit=NetBeans Maven project system support
maven.spring=Module bridging Maven and Spring features
mercurial=Mercurial Versioning System
mobility.antext=Provides Java ME extensions to Ant.
mobility.cldcplatform.catalog=Java ME Platform SDK Catalog
mobility.cldcplatform=Java Micro Edition CLDC Platform
mobility.databindingme=Provides runtime libraries for databinding on mobile devices.
mobility.deployment.ftpscp=FTP/SCP Deployment of Java ME Project
mobility.deployment.nokia=Deployment on Nokia phones
mobility.deployment.ricoh=Deployment on Ricoh devices
mobility.deployment.sonyericsson=Sony Ericsson Deployment of Java ME Project
mobility.deployment.webdav=WebDAV Deployment of Java ME Project
mobility.editor=Java Micro Edition Editor Support module
mobility.end2end.kit=Support for mobile end-to-end applications such as Java ME web services or mobile to web
mobility.end2end=Java ME Client to Web Application Generator
mobility.javahelp=Online documentation for Java ME.
mobility.jsr172=Stub generator for Java ME Web Service Clients (JSR 172)
mobility.kit=Java Mobile Edition System Core
mobility.licensing=Mobility Licensing module.
mobility.midpexamples=Provides a lot of MIDP examples.
mobility.plugins.mpowerplayer=SDK MPowerPlayer support for Netbeans Mobility
mobility.proguard=Provides ProGuard Obfuscator for Java ME extensions to Ant.
mobility.project.ant=Debugger support for Java ME Build System Core
mobility.project.bridge.impl=Implementation of isolation API between core Mobility project and advanced IDE functionality
mobility.project.bridge=Isolation API between core Mobility project and advanced IDE functionality
mobility.project=Java Mobile Edition Build System Core
mvd=Java Mobile Edition Visual Editor
nbjunit=NetBeans extensions to JUnit
o.apache.jmeter.kit=JMeter load generator integration bundle
o.apache.jmeter.module=JMeter integration module
o.apache.tools.ant.module.docs=Documentation for the Ant build tool.
o.apache.tools.ant.module=Supports writing of build scripts.
o.apache.xml.resolver=Apache Resolver library for development time
o.jdesktop.beansbinding=Bundles beans-binding library.
o.jdesktop.layout=Bundles swing-layout library.
o.jruby.distro=Bundled distribution of JRuby and Ruby on Rails
o.jruby=The actual JRuby implementation
o.kxml2=XML Pull Parser implementation
o.mozilla.rhino.patched=A patched version of Rhino for IDE language processing
o.n.bluej=Allows to work with BlueJ projects in NetBeans
o.n.bootstrap=The core bootstrap of NetBeans-based applications.
o.n.core=The basic framework of NetBeans-based applications.
o.n.insane=INSANE heap profiling library.
o.n.soa.libs.jgo=Wrapper module for the JGO visual library.
o.n.soa.libs.wsdl4j=WSDL4J
o.n.soa.libs.xmlbeans=XMLBeans development and runtime libraries
o.n.swing.dirchooser=\
o.n.swing.plaf=Handles per-look-and-feel UIManager customizations for NetBeans
o.n.swing.tabcontrol=The tab control used by the window system
o.n.upgrader=Import IDE environment and settings.
o.n.xml.libs.jxpath=JXPath Library.
o.openidex.util=Search API for use by various modules.
openide.actions=Definition of common actions for NetBeans
openide.awt=User interface utilities.
openide.compat=Some old classes that are now deprecated.
openide.dialogs=Handles dialogs and wizards.
openide.execution=Execution API from the Open APIs.
openide.explorer=Various view for displaying node structures.
openide.filesystems=Virtual File System API.
openide.io=Open APIs relating to displaying output.
openide.loaders=NetBeans Open API for manipulating data objects.
openide.modules=APIs for getting information about installed modules.
openide.nodes=API for defining generic tree-like structures.
openide.options=Support for storing preferences.
openide.text=Generic API wrapping Swing based EditorKits.
openide.util.enumerations=Enumeration API that is in wrong package.
openide.util=Basic Utilities API.
openide.windows=API for managing components on a screen.
options.api=Provides the Options dialog and an SPI to add panels to it.
options.editor=Provides the editor related panels in the Options dialog.
o.rubyforge.debugcommons=Integration of debug-commons-java library
performance=The basic core framework of the IDE.
performance=The basic core framework of the IDE.
php.dbgp=PHP Debugger.
php.doc=PHP Documentation.
php.editor=Support for editing PHP files
php.help=Online help pages for the IDE's PHP support
php.kit=Provides tools and support for php development.
php.lexer=PHP Lexer
php.model=PHP model.
php.project=Support for PHP projects.
php.rt=PHP runtime explorer.
php.samples=PHP Sample projects for NetBeans Sample Catalog
print=Implementation of print module.
profiler.attach=Attach wizard integration provider SPI
profiler.loadgen=Profiler -> LoadGenerator Bridge
progress.ui=Task progress visualization.
project.ant=Supports all project types based on Ant as a build tool.
projectapi=General API for accessing and loading IDE projects.
projectimport.eclipse.core=Imports projects created in Eclipse IDEs into NetBeans.
projectimport.jbuilder=Imports projects created by JBuilder IDE into NetBeans.
project.libraries=Support for organizing resources into libraries.
projectuiapi=Supplies the APIs/SPIs for user interface of projects in the IDE.
projectui.buildmenu=Supplies the Run and Debug menu for java/c++ projects.
projectui=Supplies the basic user interface for projects in the IDE.
properties=Supports editing of .properties files.
properties.syntax=Syntax coloring for .properties files in the source editor.
queries=Acts as a general communication channel between modules.
quiz=Quiz Module
registration=Enables user to register to Sun Online Account
ruby.debugger=Ruby Debugger
ruby.extrahints=Extra source code hints for Ruby
ruby.help=Online help pages for the IDE's Ruby support
ruby.hints=Additional source code hints for Ruby
ruby.javaint=Support for accessing Java libraries using JRuby in Ruby projects
ruby.kit=An umbrella module covering all modules required for Ruby support: editing, projects, Rails, etc.
ruby.platform=Infrastructure and APIs for configuring and searching Ruby platforms.
ruby.project=Supports plain Ruby projects
ruby.rakeproject=Supports all project types based on Rake as a build tool.
ruby.rspec=Support for RSpec, a testing framework for Ruby
ruby.samples.depot=Depot Sample Application
ruby.testrunner=Ruby Test Runner
ruby.themes=Additional editor color themes designed for use with the Ruby file types in NetBeans.
schema2beans=Library for representing XML as java beans; development time variant.
schema2beans=Library for representing XML as JavaBeans.
sendopts=GetOpts compliant API for parsing command line
server=Provides server integration.
servletapi=Servlet 2.2 API Library
servletjspapi=Servlet 2.5/JSP 2.1 API Library
settings=A library for storing settings in custom formats.
soa.kit=Shared classes for XSLT and BPEL modules.
soa.mappercore=SOA Mapper Core.
soa.mapper=SOA Mapper.
soa.reportgenerator=SOA Report Generator Framework.
soa.ui=SOA UI.
soa.validation=SOA Validation.
spi.debugger.ui=Basic shared debugger UI.
spi.editor.hints=Editor Hints Infrastructure
spi.navigator=Navigation support SPIs and APIs
spi.palette=Common Palette visualization and APIs
spi.quicksearch=Infrastructure for quick search in menu items, actions, files etc.
spi.tasklist=Provides API for Task List plugins
spi.viewmodel=TreeTableView Model
spring.beans=Spring Beans Support
spring.webmvc=Spring Web MVC Support
sql.help=JDBC Help.
sql.project=Composite Application Base Project.
sql.project=Support for SQL Application Projects.
sql.wizard=JDBC Wizard.
subversion=Integrates Subversion actions into IDE workflow.
swingapp=Swing Application Framework Support for Form Editor
tasklist.projectint=Integrates the Task List window with Projects system
tasklist.todo=Scan for ToDo items in source file comments
tasklist.ui=Task List window implementation
templates=Advanced Templating not only for Datasystems
testtools: Module providing additional support for XTest, Jemmy and Jelly technologies.
timers=Timers API
tomcat5=Tomcat servlet container integration
uihandler.exceptionreporter=Allows automatic reporting of exceptions to our UI Gestures Server
uihandler.interactive=Collects Information about UI Gestures
uihandler=Collects Information about UI Gestures
uml.codegen=Code Generation for the UML Tools
uml.designpattern=The Design Center provides the design pattern catalog.
uml.documentation=Provides a control to view and modify the documentation of a model element.
uml.dom4jlib=Dom4j Dependency Libraries
uml.drawingarea=The modeling drawing area control.
uml.drawingarea=Reverse Engineer GUI Addin.
uml.integration=Enables model-driven analysis, design and implementation using the Unified Modeling Language (UML).
uml.kit=NetBeans 5.5, UML Modeling Module
uml.parser.java=Provides parsing support for the Java 5.0 language.
uml.project=Supports plain UML projects
uml.propertysupport=Supports UML properties
uml.reporting=Provides the ability to execute web report.
uml.requirements.doorsprovider=A requirements provider that uses DOORS to persist requirements.
uml.requirements=The requirements framework.
uml.requirements.xmlrequirements=A requirements provider that uses an XML file to persist requirements.
uml.samples=A sample Java project with its reversed engineered UML project counterpart.
uml.samples=Sample UML Model Projects
uml=Contains the core functionality for all modeling projects.
uml=Associate With Dialog Addin.
updatecenters=Declares NetBeans autoupdate centers.
usersguide=Online documentation for the IDE.
utilities.project=Support for searching projects for files.
utilities=Support for file searching, bookmarks.
versioning=Support module for Versioning systems.
versioning.system.cvss=Integrates CVS actions into IDE workflow.
visdev.prefuse=Library for Prefuse Graphing Toolkit
visualweb.api.designer=Visual Editor Hack APIs
visualweb.api.insync=InSync Source Modeler APIs
visualweb.api.j2ee=API Extensions for J2EE
visualweb.api.portlet.dd=Provides an API for a portlet deployment descriptor
visualweb.compatibilitykit=Contains libraries needed for Visual Web JSF web application development in certain environments
visualweb.dataconnectivity.designtime=Design Time Classes for Data Connectivity
visualweb.dataconnectivity=Database and Data Source related
visualweb.designer.markup=Designer Markup and CSS Impl.
visualweb.designer=The Visual Designer enables you to create pages in WYSIWYG mode
visualweb.designtime.base=Base design-time implementations
visualweb.designtimeext=Design-Time API Extension for component authors
visualweb.designtime=Design-Time API
visualweb.designtime=Design-Time API for component authors
visualweb.ejb=Enterprise Java Bean Support
visualweb.errorhandler.client=Web Application error handler client
visualweb.errorhandler=Web Application error handler server
visualweb.extension.openide=Extends Openide.
visualweb.gravy=A library used for GUI-testing NetBeans IDE Visual Web features.
visualweb.insync=InSync provides abstract source manipulation support for Java, XML, and HTML
visualweb.jsfsupport.components=JSF Components
visualweb.jsfsupport.designtime=Visual Web Design-Time support and standard JSF components
visualweb.jsfsupport=JSF Support Container
visualweb.kit=Visual development of web applications with Java Server Pages
visualweb.libs.batik=Batik CSS Parser (modified)
visualweb.libs.jtidy=JTidy HTML cleaner (modified)
visualweb.libs.rowset=JDBC RI Rowset Library
visualweb.project.jsfloader=JSF Loaders faking one JSF object.
visualweb.project.jsf=Support for development of web applications based on JavaServer Faces.
visualweb.project.jsf=Supplies the basic user interface for projects in the IDE.
visualweb.propertyeditors=Property Editors
visualweb.ravehelp.rave_nbpack=Online help pages for the IDE
visualweb.websvcmgr=Web Service Support
visualweb.web.ui.appbase=Application Runtime API
visualweb.webui=Wrapper module for Sun Web User Interface Component runtime library
visualweb.webui.themes=Default themes for the Sun Web UI Components
visualweb.xhtml=Defines beans for most XHTML elements
vmd.analyzer=Visual Mobile Designer - Analyzer
vmd.codegen=Visual Mobile Designer - Code Generator
vmd.components.midp.pda=JSR 75: Accessing the PIM database and File system custom components.
vmd.components.midp=Provides basic set of Netbeans MIDP custom components.
vmd.components.midp.wma=Wireless Messaging API (WMA) custom components.
vmd.componentssupport=Visual Mobile Designer - components creation
vmd.componentssupport=VMD Custom Component Project
vmd.componentssupport=VMD Custom Component Project
vmd.componentssupport=VMD Custom Component Project
vmd.flow=Visual Mobile Designer - Flow Designer
vmd.game=Visual editing support for MIDP 2.0 Game API
vmd.inspector=Visual Mobile Designer - Inspector
vmd.io.javame=Visual Mobile Designer - Java ME Communication IO Implementation
vmd.io=Visual Mobile Designer - Input Output
vmd.kit=Support for visual development in JavaME.
vmd.midpnb=Visual Mobile Designer - MIDP NetBeans Components
vmd.midp=Visual Mobile Designer - MIDP
vmd.model=Visual Mobile Designer - Model
vmd.palette=Visual Mobile Designer - Palette
vmd.properties=VMD Properties
vmd.screen=Visual Mobile Designer - Screen Designer
vmd.structure=VMD Structure Browser
web.client.javascript.debugger.ant=Lets you use the NetBeans JavaScript debugger from Ant.
web.client.tools.firefox.extension=This module implements the JavaScript Debugger Firefox Extension.
web.client.tools.impl=This module contains the Web Client JavaScript Debugger API classes.
web.client.tools.impl=This module contains the Web Client JavaScript Debugger UI classes.
web.client.tools.impl=Web Client Tools Implementation.
web.client.tools.internetexplorer=This module implements the NetBeans Add-on for Internet Explorer.
web.client.tools.kit=Support for web client tools.
web.core=Supports the creation, editing, compiling, and testing of JavaServer Pages.
web.core.syntax=Provides editing support for JSP files.
web.debug=Supports the debugging of JSP
web.examples=Provides web application examples.
web.flyingsaucer=Allows to render XHTML documents using CSS
web.freeform=Support of Web development in Freeform project.
web.jsf12ri=Wrapper module for JavaServer Faces 1.2 RI
web.jsf12=Installs the JavaServer Faces 1.2 Library
web.jsf.kit=JavaServer Faces support.
web.jsf.navigation=The Page Flow Editor lets you edit page flow
web.jsf=Support for development of web applications based on JavaServer Faces.
web.jspparser=Provides support for parsing JSP files using the Jakarta JSP parser.
web.jstl11=Installs the JSP Standard Tag Library 1.1.
web.kit=Basic Java web application support.
web.libraries.jsf1102=Installs the JavaServer Faces 1.1.02 Library
web.monitor=Tracks data flow inside the servlet engine
web.project=Support for web module projects.
web.struts=Support for Struts Framework
websvc.axis2=Axis2 Support
websvc.clientapi=SPI for modules that are web service consumers.
websvc.core=Provides generic support for development and consumption of web services.
websvc.customization=Provides support for JAX-WS customization.
websvc.design=Visual Designer for Web Services
websvc.editor.hints=Hints support for JAXWS Web Services
websvc.jaxrpc16=Installs the JAX-RPC libraries from JWSDP 1.6
websvc.jaxrpckit=JAX-RPC Web Services Development Support
websvc.jaxrpc=Provides support for development and consumption of JAX-RPC web services.
websvc.jaxws21api=JAX-WS 2.1 API
websvc.jaxws21=Installs the JAX-WS 2.1 client libraries
websvc.jaxwsapi=SPI for modules that are JAX-WS service providers.
websvc.jaxwsmodel=JAX-WS(wsimport) WSDL to Java model and project support for JAX-WS technology.
websvc.kit=Provides generic support for development and consumption of web services.
websvc.manager=IDE-wide registration for web services
websvc.metro.samples=Provides examples of Metro web services
websvc.projectapi=Web Services Project API
websvc.registry=Web Services Implementation
websvc.registry=Web Service Registry Implementation
websvc.restapi=API/SPI for RESTful Web Services Support
websvc.restkit=RESTful Web Services Development Support
websvc.restlib=Installs JAR files for JSR-311 API and reference implementation.
websvc.rest.samples=RESTful Web Services Sample Projects
websvc.rest=Support for creation of RESTful Web Services
websvc.saas.api=API supporting consumers of SaaS (Software as a Services)
websvc.saas.codegen.j2ee=Provides code generation support for consuming SaaS services in Java EE applications.
websvc.saas.codegen.java=Provides code generation support for consuming SaaS services in Java desktop applications.
websvc.saas.codegen.php=Provides code generation support for consuming SaaS services in PHP applications.
websvc.saas.kit=Provides support for consuming SaaS services.
websvc.saas.services.strikeiron=StrikeIron Service Component
websvc.saas.services.strikeiron=StrikeIron Service Component
websvc.saas.ui=SaaS Services UI
websvc.utilities=Utilities for Web Services
websvc.websvcapi=SPI for modules that are JAX-RPC service providers.
websvc.wsitconf=Provides support for web services interoperability technologies.
websvc.wsitmodelext=Provides WSDL extensions to other (WSIT or other) modules.
websvc.wsstackapi=Web Services Stack API
websvc.wsstack.jaxws=JAX WS Stack Description
welcome=Shows welcome content after the first startup of the IDE.
wsdlextensions.file=FILE extension for wsdl editor.
wsdlextensions.ftp=FTP extensions in WSDL editor.
wsdlextensions.jms=Provides JMS extensions in WSDL editor.
wsdlextensions.snmp=Provides SNMP extensions in WSDL editor.
xml.catalog=The module allows to persistently mount entity catalogs.
xml.core=This module keeps some miscellaneous APIs.
xml.jaxb=Java XML binding wizard and utilities.
xml.kit=XML, Schema and WSDL related tools.
xml.multiview=XML Multiview Editor Infrastructure
xml.nbprefuse=Prefuse Customization Module
xml.refactoring=Refactoring support for XML-based components.
xml.refactoring=Graph Analysis of XML Schema Relationships
xml.retriever=Retriever and XML catalog support
xml.schema.abe=Support for the graphical design view of the schema editor
xml.schema.model=API for manipulating XML Schema
xml.schema.refactoring=Refactoring of Schema Component Usages
xml.schema=The module provides support for XML Schema.
xml.search=XML Search.
xml=The module is a base for all XML related modules.
xml.tax=The module contains Tree API for XML ("TAX") library.
xml.text=The module provides text editing capabilities.
xml.tools.java=The module contains various actions and generators.
xml.tools=The module contains various actions and tools.
xml.validation=XML Validation module
xml.wsdl.bindingsupport.api=WSDL Binding Support API
xml.wsdl.bindingsupport=WSDL Extensibility Elements Support
xml.wsdl.extensions=Extensions to WSDL Model
xml.wsdlextui=WSDL Editor Extensions.
xml.wsdl.kit=WSDL related tools.
xml.wsdl.model=WSDL Model
xml.wsdl.refactoring=Support for XML Refactoring in WSDL
xml.wsdlui=WSDL Editor for editing and creating WSDL documents.
xml.wsdlui=FTP extensions in WSDL editor.
xml.wsdlui=Provides JMS extensions in WSDL editor.
xml.xam=Framework for design synchronous object model from textual document.
xml.xam.ui=Interface code common to clients of the XAM model.
xml.xdm=An toolable document model for XML
xml.xpath.ext=XPath model with deep resolving of schema objects
xml.xpath=XPath 1.1 Model.
xsl=The module contains simple XSL support.
xslt.core=XSLT Core.
xslt.help=XSLT Help.
xslt.kit=XSLT development support.
xslt.mapper=XSLT Mapper.
xslt.model=XSLT Model.
xslt.project=XSLT Project.
xslt.tmap=Transformmap Core.
xslt.validation=XSLT Validation.

My module requires JDK 6; how do I keep it from being loaded in JDK 5?

Add a line to your manifest, specifying which version of Java you need. E.g. to only run on JDK 6 and higher, not 5:

OpenIDE-Module-Java-Dependencies: Java > 1.6

Note that > really means >=, and that the traditional "internal" version numbers like "1.5", "1.6", etc. must be used despite the new Java naming scheme (JDK 5, JDK 6, ...).

Requesting 5+ is pointless since no recent version of NetBeans runs on JDK 1.4 anyway.

There is also a syntax for requesting a particular version of the virtual machine (as opposed to Java platform APIs) but this is seldom if ever used.

By default, your module will depend on the same Java version as you specify for javac.source, i.e. the version of the Java language your module requires.

The NetBeans module development support permits you to pick a JDK to use for compiling (and running) a module or suite. Obviously you must specify a JDK at least as new as what your dependency requests; it is unwise to specify a newer JDK than that: you might accidentally use some newer APIs without realizing it, making your code not actually run on the declared minimum version.


Applies to: NetBeans 6.x

Platforms: all

What is the difference between a suite and a cluster?

Suite

A suite is a container project used to group external module projects into a unit whose members can refer to one another as well as to a NB platform. If you only have one module project, you can treat it as "standalone" and you do not need a suite, but using a suite is advisable for serious projects since it offers you more options, such as adding library wrapper modules, or creating a complete application based on your module.

Since NetBeans 6.7 a suite can depend either on another suite, standalone module or even external binary cluster, see DevFaq How To Reuse Modules. If you use version earlier than 6.7 a suite S2 cannot directly depend on another suite S1. But if S1 uses NB platform P1, you could create a derived platform P2 by building S1 on top of P1, and then select P2 as the NB platform for S2. Then S2 can refer to all the modules in P1 as well as the modules built from S1.

The NB IDE build (from sources on hg.netbeans.org) does not use suites. It uses a historical build infrastructure which partially overlaps the external module/suite build harness introduced in 5.0, but which has different requirements (and is considerably more complex). Module projects physically inside the netbeans.org source tree cannot be "standalone" modules nor "suite component" modules - they are simply netbeans.org modules, and as such use a (slightly) different format for metadata, and have access to somewhat different facilities specific to netbeans.org practices.

Cluster

A cluster is simply a subdirectory of a NB-based-app's binary installation; every module in the installation falls into one cluster. The installation is divided into clusters for purposes of:

  1. Conceptual clarity.
  2. Possible mapping to native packaging systems such as RPM.

The NB team has a policy of treating inter-cluster module dependencies as more significant than intra-cluster module dependencies with respect to backward compatibility, with the aim of making it possible for product teams building on top of the NB IDE to select a subset of the IDE to use with cluster granularity rather than with module granularity, which may be simpler to grasp and integrate with native packaging. But there is nothing preventing you from reusing a subset with module granularity.

The NB launcher (nbexec) accepts a list of cluster directories to load modules from - basically a search path. There are no further semantics to clusters.

The suite project type has a standard build target to assemble a complete application. For simplicity, it simply places all modules built from suite sources into their own cluster named in accordance with the suite's name.

NBMs may specify a cluster. The netbeans/ subdirectory of the NBM (which is a ZIP file) has a file layout which matches the layout of files within a single cluster. Each cluster managed by Auto Update has an update_tracking/ subdirectory with one XML file per module, enumerating the files which that module contributes to the cluster.

Currently the "NB Platform" is just the platform* cluster from the IDE, though the choice of modules may not be exactly what you want for every "platform" application.

Clusters are supposed to be medium-grained or coarse-grained, unlike modules which are generally fine-grained units.

References:


Applies to: NetBeans 6.5

How can I change the contents of a menu according to the selected file in the editor?

Can I hide or show a whole menu or toolbar?

To hide a menu or toolbar you have to edit your layer.xml and append _hidden to the name of the desired menu or toolbar. You may also hide *.instance files.

<folder name="Menu">
    <!-- Hide View menu -->
    <folder name="View_hidden"/>
    <folder name="SomeMenu">
        <!-- Hide a single menu item -->
        <file name="SomeAction.instance_hidden"/>
    </folder>
</folder>
<folder name="Toolbars">
    <!-- Hide Edit toolbar -->
    <folder name="Edit_hidden"/>
</folder>

It's generally much easier to do this from the NetBeans IDE, as described here.

How can I register services into the default lookup using the system filesystem?

In short, you probably do not want to. The typical way of registering services is via META-INF/services registration: DevFaqLookupDefault. That method is easier to use and offers compatibility with non-platform applications via the Java Extension Mechanism.

But there are some special cases when registration via the system filesystem is needed. One example might be when you want to dynamically change or unregister services, since the system filesystem is writable at runtime. Again such needs are rare and you should probably avoid doing this unless there is no alternative. (Usually the service interface should be defined so that the service itself is a singleton, but it can create other objects on demand and signal certain events.) Another minor use case is to register several services with the same implementation class but different parameters; META-INF/services registrations require a zero-argument constructor, meaning you need a different implementation class for each distinct service.

As an example, assume that Module 1 defines an interface com.tomwheeler.example.intf.SampleInterface which is exported to other modules. Module 2 depends on Module 1 and provides an implementation of that interface named com.tomwheeler.example.impl.SampleImplementation. Module 1 does not need anything in its layer file (or even need a layer file at all), but Module 2 can register the service like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.2//EN" 
                            "http://www.netbeans.org/dtds/filesystem-1_2.dtd">
<filesystem>
    <folder name="Services">
        <folder name="Hidden">
            <file name="com-tomwheeler-example-this-name-is-Irrelevant.instance">
                <attr name="instanceClass"
                      stringvalue="com.tomwheeler.example.impl.SampleImplementation"/>
                <attr name="instanceOf"
                      stringvalue="com.tomwheeler.example.intf.SampleInterface"/>
            </file>
        </folder>
    </folder>
</filesystem>

The name of the file is arbitrary but must end with .instance. The value of the instanceClass attribute needs to define the implementation class being registered, while instanceOf defines the interface (or abstract class) being implemented.

If you want to create the implementation using a factory method rather than calling a zero-argument constructor, replace instanceClass with instanceCreate, e.g.:

<attr name="instanceCreate"
      methodvalue="com.tomwheeler.example.impl.SampleImplementations.make"/>
It is also possible to pass parameters to the factory method; see API documentation for details.

Client code is unaware of the registration mechanism, so the code used to look up a registered implementation of the interface would be the same as always; for example:

SampleInterface intf = Lookup.getDefault().lookup(SampleInterface.class);
// now do something with intf...

What is the System Filesystem?

The system filesystem is the central repository for configuration data in NetBeans. It is composed at runtime of a stack of XML layers (DevFaqModulesLayerFile) supplied by modules in the system. Modules use folders in the system filesystem to define extension points - a module can define a folder and document what files or objects (typically instance files: DevFaqInstanceDataObject) other modules can put there, and then, at runtime, scan the contents and do something with the result.

The top layer of the System Filesystem is the config/ subfolder of the user directory. (DevFaqUserDir) That is what makes the System Filesystem read-write - diffs are written there, and there are semantics for programmatically deleting files by creating a 0 byte file called, e.g., TheFile.instance_hidden.

Any type of file can be put into the System Filesystem; what is done with those files is a contract between the module that defines a folder and documents what can be put there, and the modules that put things there. You can use FileUtil.getConfigFile to access entries at runtime.

The same mechanism for file recognition that recognizes user files on disk recognizes files in the system filesystem - so you can put a .java file in the system filesystem, and it can be opened in the editor and edited just as a file on disk can (if saved, it will be written to the user dir on disk, and the newly written file will then be the actual content. In fact, this is why file templates in the IDE can be edited.

Some folders have special meaning to the system, because they are defined by modules that are part of the NetBeans Platform. Some of them are:

  • Actions/ - A global repository for actions in the system, it contains subfolders which categorize actions into ad-hoc categories. This folder is what is represented in the Options dialog in Look And Feel | Actions. If you install actions, the typical pattern is to put an *.instance file here.
  • Menu - The contents of the menu bar in the main window - it has a folder for each menu; subfolders of these represent submenus, and *.instance files represent Actions to be shown on the menus.
  • Loaders - Contains subfolders that define mime types (e.g. Loaders/text/x-java) which are used to define various attributes such as popup menu items that should appear when the user right clicks on a file of a given MIME type.

There are several things, all or some of which may be specified by a module's API and affect how objects are used:

  • The location of a file - a module may define a folder that modules put objects directly into, or request that client modules create subfolders in that folder in cases where the entire path to the file has semantic meaning (see below).
  • The type of the file - very often you will install *.instance files that represent Java objects; typically the module will specify what classes or interfaces objects in a folder should be assignable from.
  • File attributes (DevFaqFileAttributes) - for cases where additional information is required to describe what to do with the files client modules add to the folder, some optional or mandatory key-value attributes may be specified.

Available documentation on System Filesystem contents

List of files and folders in the system filesystem in NetBeans API Javadoc lists some locations. Feel free to file documentation bugs for modules you know read other locations but which fail to list them in their arch.xml file.


Applies to: NetBeans 6.5, 6.7

Writing Tests For DataObjects and DataLoaders

Quite easy. At least in NetBeans 6.5 and newer. Everything shall work as declarative MIME resolvers are loaded automatically from unit tests and loaders are available from unit tests automatically.

Example code is below:

    private static final String BAD_MANIFEST_CONTENT =
            "Manifest-Version: 1.0\n" +
            "junk junk junk\n" +
            "some more junk\n";
    private static final String GOOD_MANIFEST_CONTENT =
            "Manifest-Version: 1.0\n" +
            "Java-Bean: true\n" +
            "OpenIDE-Module-Name: com.foo.bar\n\n";

    @Test public void checkContent() throws Exception {
        FileSystem fs = FileUtil.createMemoryFileSystem();
        FileObject good = fs.getRoot().createData("good.mf");
        writeFile(GOOD_MANIFEST_CONTENT, good);
        DataObject goodDob = DataObject.find(good);

        FileObject bad = fs.getRoot().createData("bad.mf");
        writeFile(BAD_MANIFEST_CONTENT, bad);
        DataObject badDob = DataObject.find(bad);

        YourInterface y = goodDob.getLookup().lookup(YourInterface.class);
        y.doYourTest();
    }

    private void writeFile(String content, FileObject file) throws Exception {
        OutputStream os = file.getOutputStream();
        os.write(content.getBytes("UTF-8"));
        os.close();
    }

In the somewhat unusual case in which your unit test resides in a different module from that which contains your file support code (DataLoader, DataObject, etc.), you will need to add a <test /> dependency on the module which contains the file support code. Currently this can only be done by editing the project.xml file for the module containing your unit tests. See the build harness' README for more information; you can find the relevant section by searching for test-dependencies in that file.

Older versions than 6.5

If you are writing a test for a DataObject, you need to set up enough of the DataLoader infrastructure that DataObject.find() will locate your DataLoader and call it to create your DataObject subtype.

First, use the setup code described in Testing Things That Use File Objects. Add to the test's setUp() method a call to FileUtil.setMIMEType() to manually assign the file extension to the MIME type of your DataLoader.

FileUtil.setMIMEType("mf", "text/x-manifest");

(setMIMEType() is deprecated with respect to usage from inside a module, but it is fine to use it in a unit test).

(For XML file subtypes, FileUtil.setMIMEType() on *.xml is not likely to work. You can instead register a MIMEResolver in default lookup which does whatever you need.)

Second, you need to make sure your DataLoader is registered in the default Lookup so that DataObject.find() will find it. In 6.0, the New File Type template will set this up automatically by creating the correct file in test/unit/META-INF/services. (Or you can get better control by using org.openide.util.test.MockLookup.)

How do I test something which uses the System Filesystem?

If your test makes use of a class that uses the system filesystem, and in particular specialized protocol handlers like nbresloc://, then you might encounter a MalformedURLException because the test classpath does not include the protocol handlers needed to resolve content from the system filesystem.

In this case, you need to add the following dependencies for your test classpath:

  • Bootstrap (org.netbeans.bootstrap)
  • Startup (org.netbeans.core.startup)
  • Master Filesystem (org.netbeans.modules.masterfs)

In the NetBeans IDE, this is most easily accomplished by right-clicking the "Unit Test Libraries" folder beneath your module project's node and selecting the "Add Unit Test Dependency." But because these modules don't export public APIs, you will need check the "Show Non-API Modules" box before they'll appear in the list.

I need to run some code on a background thread. Can the platform help me?

First, ask yourself why you need to do this and if it is really necessary. Generally there is only one reason: You are doing something takes some time (file I/O, computing something large and complicated, talking to a network socket) that will block the UI.

NetBeans contains a thread pool org.openide.util.RequestProcessor. (You can use the thread pools that exist today in java.util.concurrent but it is more typical to use RequestProcessor.) There is a general purpose built-in thread pool - RequestProcessor.getDefault(). You can use that for things that only happen once in a while; otherwise you are probably better off creating your own instance of RequestProcessor. There is a FAQ item about how to know when to do which. In its most simple usage, RequestProcessor.post() is called with a Runnable. The call returns a RequestProcessor.Task which you can use to monitor the status of the task.

Note that if you are doing something in the background, you may want to use the Progress API to show a progress indicator in the status-bar (or use it to put up a modal progress dialog if the UI really needs to be blocked).

Remember that if you are running more threads than you have processors (or cores) - and your OS is probably using some as well - then when you ask to multi-thread, you are asking your CPU to divide the time of the CPUs you have between more virtual threads. And switching the context a CPU is working in - sending it off to some other memory space and set of instructions, and then another - takes time. So heavy use of multithreading, especially on single CPU machines, can slow things down rather than speed them up. If you can make your code run faster, do that first.

Where is TopManager? I'm trying to do the examples from the O'Reilly book

The O'Reilly book is old (written between 2001 and 2002) - the chapters on architectural background will still work, but many of the examples won't.

The generation of NB it was written for is from before Lookup (see DevFaqLookup) was in use. TopManager was a class with a bunch of static methods for getting service objects. It is now gone.

For pretty much everything available via TopManager, simply take the class you were looking for and try SomeClass.getDefault() - that's typically the modern way to do this sort of thing. TopManager caused a tangle of interdependencies between different APIs that it was very desirable to remove.

If you were calling TopManager.getDefault().getPlaces().nodes().projectDesktop() in a NetBeans 3.x based application, there is no direct equivalent in NB 4.0 and later. Rather, there is a rich set of project-related APIs which can be used for various purposes. As a rule, there is no 1-to-1 conversion from the above idiom to NB 4.0+; the affected O'Reilly examples would need to be rewritten to make sense today.


Applies to: NetBeans 4.0+

I need to write some code that tracks the global selection. What should I do?

If you are writing an action, consider using one of the context sensitive action classes in the apis such as NodeAction or CookieAction.

For other types of code (or for actions sensitive to something that does not implement Node.Cookie in the active TopComponent's or Node's Lookup , consider using Utilities.actionsGlobalContext().

Utilities.actionsGlobalContext() returns a Lookup which proxies the Lookup of the active (focused) TopComponent's Lookup (which, if it is an explorer view, is proxying the Lookup(s) of whatever Node(s) are selected). You can do something like this:

Lookup.Template tpl = new Lookup.Template (SomeApiClass.class);
Lookup.Result res = Utilities.actionsGlobalContext().lookup (tpl);
res.addLookupListener (new LookupListener() {
   public void resultChanged (LookupEvent evt) {
     Collection c = ((Lookup.Result) evt.getSource()).allInstances();
     //do something with the collection of 0 or more instances - the collection has changed
   }
});

The nice thing about this approach is that, unless your code specifically cares about Nodes, you don't need to depend on the Nodes API.

The idea behind this is that every "logical window" in NetBeans has its own Lookup, whose contents represent the "selection" in that window (or whatever services it wants to expose). Utilities.actionsGlobalContext() is a single point of entry - you don't have to track which window currently has focus - it is a Lookup which proxies the Lookup of whatever window does have focus. When the focused window changes, the Lookup returned by Utilities.actionsGlobalContext() will fire the appropriate changes. So, for example, an Action can be written to be sensitive to a particular object type; it does not need any code that relates to tracking window focus or similar.

Please note: Generally, keep a hard reference on the Lookup.Result (or make a closure on it with some final keyword and a reference from the anonymous listener). Because if you don't -- the garbage collector might kick in quite soon and your listener won't be called. Source: Lookup.Result garbage collection trick

How should I keep track of what the current nodeselection in the Explorer window is? Should I use the ExplorerManager ?

You can use the ExplorerManager if you created the explorer window, or you can programmatically get a reference to it. If you can somehow find a class implementing ExplorerManager.Provider then you can get the Explorer manager. This provider might in fact be a TopComponent in the TopComponent.Registry, if for example it was actually a ExplorerPanel.

But this is bad style - for example, if someone wrote a TopComponent that included a component implementing ExplorerManager.Provider, but as a subcomponent, and manually managed the node selection, this trick would fail.

Rather, if you know which top component you care about, you can just call TopComponent.getActivatedNodes() and this will work correctly even for non-Explorer components with a node selection, such as Editor panes open on Java sources.

Better still is to be agnostic about which top component should be providing the activated nodes, and just listen to changes in the TopComponent.Registry.PROPACTIVATEDNODES (or TopComponent.Registry.PROP_CURRENT_NODES as appropriate).

But best of all is not to have to ever directly pay attention to the node selection. If you only need to know the node selection in order to make some user action enabled or not, you should simply extend NodeAction; this class does all the dirty work for you of listening to changes in the node selection and updating its state automatically.

If you just want to write some code that is sensitive to the global selection (not an action), you probably want to use Utilities.actionsGlobalContext().

Multiple nodes selection - gotcha

If you allow multiple nodes to be selected you also have to keep in mind that certain other Netbeans components may only operate on single nodes.

One example is the Navigator. Let's suppose you have a navigator window associated with your selected node. What you will notice is that while your multiple selection is in focus, your code for acquiring the selected nodes returns all the selected nodes. If the focus is then switched to the Navigator window, only one node is retrieved, all that while the multiple selection is still there, in the un-focused window.

The reason is because along with the focus change, the (single) node represented by the Navigator and stored in its lookup becomes the global selection which your retrieval code will then grab.

I got a ClassNotFoundException or NoClassDefFoundError. How can I fix it?

The most likely explanation is that you have a problem in your dependencies. In order for a class in one module to reference a class/interface defined in another module, the following must be true:

  1. The class/interface being referenced must be visible to the code using it, according to the normal Java visibility rules. This typically means that the class must be public, since package-private access across modules is impossible.
  2. The package containing the class/interface must be exported (marked as providing an API visible to other modules). To "export" package, right click project, select Properties -> API Versioning and choose either public or friend export type.
  3. The module containing the code which uses this class/interface must declare a dependency on the module which provides it.

These rules are pretty straightforward and it is easy in most cases to verify that dependencies are set up correctly. If you receive a ClassNotFoundException or NoClassDefFoundError at runtime, the stack trace will generally lead you to the problem.

However, there are some cases where you will receive a ClassNotFoundException or NoClassDefFoundError at runtime, but finding which modules need to declare dependencies on one another is more difficult because the stacktrace does not directly identify the code involved. This occurs most frequently when you have library modules (composed of JAR files which were compiled outside of the platform). Although the dependencies were satisfied (by setting the classpath as needed) when the libraries were compiled, the developer may not have correctly set these dependencies in the platform application which uses them.

In this case, you can often locate the problem by rebuilding the suite and paying close attention to the output generated by the verify-class-linkage task. For example:

verify-class-linkage: Warning: a.SomeImplementation cannot access b.publicapi.SomeInterface

This tells us that the module which provides SomeImplementation needs to declare a dependency on the module which provides SomeInterface.

For more background, see Issue 145503.

Tutorial index

  • NetBeans Platform API starting point
    • How to use certain NetBeans APIs includes introductions to:
      • Actions
      • Ant-Based Project Support
      • Ant integration module
      • Autoupdate Services
      • Classfile Reader
      • Command Line Parsing
      • Common Palette
      • Database Explorer
      • Datasystems
      • Debugger Core
      • Debugger Core UI
      • Debugger JPDA
      • Dialogs
      • Diff module
      • Editor Braces Matching
      • Editor Code Completion
      • Editor Code Folding
      • Editor Code Templates
      • Editor Error Stripe
      • Editor Guarded Sections
      • Editor Indentation
      • Editor Library
      • Editor module
      • Editor Settings
      • Editor Utilities
      • File Systems
      • General Queries
      • I/O APIs
      • J2EE DD
      • Java EE Metadata
      • Java EE Server Registry
      • Java Platform
      • Java Project Support
      • Java SE Projects
      • Java Support
      • JUnit Tests
      • Lexer module
      • Look&Feel Customization
      • Master Filesystem
      • MIME Lookup
      • Module System
      • MultiView Windows
      • Navigator
      • Options Dialog
      • Progress
      • Project API
      • Project UI
      • Refactoring
      • Search API
      • Settings Options
      • Tab Control
      • Task List
      • TreeTableView model
      • UI Gestures Collector
      • UI Handler Library
      • Utilities
      • Visual Library
      • Web
      • Window System

Debugging modules

Once your module is installed all error messages are sent to your (NetBeans user directory)/var/log/messages.log; use that for watching what's going on.

You can use java.util.logging.Logger (or org.openide.util.Exceptions) to report exceptions and informational messages to the log file.

You can debug your own module from within NetBeans just like you would any other project. However, if you want to step into NetBeans code then you need to download the NetBeans source. You do not need to build it; just tell NetBeans where your NetBeans source code lives using Tools > NetBeans Platform Manager > Sources.

If you still have strange problems stepping into NetBeans code, try the following:

  • Open the NetBeans project that contains the code you are trying to access - for example, if you are stepping into the editor, open the NetBeans editor project.
  • Now run the debugger again then open the debugger sources window (Window > Debugging > Sources) and ensure all the checkboxes are ticked.
  • Now there is no reason why NetBeans debugging should fail!

An alternative way of debugging is to start NetBeans in debug mode as follows:

netbeans/bin/netbeans -J-Xdebug -J-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5858
then use Run > Attach Debugger and then choose Connector = SocketAttach, port = 5858 and timeout = 5000 and press OK.
Applies to: NetBeans 6.5+

How do I remove a menu item or toolbar button from a module's XML layer?

Refer to TaT_HackingNetBeansXMLLayerPartOne for more details on where to use the following tricks.

Trick #1

  • If you want to remove either one of the separators, or even both of them, then delete the entries looking like:
 
<file name="org-nvarun-tat-separatorAfter.instance">
    <attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
    <attr name="position" intvalue="175"/>
</file>
<file name="org-nvarun-tat-separatorBefore.instance">
    <attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
    <attr name="position" intvalue="125"/>
</file>

Trick #2

  • If you want to remove the action from a toolbar, then remove entries like:
<folder name="Toolbars">
    <folder name="Build">
        <file name="org-nvarun-tat-SayCheez.shadow">
            <attr name="originalFile"
                  stringvalue="Actions/Tools/org-nvarun-tat-SayCheez.instance"/>
            <attr name="position" intvalue="325"/>
        </file>
    </folder>
</folder>

Trick #3

  • If you want to remove the action from a menu, and retain it only on the toolbar, then remove entries like:
<folder name="Menu">
    <folder name="Tools">
        <file name="org-nvarun-tat-SayCheez.shadow">
            <attr name="originalFile"
                  stringvalue="Actions/Tools/org-nvarun-tat-SayCheez.instance"/>
            <attr name="position" intvalue="150"/>
        </file>
        <file name="org-nvarun-tat-separatorAfter.instance">
            <attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
            <attr name="position" intvalue="175"/>
        </file>
        <file name="org-nvarun-tat-separatorBefore.instance">
            <attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
            <attr name="position" intvalue="125"/>
        </file>
    </folder>
</folder>

Note that these tricks apply to the module which declares the action. You cannot remove an action declared in another module, but you can hide it: DevFaqSwitchingMenusByContext

(Reposted from this entry on NetBeans Zone.)

How do I have only shortcut keys for an action?

The New Action wizard allows you to uncheck both menu and toolbar placement for your action and only assign a keyboard shortcut. To learn how to do this manually, read on. Refer to TaT_HackingNetBeansXMLLayerPartOne for more details.

Trick #1

  • Retain the action's basic registration:
 
<folder name="Actions">
    <folder name="Tools">        
        <file name="org-nvarun-tat-SayCheez.instance"/>
    </folder>
</folder>
  • This registers an action as a Global Menu Item:
<folder name="Menu">
    <folder name="Tools">
        <file name="org-nvarun-tat-SayCheez.shadow">
            <attr name="originalFile"
                  stringvalue="Actions/Tools/org-nvarun-tat-SayCheez.instance"/>
            <attr name="position" intvalue="150"/>
        </file>
    </folder>
</folder>
  • This registers an action as a Global Toolbar Button:
<folder name="Toolbars">
    <folder name="Build">
        <file name="org-nvarun-tat-SayCheez.shadow">
            <attr name="originalFile"
                  stringvalue="Actions/Tools/org-nvarun-tat-SayCheez.instance"/>
            <attr name="position" intvalue="325"/>
        </file>
    </folder>
</folder>
  • To assign a shortcut key, replace either or both of them with something like the following:
<folder name="Shortcuts">
    <file name="O-F3.shadow">
        <attr name="originalFile"
              stringvalue="Actions/Tools/org-nvarun-tat-SayCheez.instance"/>
    </file>
</folder>

Trick #2

  • In the above example the action has the shortcut key Alt+F3, which is represented as O-F3. In general, if you have some key combination that uses Alt (or the equivalent on Mac OS X), then use O. Separate modifiers from the base keycode name with -, and append .shadow for the filename. Ctrl (or its Mac equivalent) is represented by D, and Shiftby S. (C and A represent the literal Ctrl and Alt keys, but this is less portable.)

Tips to Remember

  1. Following are some keycode equivalents. See Javadoc for KeyEvent for the full list:
    • A to Z (as is), F1 to F12 (as is), 0 to 9 (as is)
    • / as SLASH, \ as BACK_SLASH
    • ; as SEMI_COLON
    • . as PERIOD
    • as QUOTE

See also DevFaqKeybindings.

(Reposted from this entry on NetBeans Zone.)

DevFaqUIGestures

A perfect tool to get you know users of your application. Read more...

How should the LogRecords be named

Use structured logging e.g. use just a machine name for a log record's message and keep its localized version in a Bundle. Set the logger name to be below the namespace {org.netbeans.ui} in some meaningful subpackage.

The statistic on the server shall then recognize the logger name as well as the message.

How to verify that my "agent" is logging correctly?

Make sure the interactive gestures collector is installed. Make "Memory" toolbar visible. Execute the action that does the logging. Invoke the icon in the "memory" toolbar and "View Data". Use the combo box to scroll to the right message - which anyway should be somewhere at the bottom of the displayed file.

How to find out existing logger

They should be listed at at UILoggingInPlatform, UILoggingInBasicIDE, UILoggingInJ2EE and UILoggingInPHP.

Why can't I load properties using UIDefaults?

You may encounter this problem while porting a Swing application to the NetBeans platform or when using a third-party library like SwingX. While the following code works in a standalone Swing application, it does not load the property in a platform-based application:

UIManager.getDefaults().addResourceBundle("com.example.foo.sample");
myLabel.setText(UIManager.getString("greeting"));

This fails in the platform because of JDK bug #4834404. Although the best solution is to replace the original code to load properties in a way that uses the correct class loader, that may not be possible when using a third-party library. In these cases, your module can work around the problem by using code similar to this:

UIDefaults def = UIManager.getDefaults();
ResourceBundle bundle = ResourceBundle.getBundle("com.example.foo.sample");
Enumeration<String> e = bundle.getKeys();
while (e.hasMoreElements()) {
   String key = e.nextElement();
   def.put(key, bundle.getString(key));
}

Yet another alternative is to ensure the resource bundles are available to the startup classloader. You can do this by placing the JAR containing the resource bundles in the lib subdirectory of your platform cluster, although this workaround has not been tested.


Applies to: NetBeans 6.5

URIs and URLs

Q: What is the difference?

A: A URL is a kind of URI. URNs such as urn:oasis:foo are URIs but not URLs.

Q: Should I use java.net.URI or java.net.URL?

A: Whichever is more convenient. URLs must use a registered URL protocol and cannot handle URNs; there is slightly more overhead in making a URL than a URI, but not much. URI provides better methods for relativizing and canonicalizing URLs as well as other operations on the syntactic structure. To directly load content you need to use a URL. URI seems to have difficulty with the jar protocol.

Q: Can I interconvert URIs and URLs?

A: Yes, use uri.toURL() and URI.create(url.toExternalForm()).

Q: Can I interconvert Files and URIs?

A: Easily. Use file.toURI(). In the other direction, use new File(uri).

For URLs, go through URI. Never use file.toURL(); it does not handle unusual characters correctly.

Careful with file URLs/URIs denoting directories. NetBeans APIs generally expect these to end in a slash (/). However file.toURI() will not end in a slash if the file does not currently exist! Be sure to check if the URI ends in a slash and add one if not, if you in fact know that the File is intended to represent a directory.

Q: Can I interconvert FileObjects and URLs?

A: Use fileObject.getURL(), or URLMapper methods for more control over the kind of returned protocol; in the other direction, use URLMapper.findFileObject(url).

For URIs, go through URL.

Q: How do jar URLs work?

A: Unlike e.g. URLClassLoader, in the NetBeans APIs file:/tmp/foo.jar refers to the raw byte contents of foo.jar. To refer to the root entry of the JAR (e.g. for use as a classpath entry) you must use jar:file:/tmp/foo.jar!/. FileUtil has methods (getArchiveFile, getArchiveRoot, and isArchiveFile) to help you convert between these representations.

Q: Which URL protocols are used in NetBeans?

A: Several, including some custom protocols:

  • file - for representing files on disk.
  • jar - for representing entries inside JARs and ZIPs, including the root directory entry.
  • nbres - a resource loaded from a NetBeans module (or technically the cross-module class loader), e.g. nbres:/org/netbeans/modules/foo/resources/foo.dtd may load the same thing as jar:file:/opt/netbeans/ide4/modules/org-netbeans-modules-foo.jar!/org/netbeans/modules/foo/resources/foo.dtd.
  • nbresloc - same, but transparently localized and branded according to the usual conventions, e.g. nbresloc:/org/netbeans/modules/foo/resources/foo.html may actually load the same thing as nbres:/org/netbeans/modules/foo/resources/foonbja.html.
  • nbdocs - same as nbresloc but also searches in docs/ subfolders of installation directories, e.g. nbdocs:/org/netbeans/modules/usersguide/ide.css may work like file:/opt/netbeans/ide4/docs/org/netbeans/modules/usersguide/ide.css.
  • nbinst - loads installation files using InstalledFileLocator in installation directories, e.g. nbinst:///modules/ext/some-lib.jar may load the same thing as file:/opt/netbeans/ide4/modules/ext/some-lib.jar.
  • nbfs - refers to a file object. As of NetBeans 4.0 there are no user-mounted filesystems so this is only useful to refer to file objects in the system filesystem (XML layers). For example, nbfs:/SystemFileSystem/Templates/Other/html.html refers to an HTML file templates installed in the IDE.

Applies to: NetBeans 4.0, 4.1, 5.0, 5.5, 6.0, 6.1, 6.5, 6.7

What is the user directory, what is in it, and why do I need one?

The userdir is a directory passed to NetBeans on startup by the launch script. You can specify it on the command line, e.g.:

--userdir /tmp/some/folder/that/need/not/exist/yet

It contains configuration data that allows NetBeans to restore its state after shutdown; it also contains log files and other miscellaneous artifacts of running NetBeans. The config/ subfolder of the userdir is where changes made at runtime to the system filesystem (DevFaqSystemFilesystem) are written.

It is expected that applications built on the NetBeans platform will provide a custom launch script which will specify the userdir such that it does not overlap with any other platform-based application. This is done for you if you use the stock launchers created by "suite" projects in the IDE.

Only one running copy of NetBeans may use a single userdir at a time; during startup, the platform checks a lock file and if it is present, tries to contact the running instance via a socket, to determine if the lock file is stale or not. If it does not make contact, it will display a warning and ask the user if startup should continue. This same protocol also supports command-line options.

You can find the path to the userdir at runtime if you need to, using the system property netbeans.user. Most modules should not do this; use FileUtil.getConfigFile to work with the config/ subdirectory.


Applies to: NetBeans 6.7

How do I test a 6.5M2 or later platform-based application?

NOTE: This is a work in progress and will be expanded/improved as I experiment more with the new testing setup. Correctness is more important than being thorough.

Background

In versions of NetBeans prior to 6.5M2, comprehensive testing of platform-based applications was done using the XTest Framework. XTest added a number of build scripts, utilities and testing libraries plus some configuration to categorize and group tests together. The framework was originally developed for testing the IDE itself, and although using it to test other platform-based applications was possible, it was somewhat difficult to set up these tests.

During development of the 6.5 series, an effort was made to improve testing and XTest was replaced by inherent support for tests in NetBeans build scripts (also known as the build harness). Therefore, unit and functional tests for platform applications are now supported out of the box in NetBeans 6.5M2 and later. This effort is sometimes called "simpletests" because it greatly simplifies the work necessary to do such tests on your application. More information about simpletests can be found in the Wiki.

JUnit Version

While XTest supported only JUnit 3.x, NetBeans 6.5 now supports JUnit 4.x, via the JUnit 4 module in the platform9 cluster. If you're not familiar with the difference, this helpful article explains the changes from JUnit 3 and JUnit 4. Put simply, the main difference from a user's point of view is is one of syntax and style. The tests you've already written against 3.x will continue to run under 4.x. And although you could continue writing new tests using the 3.x syntax if you wanted, it's much easier to have NetBeans generate the test stubs for you (Tools -> Create JUnit Tests or Ctrl+Shift+U). Starting with NetBeans 6.5, any new tests will be generated using the JUnit 4.x style.

Converting Tests for Applications Which Previously Used XTest

Essentially, you need only remove the XTest build and configuration files from your modules and replace them with a few lines of code in your tests' suite() method. More information is available in the XTest Replacement Cookbook

Learn by example

Before: See PaintApplicationWithXTest.zip (Using XTest) works only with NB 6.5M1 and earlier and requires XTest After: See PaintApplicationWithSimpletests.zip (Ported to use simpletests); works only with NB 6.5M2

Code Coverage

See Code Coverage.

Setting up functional tests for a Platform Application

The testing libraries are included as modules in the build harness, so you will need to include the harness cluster in your application before you can support tests. This is easily done through the IDE:

  • Right click your suite's node in the project view
  • Choose "Properties"
  • Click "Libraries" on the left
  • Check the "harness" box and add the entire harness cluster.
  • Now click the platform n cluster (currently platform 10)
  • Check the boxes against the MultiView Windows and Visual Library API.

Now you must set up the structure under your module:

  • Go to the 'file' view, and expand your modules node
  • In the test folder, create a folder named 'qa-functional'. Underneate that, create the folder src.
  • Under the test dir you should now have two folders, unit and qa-functional. Under each of those should be an src folder.
  • Restart the IDE, there should now be two new Nodes in that Module’s Project Tab: Functional Test Packages and Functional Test Libraries
  • Right-click the Functional Test Libraries –> Add Functional Test Dependencies, then add jemmy, nbjunit, jellytools platform, jellytools and junit4

It should now be possible to run a class that extends JellyTestCase, and for the IDE to display this correctly.

TODO

  • Describe how to set up a new unit test from scratch
  • Describe how to set up a new functional test from scratch
  • Describe adding support for external testing libraries (e.g. FIT, TestNG or marathon)
  • Describe how to set up additional test types (e.g. performance)
  • Describe how to configure suite build.xml to remove harness from ZIP distribution
  • Describe how to run tests under automated build using Hudson

NOTES

MockLookup and other classes mentioned on the Useful Test Classes in Modules are not available in the platform.
  • You can add additional libraries needed for unit tests by setting the test.unit.cp.extra property (e.g. in the module's project.properties file) to point to those libraries. It does not matter where these libraries (JAR files) reside, and you can refer to them using a hardcoded path (BAD) or via a relative path -- even using $suite.dir as a starting point in case they're used by multiple modules in the suite. In the latter case, you can define the test.unit.cp.extra property in the suite's platform.properties (NOT project.properties) file. Be aware that this may limit your ability to define additional things at the individual module level, so it might be better to define a standard suite-wide property like standard.unit.test.libs to point to things used throughout the suite, then have individual modules define test.unit.cp.extra to include this plus potentially some other things. Items defined in the test.unit.cp.extra property are used at both compile time and runtime, it seems.
  • I'd guess that the test.unit.functional.extra (or maybe test.unit.qa-functional.extra) property works the same way for functional tests, but I have not tried it. It did work under XTest though.
  • There is a property extra.test.libs.dir tersely described in the harness README that makes it sound like a great way to define a place for extra testing libraries that will be picked up automatically during tests, but I could not get it to work. Or at least things in that directory were not found at compile time.

Can I add submenus to context or main menus, instead of single menu items?

Yes, any place where the APIs expect to have an item installed into a context or main menu, you can provide a submenu instead.

Provide a dummy Action (it can be a do-nothing subclass of javax.swing.AbstractAction), or in some cases the class need not even be an Action at all. For context menus, implement the interface Presenter.Popup on your Action, and have it return a JMenu from getPopupPresenter().

Similarly, you can implement other subinterfaces of Presenter to provide a different component to display in toolbars or the main menu.

Note about using alternate components in the main menu: If you want your action to work properly on Mac OS, you probably don't want to return anything other than a JMenu or JMenuItem from getMenuPresenter() if you implement Presenter.Menu. In general, Swing allows you to treat menu popups as generic Swing containers you can put what you like into. This is not true at all of the Mac OS screen menu bar - it expects normal menu items, and will not handle unusual contents for menus.

If you just return a JMenu from getPopupPresenter or getMenuPresenter it will always be displayed, though you can conditionally disable it. If you wish to sometimes hide (not just disable) the submenu, make it implement DynamicMenuContent and you can make the submenu appear or disappear whenever you like (or even provide more than one menu item / submenu).

How do I set the version number?

There are two ways to set the version number shown in the Help... About dialog.

  • The easy way is to set the system property netbeans.buildnumber to some value in your application.
  • The harder way is to put this key/value currentVersion=My Product 1.2.3 into the file named "branding/modules/org-netbeans-core.jar/org/netbeans/core/ui/Bundle.properties" below your suite, then rebuild and run.
  • In NB 6.5 is other file location: "branding/core/core.jar/org/netbeans/core/startup/Bundle.properties"

Saving Column Attributes of a TreeTableView

Assuming you are embedding a TreeTableView (TTV) inside a TopComponent, you can override the readExternal(ObjectInput) and writeExternal(ObjectOutput) methods for preserving the attributes of the columns in your TTV (e.g. the column ordering, sorted-ness, sorting order, visibility, and width).

Start by keeping a reference to the Node.Property array used to define the columns of the TTV, since there is no way to get those properties from the TTV (i.e. there is no getProperties() method). The examples below will refer to this Node.Property array as "columns".

In order to get and set the column widths of the tree-table, we need to subclass TreeTableView and provide a getTable() method that returns the treeTable protected field of the TreeTableView class. In the examples below, this reference will be referred to as treeTable for brevity.

First let us save the column attributes to the serialized TopComponent via the writeExternal() method.

    public void writeExternal(ObjectOutput out) throws IOException {
        super.writeExternal(out);
        out.writeInt(columns.length);
        for (int ii = 0; ii < columns.length; ii++) {
            Boolean b = (Boolean) columns[ii].getValue("InvisibleInTreeTableView");
            if (b == null) {
                b = Boolean.FALSE;
            }
            out.writeBoolean(b.booleanValue());
            Integer i = (Integer) columns[ii].getValue("OrderNumberTTV");
            if (i == null) {
                i = new Integer(ii);
            }
            out.writeInt(i.intValue());
            b = (Boolean) columns[ii].getValue("SortingColumnTTV");
            if (b == null) {
                b = Boolean.FALSE;
            }
            out.writeBoolean(b.booleanValue());
            b = (Boolean) columns[ii].getValue("DescendingOrderTTV");
            if (b == null) {
                b = Boolean.FALSE;
            }
            out.writeBoolean(b.booleanValue());
        }
        try {
            TableColumnModel tcm = treeTable.getColumnModel();
            int count = tcm.getColumnCount();
            for (int index = 0; index < count; index++) {
                TableColumn tc = tcm.getColumn(index);
                out.writeInt(tc.getWidth());
            }
        } catch (IOException ioe) {
            ErrorManager.getDefault().notify(ErrorManager.WARNING, ioe);
        }
    }

Next, we see how to deserialize the column attributes.

    public void readExternal(ObjectInput in)
            throws IOException, ClassNotFoundException {
        super.readExternal(in);
        try {
            int count = in.readInt();
            for (int ii = 0; ii < count; ii++) {
                boolean b = in.readBoolean();
                columns[ii].setValue("InvisibleInTreeTableView", Boolean.valueOf(b));
                int i = in.readInt();
                columns[ii].setValue("OrderNumberTTV", Integer.valueOf(i));
                b = in.readBoolean();
                columns[ii].setValue("SortingColumnTTV", Boolean.valueOf(b));
                b = in.readBoolean();
                columns[ii].setValue("DescendingOrderTTV", Boolean.valueOf(b));
            }
        } catch (Exception e) {
            // Could be reading an old instance which is missing data.
            // In any case, ignore this as there is no use in reporting it.
        }
        nodeView.setProperties(columns);

        // Read the column widths from the stream immediately and save them
        // to a final array for the Runnable below to access them.
        TableColumnModel tcm = treeTable.getColumnModel();
        int count = tcm.getColumnCount();
        final int[] widths = new int[count];
        try {
            for (int index = 0; index < count; index++) {
                widths[index] = in.readInt();
            }
        } catch (IOException ioe) {
            // Could be reading an old instance which is missing data.
            // In any case, ignore this as there is no use in reporting it
            // (and return immediately so as not to invoke the runnable).
            return;
        }

        // Changing Swing widgets must be done on the AWT event thread.
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                // TreeTableView prohibits moving the tree
                // column, so it is always offset zero.
                setTreePreferredWidth(widths[0]);
                for (int index = 1; index < widths.length; index++) {
                    setTableColumnPreferredWidth(index - 1, widths[index]);
                }
            }
        });
    }

What is a Node?

Nodes are presentation objects. They have actions, properties and localized display names - they are the place where the architecture meets the human. Nodes typically wrap some model object and provide human-readable names, icons, etc. They are at the heart of a lot of NetBeans selection and user interface systems.

Nodes are a generic tree structure. A common use for them is to display DataObject s to the user - to represent the user's files visually. Each node has a Children object that can supply a list of child nodes. Nodes are not visual components, and they do not subclass TreeNode from the JDK - they are more related to the JavaBeans specification, subclassing java.beans.FeatureDescriptor.

Nodes are displayed in explorer views. The Explorer API provides a number of Swing components which take a Node and can display that node and its children - in trees, lists, tree tables, etc. The property sheet is also an Explorer view - Nodes have properties, which are key-value pairs with localized names.

Generally Nodes should represent not be the objects the user is interacting with - if you are putting huge amounts of logic in your Node class, you're probably doing something wrong.

Nodes form the basis of global selection in NetBeans - each component in a tab in the ui has an "activated Node". The system globally tracks what component has focus, and each component typically offers some node as the currently selected node (which can change when the user clicks, etc.).

A Node has a Lookup which you can ask for objects your code is actually interested in. You never get the selected node and then cast it to some specific Node subclass and do things to that; the real model objects should be available from the Node's Lookup. This helps to future-proof your code - you can have another module provide the same objects your client code is interested in from its Node's lookup, and the client code never has to change - it's just looking for any Node that has what it needs.

Read about how to implement your own Nodes

What is an NBM?

An NBM file is a NetBeans module packaged for delivery via the web. The principal differences between it and a module JAR are:

  • It is compressed
  • It can contain more than one JAR file - modules can package any libraries or other files they use into their NBM
  • It contains metadata NetBeans will use to display information about it in the update center, such as the manifest contents, the license, etc.
  • NBMs may be signed for security purposes

NBM files are just ZIP files with a special extension, which use the JDK's mechanism for signing JARs. Unless you're doing something unusual, you will not need to worry about the contents of NBMs - just let the standard Ant task for NBM creation take care of it for you. For those interested in gory details, read on.

Structure of an NBM

Below is an example of the contents of one - this is from the hexedit_integration module in contrib, which packages up an external library as well:
Info/info.xml
Metadata - this file is generated by the standard NBM build target, so if you use NetBeans support for creating modules, you should not need to do anything special to create it. This info is used by the IDE to figure out if a module the user is installing is newer or older, than an existing one, whether or not its dependencies can be satisfied, etc.
META-INF/MANIFEST.MF
The manifest - usually nothing of interest here, it is just generated because NBMs are created the same way that JARs are. May point to a signature for the NBM.
netbeans/....
Contents to be unpacked to some cluster in the NetBeans installation (or the user directory).
netbeans/config/Modules/org-netbeans-modules-hexeditor.xml
The module XML file used at runtime to discover modules. Indicates whether the module is autoload, etc.
netbeans/modules/org-netbeans-modules-hexeditor.jar
The actual module JAR.
netbeans/modules/ext/hexedit.jar
A library this module uses and includes.

Runtime module XML metadata

The org-netbeans-modules-hexeditor.xml runtime metadata file looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//NetBeans//DTD Module Status 1.0//EN"
                        "http://www.netbeans.org/dtds/module-status-1_0.dtd">
<module name="org.netbeans.modules.hexeditor">
    <param name="autoload">false</param>
    <param name="eager">false</param>
    <param name="enabled">true</param>
    <param name="jar">modules/org-netbeans-modules-hexeditor.jar</param>
    <param name="release">1</param>
    <param name="reloadable">false</param>
    <param name="specversion">1.0</param>
</module>

Module installation metadata - Info.xml

The Info/Info.xml file that NetBeans uses to figure out if it can install a module, dependencies, etc. looks like this (it also contains the license that the user will agree to to install the module from the update center):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//NetBeans//DTD Autoupdate Module Info 2.3//EN"
                        "http://www.netbeans.org/dtds/autoupdate-info-2_3.dtd">
<module codenamebase="org.netbeans.modules.hexeditor"
        homepage="http://contrib.netbeans.org/"
        distribution="http://...../org-netbeans-modules-hexeditor.nbm"
        license="standard-nbm-license.txt"
        downloadsize="0"
        needsrestart="false"
        moduleauthor=""
        releasedate="2005/08/29"
>
  <manifest OpenIDE-Module="org.netbeans.modules.hexeditor/1"
            OpenIDE-Module-Display-Category="Infrastructure"
            OpenIDE-Module-Implementation-Version="050829"
            OpenIDE-Module-Long-Description="Sample module hexeditor providing HexEdit"
            OpenIDE-Module-Module-Dependencies="org.openide.filesystems > 6.2, ..."
            OpenIDE-Module-Name="hexeditor"
            OpenIDE-Module-Requires="org.openide.modules.ModuleFormat1"
            OpenIDE-Module-Short-Description="Sample hexeditor module"
            OpenIDE-Module-Specification-Version="1.0"
  />
  <license name="standard-nbm-license.txt"><![CDATA[
                Sun Public License Notice
....
]]></license>
</module>

Applies to: NetBeans 6.5 and above

When do I use what registration method?

As described in DevFaqModulesGeneral, there are several different declarative registration mechanisms:

  • @ServiceProvider (creates entries in META-INF/services in the module JAR)
  • adding files to folders in the System Filesystem (DevFaqSystemFilesystem)
  • running some code on startup by implementing ModuleInstall and referring to it in your manifest

If you are implementing some API from another module, that module should tell you what to do. If it tells you something should be in the default lookup (DevFaqLookupDefault), that means to use @ServiceProvider.

If you are defining an API in your module, and other modules will implement it and provide their own classes (think of the Navigator component in the IDE - different modules register handlers that can display navigation tools for various file types), if you can possibly avoid it, you don't want modules to do anything programmatic (DevFaqModulesDeclarativeVsProgrammatic), since that doesn't scale. So we're left with services or the system filesystem. Here are the questions to ask yourself:

Q: Is this just a simple interface or abstract class people should implement, and I just have to find them all and use them?

A: If so, use @ServiceProvider.

Q: Will all of the objects other modules will register be used at the same time, or are there subsets for specific contexts?

A: This pertains to performance and scalability - wherever possible, you want to avoid actually instantiating the objects other modules install, and delay instantiating them until they really need to be used. Class loading slows things down.

If there will potentially be a large number of subclasses of your interface, try to find a way to divide them into context-appropriate categories and use folders in the system filesystem to partition contexts. For example, if you define the interface Eater, and modules will implement eaters of various foods, you probably should create folders for different general kinds of food. That way, you don't have to load a bunch of classes and create the OliveEater, BreadEater, EggEater and SausageEater just to ask them if they can eat the Pizza you came across.

You can use Lookups.forPath to quickly retrieve Eater objects from a certain folder only. Starting with NetBeans 6.7, you should define an annotation for SPI users to register your object: DeclarativeRegistrationUsingAnnotations

Q: Is there information needed about how each object is to be used which could be provided declaratively, without instantiating the object?

A: If so, use the system filesystem, and either let modules declare file attributes that provide additional information, or let modules put their objects in subfolders that have contextual meaning (the same way the folder Loaders/text/x-java uses the folder path to indicate the data type objects pertain to).

Q: How many modules will actually implement my interface? How many objects from other modules will I typically be dealing with? Do I need to instantiate all of them just to display a list in the UI?

A: Displaying things in the UI is a particularly important case: you do not want to have to load a bunch of classes from a module just to show an icon and a display name for something. This pertains to anything you're going to display in the Options dialog, on Menus, or various other views.

You can solve this by using *.instance files (DevFaqInstanceDataObject) and asking that modules implementing your API use the file attributes (DevFaqFileAttributes) defined for .instance files to declare the icon and display name. (Normally annotations should be used to make this easier for the developer.) Then your code can just get a FileObject (DevFaqFileObject) for each registered instance, call DataObject.find(theFileObject).getNodeDelegate().getIcon() or getDisplayName() to get the icon or display name of the object without ever having to create the object until it needs to do real work.


Applies to: NetBeans 6.7

When should I use a library wrapper module and when should I just package the library into my module?

The New Module Wizard offers easy support for creating a wrapper module: File > New Project > NetBeans Modules > Library Wrapper Module. This biases the answer to this question, due to its convenience, but generally there's no harm in using a library wrapper module.

Note that a library wrapper module can wrap more than one external JAR - you do not need to create one for each library. But it is a good idea to create a separate wrapper for each JAR if they come from different projects and might conceivably be used independently.

The general algorithm for making an optimal decision about when to use a wrapper module is this:

There is a very slight performance penalty to using a wrapper module - it's one more JAR to open and read from, and one extra layer of indirection for the classloader. That is not a reason to avoid using a wrapper module if that's what you need - it really is slight. In a very large application such as the NetBeans IDE, such considerations are more important because there are more JARs, more classloaders, and hence more overhead already.

If you are developing the library yourself, but decide you want to keep the library project separate from any NB module project, you can do so. See Using a wrapper module for an existing project for information and various methods to hook them up for development.


Applies to: NetBeans 6.5

Windows & dialogs

Can I just open up my own frames and dialogs?

  • Yes, you could; but please instead use the standard
windowing system to do these sorts of things. Then you will properly handle docking, separated floating windows, context help, various keyboard shortcuts, and many other things contributing to the IDE's appearance and functionality.
  • The Window System API describes the general steps you should use to open up new function
windows, if you need such a thing. Specifically, you should use TopComponent s for such purposes.
  • You can also use DialogDisplayer.notify(NotifyDescriptor) to show dialogs that interact well with the IDE's window system,
and have a number of bits of prebuilt UI. You can use various standard subclasses of NotifyDescriptor to represent simple messages; exceptions; general-purpose dialogs with content panels; or even multi-stage wizards.

What are the steps to create a simple Wizard?

Easiest way is to use File -> New File wizard, Module Development category and Wizard item, which will generate all needed boilerplate code for you. Essentially what wizard does is described below:

Create Panels:

You should start with creating a set (at least one) on WizardDescriptor.Panel objects (see
Wizard Panel Performance Guide for more information about the best way to create a panel).

Create WizardDescriptor

Use the panels to tell the a WizardDescriptor instance the sequence of panels it should display. This you can do either directly by WizardDescriptor wd = WizardDescriptor(wizardPanelArray) Or you can create a WizardDescriptor.Iterator with these panels, which gives you more control over the sequencing.

Set Properties

Set certain properties on the WizardDescriptor which can influence the appearence of the wizard. If you like to add a help pane for example you call: wd.putProperty("WizardPanel_autoWizardStyle",Boolean.TRUE); wd.putProperty("WizardPanel_helpDisplayed",Boolean.TRUE);

This will display a help html file which has to be defined on each panel by setting a clientProperty in the JComponent superclass of the panel that is the wizard content. In this case it would look like:

putClientProperty("WizardPanel_helpURL",new URL("http://path/to/help/html/file/panelHelp.html"));

Show Wizard

Finally you set the Wizard to screen using the DialogDisplayer
Dialog d = DialogDisplayer.getDefault().createDialog(wd);

        d.setVisible(true);

        d.toFront();

I want to show my own component(s) in the main window - where do I start?

Use File -> New File wizard, Module Development category and Window Component item. It will generate all necessary background code for you and open GUI Builder to design UI of your own component.

But what is behind the scenes, created by wizard?

public class MyAction extends AbstractAction {
   public MyAction() {
      putValue (Action.NAME, "Open My Component");
   }

   public void actionPerformed(ActionEvent ae) {
      new MyComponent().open();
   }
}
  • Declarative XML descriptions of component are created following declarative XML API principles.

TopComponents are part of the Windows API.

What is the Window System?

The windowing system is what creates the main application window, and makes it possible to open components in the UI. The API for the windowing system is in the package org.openide.windows. The implementation of the windowing system is in the module org.netbeans.core.windows (core.windows in Mercurial repository, was core/windows in CVS).

The window system defines Modes which are places in the main window occupied by tabbed containers. TopComponents are GUI components (instances or subclasses of org.openide.windows.TopComponent which can be put into these tabbed containers.

There is a programmatic API for creating/opening TopComponents - this is useful for testing components under development - just create an Action which calls new MyTopComponent().open() to quickly try out GUI components.

However, the main API modules use to install their components is the declarative XML Window System API, for the following reasons:

  • Scalability: Components do not need to be created/deserialized unless they really need to be opened
  • Singletonization: You wouldn't want to have 5 Projects tabs in the IDE. Using the XML API correctly, you can easily refer to the singleton instance of your component once it's instantiated (almost) for free.
  • Persistence: The window system associates components with unique IDs; to properly persist your component across sessions, you need to use the XML APIs

NetBeans Window System - what happens during startup

Below is a blow-by-blow account of what actually goes on during NetBeans startup, put together by, well, reading the code. It's here as much for the author's edification (if you read through it and document it, you understand it) as yours.

The three and a half models model

The NetBeans window system is extremely defensively coded - one of the main goals of rewriting it for 3.6 was robustness in the face of components that throw exceptions, do evil things to other components, and so forth. The way the robustness of the current system is achieved is by very cleanly separating the model of how the UI should be, the model of how the UI actually is and the AWT component hierarchy, which is a model of sorts itself, but cannot be relied upon, because in an extensible application any component may do something evil. On top of this is the persistence model.

UIs are hierarchical, with components inside containers inside other containers - so each model we'll describe is hierarchical to represent this. TopComponents (panels in tabbed container) get a little special handling because there's a potential one-to-many relationship between TC's and tabbed containers (an implication of winsys v1, where one component could live in more than one docking Mode (tabbed container) per workspace).

So, the models (names made up for the purpose of this document):

  • The Persistent Model - org.netbeans.core.windows.persistence - these classes are really record types - classes with public fields that contain data read out of persisted XML describing the window system and written back to it. These classes are instantiated at de-persistence and persistence time, and read and written, but are not used at runtime - they just provide the stored state of the system, and are used to construct the initial model of the window system at runtim
  • The Runtime State Model - this is the model of how the window system and all its components are *supposed* to be, based on persisted state and any changes made by calling methods (i.e. the user maximizes or closes a component) at runtime
  • The Runtime View Model - this is another set of model objects - org.netbeans.core.windows.view , each of which represents (and can manipulate) a UI component. Each model object has a corresponding Accessor object which isa layer of indirection that connects it to the actual Component it models.
  • Snapshots (this is the 1/2 model) - a snapshot is an object that immutably captures the state of the Runtime State Model at a particular moment in time. When a change has happened, a request to update the UI is enqueued. When that request runs, it synchronizes the UI model with the state described in the snapshot (what's open, what's closed, what's maximized, splitter positions, etc...)

Reading the source to the window system can be a little complicated, because there are multiple models of the same thing all being synchronized, and just about everything follows a chain of single-method-call methods back to Central or WindowManagerImpl. Hence this document.

In its essence, though it's simple: all changes in the window system simply mean synchronizing the two runtime models. It's only the number of classes that requires that make it look complex.

The Window System Startup Sequence

Loading the window system is a distinct phase in NetBeans startup. A set of model objects representing the window manager (data like SDI vs. MDI, frame size/location/state), its Modes (docking containers - bounds, contents), and references to TopComponents by ID (not the components themselves, but unique String ids for them).

Once all this is done, we'll have a set of model objects representing all the persisted data. Note that these model objects are not the ones used by the model of the window system at runtime, there are different classes for that.

Here's the load sequence:

WindowSystemImpl

  • copy all TopComponent settings files aggressively to the userdir (BUG? Probably needed this for the 3.5 project system, probably don't now)
  • checks its on the dispatch thread, and calls PersistenceHandler.getDefault().load()
  • that calls PersistenceManager.getDefault().loadWindowSystem()
    • that gets an XML parser
    • the parser creates a WindowManagerConfig from data it finds in XML files. A WindowManagerConfig just has a lot of public fields from parsed data, that refers to other similar objects
      • ModeConfig - information about a docking container, placement, contents
      • TcRefConfig - references to a TopComponent by ID, no component there yet
      • GroupConfig - Refers to a Group of TopComponents (like form editor + its palettes)
      • TcGroupConfig - Reference to a TopComponent by a GroupConfig
      • InternalConfig - Just notes what version of the window system saved the date we loaded

Now we're back out in PersistenceManager. We:

  • Build a set of TopComponent ID's in use (if a new component opens and it wants the same ID as an existing one, we append an integer to the ID string)
  • Start listening on the folder for changes (i.e. a new module is installed and it has a persisted component that should be opened)
  • Clear the reference to the parser
  • Return the WindowManagerConfig to PersistenceHandler

Now we have a model for the contents of the window system as it was persisted...

Back in PersistenceHandler.load() now, we build the runtime model of the window system (note that except for deserializing TopComponents, we're not creating any components yet, we're just creating model objects that will be represented by GUI components in the UI):

  • Misc: get the large/small preferred toolbar icon size and store that on the WindowManagerImpl
  • Get the list of TopComponent ids found in deserializing the window system
  • Iterate the IDs
    • for each, deserialize the TopComponent in question
  • Set the "recent view list" on the WindowManager with the array of deserialized TopComponents. This is used for ordering the components visited when the user Ctrl-Tabs between TopComponents
  • Iterate all of the ModeConfigs
    • for each, create a ModeImpl (note this is a model object, not a tabbed container)
    • if the mode was active at shutdown last time, remember that fact in a local variable
    • if the mode was persisted as maximized, remember that fact in a local variable
  • Iterate all of the ModeImpls created
    • initialize each one from the ModeConfig it was created for
    • iterate all TcRefConfigs in the ModeConfig, extract some persisted data about the "previous mode" the TopComponent was in, and pass that data to the window system - this is so that sliding windows know where they should land if the user presses the "pin" button to put them in a tabbed container
  • set the id of the selected TopComponent on the ModeImpl
  • Iterate all the GroupConfigs loaded
  • For each group, create a TcGroup object
  • Add a mapping from GroupConfig.name to the tcGroup to a map held by PersistenceHandler (BUG? Why should this data be kept here? Nothing else keeps data *in* PersistenceManager - it means it can't be collected - or I'm not seeing/understanding how it's used)
  • Iterate all the TcGroupConfigs (BUG: bad name - these are wrappers for TopComponent IDs)
    • For each TcGroupConfig (PersistenceHanponent reference), add the ID into the list of IDs in the TcGroup
    • Check the boolean open flag for the TcGroupConfig. If true, it's a component that, when opened, should open the entire group
    • Check the boolean flag whether the TopComponent was closed explicitly by the user. If true, when the group of components are all opened, leave that one closed
    • Check the boolean flag whether the TopComponent was reopened explicitly by the user, and if so, ignore the result of the closed flag - add it to the list of ids that should open
  • Add the TcGroup we created to the list held by the window manager

Note the group handling code is a little different than the rest in terms of the way it's modelled - this should probably be corrected - it appears that for some reason, PersistenceHandler holds the data for that, there is no corresponding model object for TC's in a group (not necessarily bad, but inconsistent), and the data is passed to the window manager before its initialized (harmless, but odd). On the other hand, it's less complicated.

We're not done yet.

  • Next is a hotfix for issues 37188 and 40237 (which like all good hotfixes, was never replaced by a proper fix) - this calls componentShowing() on the component before it's even in the AWT hierarchy
  • Set the active (focused) Mode in the window manager from the field we saved earlier (BUG: this code seems to run earlier than it should, and the comment refers to the NetBeans 3.x project system, which persisted the entire window system out and loaded a new one in
  • Set the maximized mode, if any, in the window manager from the field we saved earlier
  • Compute the main window sizes for MDI and SDI mode, based on persisted data and current screen size, and set it on the window manager
  • Compute the editor area bounds and set it on the window manager
  • Set the id of the toolbar configuration that's active, based on persisted data

We now have a singleton instance of WindowManagerImpl, with its model fully initialized from persisted data (or a semi-sane default if de-persisting failed). It will be available from WindowManager.getDefault();

Showing/creating the UI

The next phase happens when setVisible(true) is called on the window system. A thing to know here if you read the code is that all requests to do anything in the window system are funneled through one class called Central (yes, Central is the God Object anti-pattern). So pretty much any method that you look at in the model objects will call back through a method in Central, sometimes to itself, sometimes to some other object.

So...

  • WindowManager.show():
    • asserts we're on the EDT
    • installs the global KeyEventDispatcher on Swing's KeyboardFocusManager to handle action bindings
    • calls WindowManagerImpl.getInstance().setVisible(true) - that in turn checks that its a state change and calls
      • Central.setVisible(true) which calls DefaultModel.setVisible(true) (this just stores the boolean value in a field)
      • calls ViewRequestor.scheduleRequest() - enqueues a runnable that will set the window system's visibility property to true, which
        • has a special check if it's a visibility change request, and if so tries to run it immediately if on the EDT (semi-BUG: it will always be the EDT, unless the assertion is turned off)

Now we're into the runtime behavior of the window system - this system of enqueuing requests is how code that will change window system state operates: A change is made to the model of the expected state of the window system, and the requested change is encoded in an object that will be processed in a subsequent event on the EQ. ViewRequestor keeps a list of all pending changes, and coalesces changes to the same value. When the request is processed, the state of the UI (open components, positions, splitter positions, everything) as described by the model is composed into a "snapshot", which is then used to set the necessary parameters on the UI components.

But right now, we're still just showing the window system, period. Here's what happens:

  • ViewRequestor.processRequest() gets called when the request runs. It gets the array of all pending requests and clears the queue
  • It iterates the ViewRequests that are enqueued
    • For each, create a ViewEvent and add it to a list of events to be processed
    • and passes that to ViewRequestor.dispatchRequest, which
      • passes them to DefaultView.changeGUI(). View is an interface representing the UI state of the entire window system. It's another set of model objects, this time modelling the state of the component. For each model object (ViewElement, ModeContainer, ModeView are interfaces the winsys implements elsewhere...), there is also an "accessor" object, which is what actually talks to the UI component.

DefaultView.changeGUI is what will actually modify the UI. A ViewEvent is pretty much like a PropertyChangeEvent, with an old value and a new value, but with an integer type instead of a property name. What it does:

  • Diff the last known showing set of TopComponents and find any newly shown TC's and call componentShowing() on them
  • Iterate all the ViewEvents and see if any one is a visibility change for the entire window system (BUG? There is already special handling to dispatch such requests ahead of the queue - this seems to duplicate the work). (BUG: Interestingly, this is the real source of the componentShowing() called twice bug that has the hotfix mentioned above - if the order of operations is switched here, that hack can be deleted. Note if the request is a visibility change request, method returns after calling WindowSystemVisibilityChanged()).
  • Iterate all the ViewEvents passed:
    • for each, check the type, and for each type, cast the new value and old value to the proper types, and
      • call a setter on the UI-view-model object that in turn should call something on the actual UI component

But we're getting ahead of ourselves here - as you may have noticed above, if it's a window system visibility request, we actually exit before we've gotten to iterating all the ViewEvents the second time, to change component state and so forth.

I should mention ViewHierarchy here - it's not a very exciting class, but it's the root model for the UI model objects, so when you have one of those Accessor objects for a Mode or a component in a mode, it's where you get the corresponding model object whose setters will actually call the real UI component.

So let's go back to where we call windowSystemVisibilityChanged(). What that does:

  • First, we call hierarchy.getMainWindow() (now we're actually touching GUI - the main window is a JFrame subclass, MainWindow - so this is the first time we're really creating components, except for the TopComponents we deserialized. What that does:
    • set the icon
    • add a WindowListener that will call LifecycleManager.exit() on WindowClosing, and close menus if the window is deactivated
    • set the menu bar (this calls a whole bunch of code that generates the menu from folders of actions in the system filesystem - we won't cover it here)
    • install the toolbar panel
    • Install the statusbar (and check the special constant for putting it in the menubar for screen real estate freaks)
    • Install a JPanel at BorderLayout.CENTER, called desktopPanel, which our window system will live in in MDI mode
    • Install a hack listener on MenuSelectionManager to focus the main window if a menu is activated - this is SDI mode specific - you can invoke a menu by mnemonic but then the keyboard doesn't work unless you send focus to the main window - see issue #38810

Now we're back out in DefaultView.windowSystemVisibilityChanged(). What we do now:

  • Set the toolbar configuration - this should actually cause the toolbars to be instantiated (there can be multiple toolbar configurations - it's how the debugger changes the set of visible toolbars when you start it)
  • Next, we go back to MainWindow by calling hierarchy.getMainWindow().prepareWindow(). What that does:
    • Calls back to WindowManagerImpl and gets the main window bounds (different calls for MDI and SDI). We stored this value there when we loaded the window system data, from WindowManagerConfig
    • If not empty, set those bounds on the main window
  • (BUG: there's a bunch of weird consecutive log statements here that should be deleted)
  • Next we call hierarchy.setSplitModesVisible(), which gets the root split pane of the split desktop layout, and recursively calls setVisible(true) on it and all its tabbed containers and TopComponents
  • Next we get the bitmask frame state we should have and call Frame.setExtendedState() with it on the main window
  • Now we set the maximized Mode, if any, that we stored when de-persisting
  • Then we call hierarchy.updateDesktop(). This takes the root split pane and adds it to the "desktop" JPanel inside the main window
  • Now we run some code to show all the frames for SDI mode windows, if any
  • Next we set up the editor area, using a dummy panel in TDI mode if there are no open editors
  • Update frame states for SDI windows, if any (BUG?: shouldn't we do this before calling show() on them all? Harmless since show() is asynchronous, but I'm not sure all AWT impls have to make it asynch) MKLEINT: On some (maybe all) platforms setting of frames states before it's shown has no effect. In other words, you cannot open an initially maximized frame. You need to show it and maximize then.
  • Set the main window title - using WindowSystemAccessor.getProjectName()
  • If the main window is maximized, run a hack that fakes the user resizing the window to its current size, passing that into the model (which will generate a synchronization ViewRequest and update splitters, etc. to proportional relative sizes)
  • Get the activated mode, and tell it it's activated (meaning focus should be sent to the TopComponent that should have focus, and componentActivated() will be called, etc.
  • InvokeLater adding listeners to the main window for resize and mode changes (invokeLater it so that when the frame state changes that we called to initialize the frame state on startup don't get processed as the user resizing the window and cause a storm of window system updates just because frame state changes in AWT are processed asynchronously - so we want to start listening only after things have settled down - see issues 39238 and37369 (the fix for 37369 caused 39238)
MKLEINT: again this is a hacky workaround to the fact that one cannot prepare a maximized version of the frame before it's shown.

At this point we've got our main window up and ready to go.

Obvious questions for those unfamiliar with the winsys:

Q: So where do all the tabbed containers and split panes come from? You didn't mention those.

A: The actual implementations of ViewElement (things that own ViewEvents), like org.netbeans.core.windows.view.ModeView actually create the UI components they talk to in their constructors

Q: Why are TopComponents treated so differently and what's this reference stuff in the de-persisting process?

A: In the pre-3.5 window system, a component could be open in more than one tabbed container at the same time. What??? It is because of workspaces, which we got rid of. A workspace was a switchable window system configuration or set of windows. The interface is still there, but there is only ever one workspace in the post 3.5 winsys. So any given Mode, for legacy reasons, is not sole owner of a TopComponent, it just has a handle for one.

How do I use Matisse/GroupLayout (new form editor/layout manager in 5.0) in my window system components?

When you create a new window system component (TopComponent) using the template wizard in NB 5.0 or greater, the default layout manager is GroupLayout (the new, super-easy-to-design-with layout manager in NB 5.0). So you do not need to do anything special. Your module will have a declared dependency on the corresponding library module which is in the NB Platform as of 5.0.

GroupLayout is included in JDK 6; as long as JDK 5 needs to be supported (until JDK 8 is released at a minimum), NetBeans will use the library version rather than the JDK 6 version.


Applies to: NetBeans 5.0, 5.5, 6.x

I want to disable the popup menu on the toolbars in the main window. How do I do that?

There is no canonical (or pretty) way to do this, but there is a hack you can do - it works in NetBeans 5.0, 5.5 and 6.x (and probably earlier versions but this wasn't tested).

Create the following ModuleInstall class (remember to add a reference to it in the module manifest, e.g.

OpenIDE-Module-Install: org/netbeans/modules/toolbarthing/Installer.class

If you are using 5.0's update 1 of module development support or later, you can just use New File > NetBeans Plug-In Modules > Module Installer):

package org.netbeans.modules.toolbarthing;
import java.awt.Component;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JToolBar;
import org.openide.modules.ModuleInstall;
import org.openide.windows.WindowManager;
public class Installer extends ModuleInstall implements Runnable {

    public void restored() {
         WindowManager.getDefault().invokeWhenUIReady(this);
    }

    public void run() {
        JToolBar[] tb = findToolbars();
        for (int i = 0; i < tb.length; i++) {
            processToolbar (tb[i]);
        }
    }

    private JToolBar[] findToolbars() {
        List l = new ArrayList();
        JFrame jf = (JFrame) WindowManager.getDefault().getMainWindow();
        findToolbars (jf.getContentPane(), l);
        JToolBar[] tb = (JToolBar[]) l.toArray(new JToolBar[l.size()]);
        return tb;
    }

    private void findToolbars(Component c, List l) {
        if (c instanceof JToolBar) {
            l.add(c);
        } else if (c instanceof Container) {
            Component[] cc = ((Container) c).getComponents();
            for (int i=0; i < cc.length; i++) {
                findToolbars(cc[i], l);
            }
        }
    }

    private void processToolbar (JToolBar bar) {
        MouseListener[] ml = bar.getMouseListeners();
        for (int i = 0; i < ml.length; i++) {
            if (ml[i].getClass().getName().indexOf("PopupListener") >= 0) {
                bar.removeMouseListener (ml[i]);
            }
        }
    }
}

My TopComponent always opens in the editor area, but I want it to open in the same place as XYZ?

By default, TopComponent.open() opens all components in the central editor area of the main window. Overriding this is simple:

public MyTopComponent extends TopComponent {
  public void open() {
     Mode m = WindowManager.getDefault().findMode ("output");
     if (m != null) {
        m.dockInto(this);
     }
     super.open();
  }
}

You need to know the ID of the Mode you want to put the component in. Common IDs are "output" for the bottom of the screen, and "explorer" for the left side. For other Modes, you may need to find a module that puts something there and read its layer files, or browse the System Filesystem.

Eventually you will probably want to specify what mode to dock your component into using the XML API for installing components, but the above technique works for simple modules, testing, etc.

What is a TopComponent in the Window System?

org.openide.windows.TopComponent is a JComponent subclass which knows how to work with the NetBeans window system. If you want to add components to the main window, typically you will subclass TopComponent, using it the same way you would a JPanel.

TopComponents live inside Modes - docking containers.

TopComponents can have various states:

  • open/closed - When a TopComponent is open, a tab exists somewhere in the main window or UI for it
  • visible/invisible - When a TopComponent is visible, it is the selected tab in its Mode
  • active/inactive - When a TopComponent is active, it or a child component of it has keyboard focus, and it is currently the global selection context

Each TopComponent has a Lookup and one or more activated Nodes. These define the selection context for the window system, which determines what actions (menu items, toolbar buttons, etc.) are enabled, and in some cases, what they will do or operate on if invoked.

TopComponents are part of the Windows API.

TopComponents that were already open may be deserialized and reopened on restart. The template that NetBeans 5.0 provides includes code for this - it is actually using saved using the Externalizable interface. Whether or not it is saved is determined by what you return from getPersistenceType().

For information on how and when these are reconstructed on startup, see the gory details of the window system on startup.

Why does TopComponent have a getLookup() method? What is it for?

The windowing system is what manages global selection. In olden times, selection meant the activated Node.

In modern NetBeans, the global selection is really whatever objects are in the focused TopComponent's Lookup. It so happens that most standard TopComponents display Nodes - so for most TopComponents, the component's Lookup is just proxying the Lookup of the selected Node.

Rather than thinking of the selection as some specific object or Node, it is more useful to think of it as a grab bag of stuff provided by whatever component happens to have focus. If you use Utilities.actionsGlobalContext(), you do not have to track all the different grab-bags of stuff provided by different components - you can get one grab bag of stuff which whose content will simply change (notifying you in the process) when focus moves to a different component.

So the TopComponent's Lookup is a way to provide your particular grab bag of stuff - it can be the lookup of a Node if you want, or it can be/contain whatever else or in addition you'd like to put there.

What are the various window system file formats like .wstcref and how do I use them?

The window system on screen is composed of tabbed areas called "modes" (originally this was intended as "docking mode" as in the way a component is docked into the main window - yes, it's a lousy name). These correspond to the class org.openide.windows.Mode. In the system filesystem, each Mode is represented by a folder.

At least in theory, a TopComponent can exist in more than one Mode, so there is a one-to-many relationship. The pre-NetBeans 3.6 windowing system had a concept of "workspaces", and a Mode could be opened on multiple workspaces. So instead of putting TopComponents (as represented by the .settings files) into the folders directly, you put those settings files into the Windows2Local/Components folder. And you put a Window System Top Component Reference - or .wstcrf - lovely to pronounce - in the mode folder. It's like a symbolic link, pointing to the .settings file in the Windows2Local/Components folder via its ID. That way, one TopComponent could be linked to by several Modes.

Modes have configuration data too, such as the constraints for where in the main window they should appear - what side, what TopComponent should be selected etc. So for each Mode defined in Windows2/Modes, there is also a .wsmode file that contains that information.

The system filesystem is read-write - so changed information (for example, the user dragged a tab to a different Mode or opened or closed it) is saved to the user's settings directory, transparently. On a restart, the saved information will be read in and restored.

So what happens is, if the user changes the position of windows, the selected tab, the splitter positions, etc., then new versions of the .settings, .wsmode or .wstcref files will be saved in the userdir in order to restore the state on restart to how the user had configured it.

One handy way to generate all of those files, rather than doing it by hand, is to just create an action in your module that will open your TopComponent. Run it on a clean userdir, open your TopComponent, and put it where you want it to appear. Shut down. Go into your user dir, and copy the files the IDE persisted into your module. Edit to taste, add references in your module's layer file (any module that opens a component is a good example - try core/navigation) and voila.

You may want to look at the samples - there are example modules that use all of the declarative window system APIs and file formats.

How does the declarative XML API for the window system work?

The API is not hard, just a bit baroque.

On startup, the window system needs to know some things to construct the main window, and possibly restore the state it was in before shutdown:

  • The window system needs know what components it will be displaying
  • It needs to know where to display individual components
  • And it has a way to define places where components can be displayed, and needs to know what places have been defined

It would be a disaster for performance if all possible components in the system had to be instantiated/deserialized during startup just to figure out if they actually need to be on screen. The XML definitions for window system components allow a module to completely declaratively provide all the information described above.

There are three main file types to be concerned with - these are put in the System Filesystem by declaring them in your module's layer file:

  • .settings files - representing TopComponents that will be on screen - these go in Windows2/Components
  • .wsmode files - representing docking modes - places where TopComponents can be put - think of them as tabbed containers - these go in Windows2/Modes. For each Mode, you will also create a folder in Windows2/Modes where the .wstcref files that indicate what components are present can go TopComponents can live (essentially tabbed containers)
  • .wstcrf files - a pseudo symbolic-link that contains some configuration data and points to the appropriate .settings file via its ID - put these in the folder you created in Windows2/Modes

See also:

Q: How do I show that a user has filled an invalid input into my wizard?

A: Set the WizardPanel_errorMessage property in the WizardPanel instance that is related to the displayed panel.

Example:

wizardDescriptor.putProperty("WizardPanel_errorMessage", NbBundle.getMessage(MyPanel1.class, "key"));

Note: Since WizardDescritor, spec.version 7.8 (i.e.since NetBeans 6.5 Platform)

  • you can use WizardDescriptor.PROP_ERROR_MESSAGE instead of "WizardPanel_errorMessage".
  • beside WizardDescriptor.PROP_ERROR_MESSAGE you can also use WizardDescriptor.PROP_WARNING_MESSAGE for warning messages or WizardDescriptor.PROP_INFO_MESSAGE for information messages.
  • All kind of messages will be badged with appropriate icons: DevFaqWizardPanelError/error.gif, DevFaqWizardPanelError/warning.gif and DevFaqWizardPanelError/info.png
  • To clean the message just call wizardDescriptor.putProperty(WizardDescriptor.PROP_ERROR_MESSAGE, null);

You can obtain the instance of WizardDescriptor in the WizardDescriptor.Panel.readSettings as settings parameter method.

What is a library wrapper module and how do I use it?

If your module uses some external library, you will probably use a wrapper module to make classes from that library available to your module at runtime.

A wrapper module is a module that contains no code; really the only significant thing about it is its manifest, which does two significant things, in addition to the standard module unique ID/version/etc.:

  • Has a Class-Path entry for one or more JARs, conventionally in the subdirectory ext/ of the directory where the module is.
  • Declares OpenIDE-Module-Public-Packages followed by a list of the packages from the library that other modules should be able to use.

You can use File > New Project > NetBeans Modules > Library Wrapper Module to make a library wrapper.

So a wrapper module acts as a proxy to turn a library into a NB module. Since you can't modify the NetBeans classpath directly (DevFaqNetBeansClasspath), nor would you want to, this is the way you let your code use third-party libraries. It serves the same function that running with java -cp or setting CLASSPATH would do in a smaller Java application.

There are other options for packaging libraries described in DevFaqWhenUseWrapperModule.

If the above was confusing, read DevFaqModuleDependencies.

Using a wrapper module for an existing project

If you are developing the library yourself, but decide you want to keep the library project separate from any NB module project, you can do so. Just make a plain Java project for the library and build it; and also create a library wrapper module from its JAR output. Here are two ways to hook them up. The first modifies the project so that when the project is built, it copies the jar to the wrapper module. The second modifies the wrapper module so that the wrapper cleans, builds and picks up the jar.

Method 1

To hook them up (since the library wrapper module wizard just copies the JAR you select), you can make the plain Java SE project build into the wrapper. Say your Java SE project is in e.g./src/suite/libs/foo and your NBM wrapper is in /src/suite/foo-wrapper; just edit /src/suite/libs/foo/nbproject/project.properties to specify e.g.:
dist.jar=../../foo-wrapper/release/modules/ext/foo.jar

Now you can just build the Java SE project and it will update the wrapper's JAR file. Also code completion on anything that compiles against the foo library should "see" sources in /src/suite/libs/foo/src (so long as the Java SE project is open).

Method 2

Here's how to have the wrapper module build, clean and pick up the JAR from the Java SE project's original location with source association (even if the Java SE project is not open!). You modify the wrapper's project.xml (to adjust the <class-path-extension>), project.properties (to specify extra.module.files) and build.xml (to override the release target) as shown in the following example. harness/README gives the details. See also Issue 70894, which would make it easier.

Example: Having the wrapper module clean and build the project

With these changes to a wrapper module, build/clean on the wrapper, or on the module suite that contains the wrapper, also does build/clean on the project.

For this example, my-wrapper is a library wrapper module for the JAR file produced by the regular Java project called my-project. my-project and my-wrapper are in the same directory; this only affects relative path specifications and is not a general requirement. This example was created on NetBeans 5.5. If you have jars from multiple projects in a wrapper, then this example is extended by using <antsub> instead of <ant> and a FileSet in the release target's <copy> task.

Only the my-wrapper project needs modification.

First

In my-wrapper/nbproject/project.xml, change <class-path-extension>'s <binary-origin> to reference the jar created by my-project. This change gives code completion with Javadoc and Go to Source when referencing my-project.
<binary-origin>../my-project/dist/my-project.jar</binary-origin>

Make sure a ../src directory (relative to the JAR location) containing the corresponding sources of the library exists if you want Go to Source functionality to work.

Second

In my-wrapper/nbproject/project.properties specify where my-project's JAR file is installed in the suite's cluster. This puts my-project.jar in the wrapper's NBM; it is needed since the wrapper's release directory is no longer used as a staging area.
extra.module.files=modules/ext/my-project.jar

Third

Delete the directory my-wrapper/release. The original JAR file was copied here when the wrapper was created. It will interfere if it is left around.

Fourth

In my-wrapper/build.xml add the following. Customize the first two properties' value= to specify your project's relative location and JAR. The release target is replaced; now it builds my-project then copies the JAR to the suite's cluster. The clean target first cleans as usual, then cleans my-project.
<property name="original.project.dir" value="../my-project"/>
<property name="original.project.jar"
          value="${original.project.dir}/dist/my-project.jar"/>

<target name="release">
    <echo message="Building ${original.project.dir}"/>
    <ant dir="${original.project.dir}"
         target="jar" inheritall="false" inheritrefs="false"/>
    <echo message="Done building ${original.project.dir}"/>

    <copy todir="${cluster}/modules/ext"
          file="${original.project.jar}"/>
</target>


<target name="clean" depends="projectized-common.clean">
    <echo message="Cleaning ${original.project.dir}"/>
    <ant dir="${original.project.dir}"
         target="clean" inheritall="false" inheritrefs="false"/>
    <echo message="Done cleaning ${original.project.dir}"/>
</target>

How do I include native libraries (*.so or *.dll) in my library wrapper module?

Some libraries come with a native counterpart. The current Library Wrapper wizard doesn't cater to this. As per the JNI section in this document, you simply need to create a lib directory under <my-wrapper>/release/modules (which gets created by the wizard), alongside the ext directory mentioned earlier in this document. This directory is where you place your native libraries.

How do I include more that one jar in my library wrapper module?

As explained in this mail and in this README the library wrapper creation wizard will only add one jar. To add more you need to copy the jars to release/modules/ext/ and edit nbproject/project.xml to add extra <class-path-extension> elements.
           <class-path-extension>
               <runtime-relative-path>ext/extra1.jar</runtime-relative-path>
               <binary-origin>release/modules/ext/extra1.jar</binary-origin>                
           </class-path-extension>
           <class-path-extension>
               <runtime-relative-path>ext/extra2.jar</runtime-relative-path>
               <binary-origin>release/modules/ext/extra2.jar</binary-origin>
           </class-path-extension>

Applies to: NetBeans 5.5, 6.x