NetBeans Developer Faq

Generated on Mon Aug 15 05:38:11 UTC 2011 from http://wiki.netbeans.org/NetBeansDeveloperFAQ


 

Getting Started

What is a module?

NetBeans is a modular application. That means it is composed of pieces, which are discovered at runtime. Some of those pieces may even be downloaded and installed or uninstalled at runtime.

A module is a library. It is a Java JAR (Java ARchive) file which contains some classes.

NetBeans is a Java application. It has a very small core runtime which knows how to find the modules that make up the application (the launcher passes a list of directories - these are commonly called clusters - which contain module JAR files and some XML metadata about them).

All real functionality of the NetBeans IDE or any NetBeans-based application is implemented as modules.

A module JAR contains some additional entries in its META-INF/MANIFEST.MF file, which tell NetBeans about the module - its name, its version, etc.

One distinction about NetBeans modules, as opposed to just working with JAR files on your classpath is that the NetBeans runtime enforces dependency management between modules - to call code in another module from yours, your module must declare a dependency on the other module.

Another significant distinction is that a module can specify which (if any) packages it makes visible to modules that depend on it - so it is possible to have Java packages in a module's JAR file which are visible only to other classes within that JAR file. That, in effect, extends Java's class visibility-scoping rules (public, protected, private, package-private) to include public only within this JAR file.

Becoming a proficient module developer

The NetBeans Platform has a learning curve. The goal of this FAQ 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.

Javadoc

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

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 NetBeans Platform Examples

There are a large number of samples. Many of these correspond to the tutorials.

Two full blown NetBeans Platform applications are provided as samples in NetBeans IDE. Look in the Samples category in the New Project dialog and you will find the FeedReader sample and the Paint sample, for both of which there are tutorials describing how to create them from scratch.

You can find several other samples in the 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 browse the archives online, but actually joining the mailing list is the best way to get (and give) help.

Note: dev@platform.netbeans.org was formerly dev@openide.netbeans.org - older archives can be found on Nabble and 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 do I get sources for NetBeans 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/
cd main

to get the full Platform and IDE sources. If you also want the contrib/ modules:

hg clone http://hg.netbeans.org/main/contrib/

To build, simply run ant. The build will appear in nbbuild/netbeans/.

More info about using Mercurial with NetBeans sources...

How do I get zipped sources for a periodic build?

(as of June, 2010)

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 where you can find a link to the folder with ZIP archives of binary builds and sources.

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

   http://bits.netbeans.org/dev/nightly/2010-06-11_00-01-15/zip/

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

What API do I want to use for x, y or z?

Here is a list of common things people need to do, and a very short description of how you do them. From here, use the Javadoc and tutorials to get more information.

I want to ...
Show my component in the main window

Use the Window System API. You will want to create a subclass of TopComponent, a JPanel-like class, and call its open() method to show it.

Write to the output window

Use the I/O API. Call IOProvider.getDefault().getInputOutput("Something"). The object returned has getters for standard output, standard error and input streams which write to and read from a tab in the output window.

Show a Tree, List or other control with a list of some objects

Use the Nodes API to create a hierarchy of Node objects, each representing one object in your data model. Then use the Explorer API to show the Nodes - it contains tree, list, table, combo box and other controls which can show a hierarchy of Nodes. Nodes are very easy to add popup menus to, decorate with icons and html-ized display names, etc. and are a lot less work than using Swing components directly. See also the Nodes API Tutorial.

Provide an Editor for a particular kind of file

Use the new File Type template. You will end up using the Data Systems API (DataObject, DataLoader, etc.) and Nodes API primarily, plus the Filesystems API for accessing and parsing the file. The Text API provides general support for creating editors for files.

Add a menu item to the main menu

No specific NetBeans APIs are needed - you can just create a subclass of Swing's AbstractAction, and register it in your modules layer.xml file. Or, use the new Action template in the IDE to generate a subclass of SystemAction for you and all the registration code, and fill in the action-performing logic.

Show content in the Navigator window when a file of a certain type is selected

Use the Navigator API to create a navigator panel provider; you then somehow parse the file and can create any component you want to show in the Navigator, and populate it with whatever you want.

Show a progress bar

Use the Progress API - call ProgressHandleFactory to create a ProgressHandle for you. That is an object with methods for setting the progress, status text, number of steps, etc. and is fairly self-explanatory. Remember to make sure the code showing progress is not running in the AWT Event thread.

Set the main window's statusbar text

Use the UI Utilities API. Simply call StatusDisplayer.getDefault().setStatusText().

Allow other modules to register objects and then find those objects dynamically at runtime

Define a folder in the System Filesystem in the XML layer file of your module. Other modules can register instances of whatever class you specify by declaring .instance files in their own XML layer files. You can find them at runtime using Lookups.forPath("path/to/my/folder") to get an instance of Lookup that you can query for these objects.

Save some settings persistently

Use the Utilities API, specifically NbPreferences - which is just an implementation of the JDK's Preferences API which stores things in the user's settings directory rather than globally. It's just like using standard JDK Preferences.

Run some code at application startup/shutdown

Use the Module System API. Implement a subclass of ModuleInstall and override restored(), close(), etc. Remember it is best to avoid running code on startup unless you really need to.

Add a Panel to the Options dialog

Use the Options API, implementing OptionsCategory to define the category in the dialog and OptionsPanelController to manage the UI component.

Find/listen to/manipulate the set of open projects

Use the Project UI API, specifically OpenProjects.

Create a graph editor such as the Mobility Pack uses

Use the Visual Library, which builds on top of Swing to make animated, graph-oriented UIs easy to build. More info, tutorials and webcasts can be found in the platform.netbeans.org/graph project.

I have written a module. Can I sell it?

Yes. The license is very non-restrictive. For details, see the license.

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 this way 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:

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:

1. Go to the nightly build download site: http://bits.netbeans.org/dev/nightly/

2. Click the link for the build you want.

3. 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/2010-06-11_00-01-15/zip/

5. There are about a dozen links on that page. The one you want begins with netbeans-trunk-nightly and ends with -javadoc.zip; click that link to download the Javadoc archive.

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

# Give a name to the platform at the relative path and define its location
# using the platform.base property we set above. You can change the value  
# ('myplatform') to something more descriptive (like 'nb68'), but you
# must then change the name of the second property (e.g. from 
# nbplatform.myplatform.netbeans.dest.dir to nbplatform.nb68.netbeans.dest.dir)
nbplatform.active=myplatform
nbplatform.myplatform.netbeans.dest.dir=${platform.base}

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

Some automation anyone?

The above process is basically manual so here are some stuff I developed to automate the process:

Update the development environment

The following allows to update the development environment mentioned above that should be part of version control. (i.e. to make it work from Hudson for example)

Hare are its contents:

<?xml version="1.0" encoding="UTF-8"?>
<project name="XXX-Preparation" basedir=".">
    <description>Prepares the environment to build the module suite XXX.</description>
    <!--Don't modify this file unless you know what you are doing-->
    <property name="ant-contrib-filename" value="ant-contrib-1.0b3.jar"/>
    <property file="nbproject/project.properties"/>
    <property file="nbproject/platform.properties"/>
    
    <target name="update-platform" depends="init-netbeans">
        <for list="${cluster.path}" delimiter=":" param="cur" trim="true">
            <sequential>
                <add-core-module module="@{cur}"/>
            </sequential>
        </for>
    </target>

    <target name="unzip-compilation-env" depends="init-netbeans, init-hudson">
        <!--Hudson needs to run this task first as it gets the core modules as zip from version control-->
        <for list="${cluster.path}" delimiter=":" param="cur" trim="true">
            <sequential>
                <expand-module module="@{cur}"/>
            </sequential>
        </for>
    </target>

    <target name="update-env" depends="init-netbeans, init-hudson" description="Update the Netbeans core modules used to compile/run OIT">
        <!--Make sure that any recently added module using the IDE is also included.
        Fix it to the proper format.-->
        <mkdir dir="../netbeans/"/>
        <propertyregex property="cluster.path"
               input="${cluster.path}"
               regexp="nbplatform.active.dir"
               replace="platform.base"
               global="true"
               override="true"/>
        <replaceregexp file="nbproject/platform.properties"
                       match="nbplatform.active.dir"
                       replace="platform.base"
                       byline="true"
                       flags="g,s"/>
        <pathconvert pathsep="\;" property="folders_temp">
            <dirset dir="../netbeans/">
                <include name="*/**"/>
                <!--ignore svn and cvs files-->
                <include name="**/.svn"/>
                <include name="**/.svn/**"/>
                <include name="**/CVS"/>
                <include name="**/CVS/**"/>
                <!--Exclude the nb-plugins folder-->
                <exclude name="nb-plugins/**"/>
                <!--Exclude the root folder-->
                <exclude name="../netbeans"/>
            </dirset>
        </pathconvert>
        <antcall target="update-platform"/>
        <antcall target="unzip-compilation-env"/>
    </target>

    <macrodef name="expand-module">
        <attribute name="module"/>
        <sequential>
            <delete dir="@{module}"/>
            <unzip src="@{module}.zip" dest="@{module}"/>
        </sequential>
    </macrodef>

    <macrodef name="add-core-module">
        <attribute name="module"/>
        <sequential>
            <if>
                <equals arg1="@{module}" arg2="../netbeans/nb-plugins"/>
                <then>
                    <echo>Adding custom module @{module}</echo>
                    <available file="@{module}" type="dir" property="customdir.exists"/>
                    <if>
                        <equals arg1="${customdir.exists}" arg2="true"/>
                        <then>
                            <zip destfile="@{module}.zip" basedir="@{module}" update="true"/>
                        </then>
                    </if>
                </then>
                <else>
                    <length string="@{module}" property="@{module}.length.module" />
                    <substring text="@{module}" start="12" end="${@{module}.length.module}" property="new.module"/>
                    <echo>Adding netbeans core module ${new.module}</echo>
                    <mkdir dir="../netbeans/${new.module}/"/>
                    <delete file="../netbeans/${new.module}.zip"/>
                    <delete includeemptydirs="true">
                        <fileset dir="../netbeans/${new.module}/" includes="**/.*" defaultexcludes="false"/>
                    </delete>
                    <zip destfile="../netbeans/${new.module}.zip" basedir="${netbeans.home}\..\${new.module}" update="true"/>
                </else>
            </if>
        </sequential>
    </macrodef>
    
    <scriptdef name="substring" language="javascript">
        <attribute name="text" />
        <attribute name="start" />
        <attribute name="end" />
        <attribute name="property" />
     <![CDATA[
       var text = attributes.get("text");
       var start = attributes.get("start");
       var end = attributes.get("end") || text.length;
       project.setProperty(attributes.get("property"), text.substring(start, end));
     ]]>
    </scriptdef>

    <target name="check-env" depends="getAntContribJar">
        <condition property="isNetbeans">
            <not>
                <isset property="Hudson"/>
            </not>
        </condition>
    </target>

    <target name="getAntContribJar">
        <fileset id="ant-contrib-jar" dir="${suite.dir}/tools">
            <include name="ant-contrib-*.jar" />
        </fileset>
        <pathconvert property="ant-contrib-jar" refid="ant-contrib-jar" pathsep="," />
        <basename property="ant-contrib-filename" file="${ant-contrib-jar}"/>
    </target>

    <target name="init-netbeans" depends="check-env" if="isNetbeans">
        <echo>Configuring ant-contrib for Netbeans use...</echo>
        <property name="ant-contrib-loc" value="${suite.dir}/tools/${ant-contrib-filename}"/>
        <available file="${ant-contrib-loc}" property="ant-contrib.present"/>
        <fail unless="ant-contrib.present" message="The ant-contrib jar doesn't exist at: ${ant-contrib-loc}, can't build. Check your settings!" />
        <!--We are in not Hudson-->
        <taskdef resource="net/sf/antcontrib/antcontrib.properties">
            <classpath>
                <pathelement location="${ant-contrib-loc}"/>
            </classpath>
        </taskdef>
    </target>

    <target name="init-hudson" depends="check-env" unless="isNetbeans">
        <echo>Configuring ant-contrib for Hudson use...</echo>
        <!--Import Hudson environment variables-->
        <property environment="env"/>
        <property name="ant-contrib-loc" value="${env.ANT_HOME}/lib/${ant-contrib-filename}"/>
        <available file="${ant-contrib-loc}" property="ant-contrib.present"/>
        <fail unless="ant-contrib.present" message="The ant-contrib jar doesn't exist at: ${ant-contrib-loc}, can't build. Check your settings!" />
        <!--Define it. For some reason the approach in init-netbeans doesn't work in Hudson.-->
        <taskdef name="for" classname="net.sf.antcontrib.logic.ForTask">
            <classpath>
                <pathelement location="${ant-contrib-loc}"/>
            </classpath>
        </taskdef>
        <taskdef name="propertyregex" classname="net.sf.antcontrib.property.RegexTask">
            <classpath>
                <pathelement location="${ant-contrib-loc}"/>
            </classpath>
        </taskdef>
        <taskdef name="if" classname="net.sf.antcontrib.logic.IfTask">
            <classpath>
                <pathelement location="${ant-contrib-loc}"/>
            </classpath>
        </taskdef>
        <taskdef name="math" classname="net.sf.antcontrib.math.MathTask">
            <classpath>
                <pathelement location="${ant-contrib-loc}"/>
            </classpath>
        </taskdef>
        <taskdef name="var" classname="net.sf.antcontrib.property.Variable">
            <classpath>
                <pathelement location="${ant-contrib-loc}"/>
            </classpath>
        </taskdef>
    </target>
</project>

Here's a sumary of the targets and what they do:

Keep in mind that after making the changes proposed earlier in this FAQ the project won't work (i.e. build, run, etc) if the environment is not set.

That's the reason of doing all this in another xml file. Attempting any of this from the suite's build file won't work since you are messing with the platform files it is working from.

Notes:

for=net.sf.antcontrib.logic.ForTask

See also:

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/

Set the available memory that Ant can use:

set ANT_OPTS=-Xmx256M

(or on Unix, export ANT_OPTS=-Xmx256M)

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. As of NetBeans 6.9, NetBeans is built with JDK 6, and this flag is no longer needed.

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.

1. Click Tools -> NetBeans Platforms (note that the menu item name varies slightly in older versions)

2. Click the "Add Platform..." button in the lower right

3. Locate the platform binary and click OK. In this example the proper path is ~/netbeans-repository/main/nbbuild/netbeans/.

4. You can associate sources and javadoc for this platform using the respective tabs in the platform manager

5. You can also choose which version of the build scripts you want to us on the Harness tab. You'll usually want to use the version corresponding to that platform.

4. Reference The New NetBeans 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: 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.

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.

In the Libraries tab of my application's Project Properties, there sure are a lot of modules listed. What are they for

When you're creating an application on the NetBeans Platform in NetBeans IDE, you can right-click the app in the Projects window, choose Properties, and then go to the Libraries tab. There you'll see a list of clusters containing the modules you can add to your application.

What are they all for? Here's the answer.

platform cluster

Display Name Module Comments
Actions API org.openide.actions
Actions SPI (Experimental) org.netbeans.modules.spi.actions
Apache's Felix OSGi Implementation org.netbeans.libs.felix
Apple Application Menu org.netbeans.modules.applemenu
Auto Update Services org.netbeans.modules.autoupdate.services
Auto Update UI org.netbeans.modules.autoupdate.ui
Bootstrap org.netbeans.bootstrap
Command Line Parsing API org.netbeans.modules.sendopts
Common Annotations org.netbeans.api.annotations.common
Core org.netbeans.core
Core - Execution org.netbeans.core.execution
Core - UI org.netbeans.core.ui
Core - Windows org.netbeans.core.windows
Datasystems API org.openide.loaders
Dialogs API org.openide.dialogs
ETable and Outline org.netbeans.swing.outline
Execution API org.openide.execution
Explorer & Property Sheet API org.openide.explorer
Favorites org.netbeans.modules.favorites
File System API org.openide.filesystems
General Queries API org.netbeans.modules.queries
I/O APIs org.openide.io
I/O UI org.netbeans.core.io.ui
JavaHelp Integration org.netbeans.modules.javahelp
JNA org.netbeans.libs.jna
JUnit 4 org.netbeans.libs.junit4
Keymap Options org.netbeans.modules.options.keymap
Keyring API org.netbeans.modules.keyring
Keyring Implementations org.netbeans.modules.keyring.impl
Look & Feel Customization Library org.netbeans.swing.plaf
Lookup API org.openide.util.lookup
Master Filesystem org.netbeans.modules.masterfs
MIME Lookup API org.netbeans.modules.editor.mimelookup
MIME Lookup on SystemFS org.netbeans.modules.editor.mimelookup.impl
Module System API org.openide.modules
MultiView Windows org.netbeans.core.multiview
Native Access org.netbeans.core.nativeaccess
NetBeans in OSGi Runtime org.netbeans.core.osgi
NetBeans OSGi Integration org.netbeans.core.netigso
Nodes API org.openide.nodes
Options Dialog and SPI org.netbeans.modules.options.api
OSGi Specification org.netbeans.libs.osgi
Output Window org.netbeans.core.output2
Print org.netbeans.modules.print
Progress API org.netbeans.api.progress
Progress UI org.netbeans.modules.progress.ui
Quick Search API org.netbeans.spi.quicksearch
RCP Platform org.netbeans.modules.core.kit
Settings API org.netbeans.modules.settings
Startup org.netbeans.core.startup
Tab Control org.netbeans.swing.tabcontrol
Text API org.openide.text
UI Utilities API org.openide.awt
Utilities API org.openide.util
Visual Library API org.netbeans.api.visual
Window System API org.openide.windows


nb cluster

Display Name Module Comments
Bugzilla-Exception Reporter Bridge org.netbeans.modules.bugzilla.exceptionreporter
Exception Reporter org.netbeans.modules.uihandler.exceptionreporter
IDE Branding org.netbeans.modules.ide.branding.kit
NetBeans IDE Branding org.netbeans.modules.ide.branding
Plugin Importer org.netbeans.modules.autoupdate.pluginimporter
UI Gestures Collector Infrastructure org.netbeans.modules.uihandler
UI Handler Library org.netbeans.lib.uihandler
Update Centers org.netbeans.modules.updatecenters
Upgrade org.netbeans.upgrader
Welcome Screen org.netbeans.modules.welcome


ide cluster

Display Name Module Comments
.diff File Editor Support org.netbeans.modules.languages.diff
,manifest file Editor Support org.netbeans.modules.languages.manifest
Abstract XML Instance Object Model org.netbeans.modules.xml.axi
Ant-Based Project Support org.netbeans.modules.project.ant
Antlr 3.1.3 Runtime org.netbeans.libs.antl3.runtime
Apache Resolver Library 1.2 org.apache.xml.resolver
Bugzilla org.netbeans.modules.bugzilla
Bugzilla Libraries org.netbeans.libs.bugzilla
Classpath APIs org.netbeans.api.java.classpath
Code Coverage Support org.netbeans.modules.gsf.codecoverage
Common Palette org.netbeans.spi.palette
Commons Code Integration org.netbeans.libs.commons_codec
Common Scripting Language API (new) org.netbeans.modules.csl.api
Common Server org.netbeans.modules.server
Commons Logging Integration org.netbeans.libs.commons_logging
Commons Net Integration org.netbeans.libs.commons_net
Common Test Runner API org.netbeans.modules.gsf.testrunner
Core IDE org.netbeans.core.ide
CSS Editor org.netbeans.modules.css.editor
CSS Visual Editor org.netbeans.modules.css.visual
CVS org.netbeans.modules.versioning.system.cvss
CVS Client Library org.netbeans.libs.cvsclient
Database org.netbeans.modules.db.kit
Database APIs org.netbeans.modules.dbapi
Database Core org.netbeans.modules.db.core
Database DataView org.netbeans.modules.db.dataview
Database Drivers org.netbeans.modules.db.drivers
Database Explorer org.netbeans.modules.db
Database Metadata Model org.netbeans.modules.db.metadata.model
Debugger Core API org.netbeans.api.debugger
Debugger Core - UI org.netbeans.spi.debugger.ui
Diff org.netbeans.modules.diff
Directory Chooser org.netbeans.swing.dirchooser
Editing Files org.netbeans.modules.editor.kit
Editor org.netbeans.modules.editor
Editor Actions org.netbeans.modules.editor.actions
Editor Bookmarks org.netbeans.modules.editor.bookmarks
Editor Brace Matching org.netbeans.modules.editor.bracesmatching
Editor Code Completion org.netbeans.modules.editor.completion
Editor Code Folding org.netbeans.modules.editor.fold
Editor Code Templates org.netbeans.modules.editor.codetemplates
Editor Error Stripe org.netbeans.modules.editor.errorstripe.api
Editor Error Stripe Impl org.netbeans.modules.editor.errorstripe
Editor Guarded Sections org.netbeans.modules.editor.guards
Editor Hints org.netbeans.spi.editor.hints
Editor Indentation org.netbeans.modules.editor.indent
Editor Indentation for Projects org.netbeans.modules.editor.indent.project
Editor Library org.netbeans.modules.editor.lib
Editor Library 2 org.netbeans.modules.editor.lib2
Editor Macros org.netbeans.modules.editor.macros
Editor Options org.netbeans.modules.options.editor
Editor Settings org.netbeans.modules.options.settings
Editor Settings Storage org.netbeans.modules.options.settings.storage
Editor Utilities org.netbeans.modules.editor.util
Embedded Browser org.netbeans.core.browser
Extensible Abstract Model (XAM) org.netbeans.modules.xml.xam
External Execution Process Destroy Support org.netbeans.modules.extexecution.destroy
External Execution Support org.netbeans.modules.extexecution
External HTML Browser org.netbeans.modules.extbrowser
External Libraries org.netbeans.modules.project.libraries Support for organizing resources into libraries.
Freemarker Integration org.netbeans.libs.freemarker
General Online Help org.netbeans.modules.usersguide
Glassfish Server 3 - Common org.netbeans.modules.glassfish.common
HTML org.netbeans.modules.html
HTML5 Parser org.netbeans.modules.html.parser
HTML Editor org.netbeans.modules.html.editor
HTML Editor Library org.netbeans.modules.html.editor.lib
HTML Lexer org.netbeans.modules.html.lexer
HTML Validation org.netbeans.modules.html.validation
HTTP Server org.netbeans.modules.httpserver
Hudson org.netbeans.modules.hudson
Hudson Mercurial Bindings org.netbeans.modules.hudson.mercurial
Hudson Subversion Bindings org.netbeans.modules.hudson.subversion
IDE Defaults org.netbeans.modules.defaults Contains font, color, and shortcut defaults.
IDE Platform org.netbeans.modules.ide.kit
Image org.netbeans.modules.image Supports viewing of image files.
Ini4j org.netbeans.libs.ini4j
Issue Tracking org.netbeans.modules.bugtracking
Issue Tracking Bridge Module org.netbeans.modules.bugtracking.bridge
Issue Tracking Libraries org.netbeans.libs.bugtracking
Jakarta ORO Integration org.netbeans.libs.jakarta_oro
Java DB Database Support org.netbeans.modules.derby
JavaScript org.netbeans.modules.javascript.kit
JavaScript Editing org.netbeans.modules.javascript.editing
JavaScript Hints org.netbeans.modules.javascript.hints
JavaScript Refactoring org.netbeans.modules.javascript.refactoring
Java Secure Channel Integration org.netbeans.libs.jsch
Java zlib integration org.netbeans.libs.jzlib
JAXB 2.2 Library org.netbeans.libs.jaxb
JAXB API org.netbeans.modules.xml.jaxb.api
Jelly Tools API org.netbeans.modules.jellytools.ide
JRuby ByteList org.netbeans.libs.bytelist JRuby ByteList Library
Jump To org.netbeans.modules.jumpto Action to quickly navigate to a file or type.
Lexer org.netbeans.modules.lexer
Lexer to NetBeans Bridge org.netbeans.modules.lexer.nbbridge
Local History org.netbeans.modules.localhistory
Lucene Integration org.netbeans.libs.lucene
Mercurial org.netbeans.modules.mercurial
MySQL Database Support org.netbeans.modules.db.mysql
Native Execution org.netbeans.modules.dlight.nativeexution
Native Terminal org.netbeans.modules.dlight.terminal
Navigate To Test org.netbeans.modules.gototest An action to quickly navigate to a test for a file
Navigator API org.netbeans.spi.navigator
Parsing API org.netbeans.modules.parsing.api
Parsing Lucene Support org.netbeans.modules.parsing.lucene
Plain Editor org.netbeans.modules.editor.plain
Plain Editor Library org.netbeans.modules.editor.plain.lib
Print Editor org.netbeans.modules.print.editor
Project API org.netbeans.modules.projectapi
Projects Searching org.netbeans.modules.utilities.project
Project UI org.netbeans.modules.projectui
Project UI API org.netbeans.modules.projectuiapi
Project UI Build Menu org.netbeans.modules.projectui.buildmenu
Refactoring API org.netbeans.modules.refactoring.api
Resource Bundles org.netbeans.modules.properties
Resource Bundle Syntax Coloring org.netbeans.modules.properties.syntax
Rhine IDE JavaScript Handler org.mozilla.rhino.patched
Schema Aware Code Completion org.netbeans.modules.xml.schema.completion
Schema-to-Beans Library org.netbeans.modules.schema2beans
Search API org.openidex.util
Servlet 2.2 API org.netbeans.modules.servletapi
Smack API org.netbeans.libs.smack
Spellchecker org.netbeans.modules.spellchecker.kit
Spellchecker API org.netbeans.modules.spellchecker.apimodule
Spellchecker Core org.netbeans.modules.spellchecker
Spellchecker English Dictionaries org.netbeans.modules.spellchecker.dictionary_en
Spellchecker HTML XML Bindings org.netbeans.modules.spellchecker.bindings.htmlxml
Spellchecker Properties Bindings org.netbeans.modules.spellchecker.bindings.properties
SQL Editor org.netbeans.modules.db.sql.editor
Subversion org.netbeans.modules.subversion
Subversion Client Library org.netbeans.libs.svnClientAdapter
Subversion JavaHL Client Library org.netbeans.libs.svnClientAdapter.javahl
Subversion SvnKit Client Library org.netbeans.libs.svnClientAdapter.svnkit
Swing Simple Validation API org.netbeans.modules.swing.validation
SwingX org.netbeans.libs.swingx
Tags Based Editors Library org.netbeans.modules.editor.structure
Target Chooser Panel org.netbeans.modules.target.iterator
Task List org.netbeans.modules.tasklist.kit
Task List API org.netbeans.spi.tasklist
Task List - Project Integration org.netbeans.modules.tasklist.projectint
Task List UI org.netbeans.modules.tasklist.ui
TAX Library org.netbeans.modules.xml.tax
Terminal org.netbeans.modules.terminal
Terminal Emulator org.netbeans.lib.terminalemulator
ToDo Task Scanner org.netbeans.modules.tasklist.todo
TreeTableView Model org.netbeans.spi.viewmodel
User Utilities org.netbeans.modules.utilities
Versioning org.netbeans.modules.versioning
Versioning-Index Bridge org.netbeans.modules.versioning.indexingbridge
Versioning Support Utilities org.netbeans.modules.versioning.util
Visual Query Editor org.netbeans.modules.db.sql.visualeditor
Web Client Tools API org.netbeans.modules.web.client.tools.api
Web Common org.netbeans.modules.web.common
Xerces Integration org.netbeans.libs.xerces
XML Core org.netbeans.modules.xml.core
XML Document Model (XDM) org.netbeans.modules.xml.xdm
XML Entity Catalog org.netbeans.modules.xml.catalog
XML Lexer org.netbeans.modules.xml.lexer
XML Multiview Editor org.netbeans.modules.xml.multiview
XML Productivity Tools org.netbeans.modules.xml.tools
XML Retriever org.netbeans.modules.xml.retriever
XML Schema API org.netbeans.modules.xml.schema.model
XML Support org.netbeans.modules.xml
XML Text Editor org.netbeans.modules.xml.text
XML Tools API org.netbeans.api.xml
XML WSDL API org.netbeans.modules.xml.wsdl.model
XSL Support org.netbeans.modules.xsl
YAML Editor Support org.netbeans.modules.languages.yaml
YAML Parser Library (jvyamlb) org.netbeans.libs.jvyamlb


java cluster

Display Name Module Comments
Ant org.apache.tools.ant.module
Ant org.netbeans.modules.ant.kit
Ant Code Completion org.netbeans.modules.ant.grammar
Ant Debugger org.netbeans.modules.ant.debugger
Bean Patterns org.netbeans.modules.beans
Beans Binding Integration org.jdesktop.beansbinding
Classfile Reader org.netbeans.modules.classfile
Code Generation Library Integration org.netbeans.libs.cglib
Database Schema (JDBC Implementation) org.netbeans.upgrader
Eclipse J2SE Project Importer org.netbeans.modules.projectimport.eclipse.j2se
EclipseLink (JPA 2.0) org.netbeans.modules.j2ee.eclipselink
EclipseLink-ModelGen (JPA 2.0) org.netbeans.modules.j2ee.eclipselinkmodelgen
Eclipse Project Importer org.netbeans.modules.projectimport.eclipse.core
Form Editor org.netbeans.modules.form
Freeform Ant Projects org.netbeans.modules.ant.freeform
GUI Builder org.netbeans.modules.form.kit
Hibernate org.netbeans.modules.hibernate
Hibernate 3.2.5 Library org.netbeans.modules.hibernatelib
Hudson Ant Project Support org.netbeans.modules.hudson.ant
Internationalization org.netbeans.modules.i18n
Internationalization of Form org.netbeans.modules.i18n.form
J2EE Support for Form Editor org.netbeans.modules.form.j2ee
Java org.netbeans.modules.java.kit
Javac API Wrapper org.netbeans.libs.javacapi
Javac Implementation Wrapper org.netbeans.libs.javacimpl
Java Common Project API org.netbeans.modules.java.api.common
Java Debugger org.netbeans.modules.debugger.jpda.ui
Javadoc org.netbeans.modules.javadoc
Java Editor org.netbeans.modules.java.editor
Java Editor Library org.netbeans.modules.java.editor.lib
Java EE Core Utilities org.netbeans.modules.j2ee.core.utilities
Java EE Metadata org.netbeans.modules.j2ee.metadata
Java EE Metadata Model Support org.netbeans.modules.j2ee.model.support
Java Freeform Project Support org.netbeans.modules.java.freeform
Java Guarded Sections org.netbeans.modules.java.guards
Java Hints org.netbeans.modules.java.hints
Java Hints Annotation Processor org.netbeans.modules.java.hints.processor
Java Lexer org.netbeans.modules.java.lexer
Java - Navigation org.netbeans.modules.java.navigation
Java Persistence org.netbeans.modules.j2ee.persistence.kit
Java Persistence API Support org.netbeans.modules.j2ee.persistence
Java Persistence API Support API org.netbeans.modules.j2ee.persistenceapi
Java Platform org.netbeans.modules.java.platform
Java Project Support org.netbeans.modules.java.project
Java Refactoring org.netbeans.modules.refactoring.java
Java SE Platforms and Libraries org.netbeans.modules.java.j2seplatform
Java SE Projects org.netbeans.modules.java.j2seproject
Java SE Samples org.netbeans.modules.java.examples
Java Source org.netbeans.modules.java.source
Java Source Debug org.netbeans.modules.java.debug
Java Source to Ant Bindings org.netbeans.modules.java.source.ant
Java Source UI org.netbeans.modules.java.sourceui
Java Support APIs org.netbeans.modules.api.java
Java Support Documentation org.netbeans.modules.java.helpset
Java Web Start org.netbeans.modules.javawebstart
JAXB Wizard org.netbeans.modules.xml.jaxb
JAX-WS 2.2 Library org.netbeans.modules.websvc.jaxws21
JAX-WS API org.netbeans.modules.websvc.jaxws21api
Jelly Tools org.netbeans.modules.jellytools
Jelly Tools Java org.netbeans.modules.jellytools.java
JPA Refactoring org.netbeans.modules.j2ee.jpa.refactoring
JPA Verification org.netbeans.modules.j2ee.jpa.verification
JPDA Debugger org.netbeans.modules.debugger.jpda
JPDA Debugger Ant Task org.netbeans.modules.debugger.jpda.ant
JPDA Debugger API org.netbeans.api.debugger.jpda
JPDA Debugger Projects Integration org.netbeans.modules.debugger.jpda.projects
JUnit Tests org.netbeans.modules.junit
Maven org.netbeans.modules.maven.kit
Maven Dependency Graphs org.netbeans.modules.maven.graph
Maven Editor org.netbeans.modules.maven.grammar
Maven Editor Model org.netbeans.modules.maven.model
Maven Embedder org.netbeans.modules.maven.embedder
Maven Hints org.netbeans.modules.maven.hints
Maven Hudson org.netbeans.modules.hudson.maven
Maven JUnit org.netbeans.modules.maven.junit
Maven OSGi org.netbeans.modules.maven.osgi
Maven Persistence org.netbeans.modules.maven.persistence
Maven Projects org.netbeans.modules.maven
Maven Quick Search org.netbeans.modules.maven.search
Maven Repository Browser org.netbeans.modules.maven.repository
Maven Repository Indexing org.netbeans.modules.maven.indexer
Maven Spring org.netbeans.modules.maven.spring
Preprocessor Bridge org.netbeans.modules.java.preprocessorbridge
Saas Services Code Generation for Java org.netbeans.modules.websvc.saas.codegen.java
Spellchecker Java Language Bindings org.netbeans.modules.spellchecker.bindings.java
Spring Beans org.netbeans.modules.spring.beans
Spring Framework Library org.netbeans.libs.springframework
Swing Application Framework Support org.netbeans.modules.swingapp
TopLink Essentials org.netbeans.modules.j2ee.toplinklib
Web Browser Ant Task org.netbeans.modules.ant.browsetask
XML Tools Java Ext org.netbeans.modules.xml.tools.java


harness cluster

Display Name Module Comments
INSANE org.netbeans.insane
Jelly Tools Platform org.netbeans.modules.jellytools.platform
Jemmy org.netbeans.modules.jemmy
Module Build Harness org.netbeans.modules.apisupport.harness
NBI Ant Library org.netbeans.libs.nbi.ant
NBI Engine Library org.netbeans.libs.nbi.engine
NB JUnit org.netbeans.modules.nbjunit


apisupport

Display Name Module Comments
CRUD Application Platform Sample org.netbeans.modules.apisupport.crudsample
FeedReader Application Platform Sample org.netbeans.modules.apisupport.feedreader
Maven NetBeans Module Projects org.netbeans.modules.maven.apisupport
Maven NetBeans Platform Application Installer org.netbeans.modules.apisupport.installer.maven
Module Reload Ant Task org.netbeans.modules.apisupport.ant
NetBeans Module Projects org.netbeans.modules.apisupport.project
NetBeans Module Refactoring org.netbeans.modules.apisupport.refactoring
NetBeans Platform & OSGi Samples org.netbeans.modules.apisupport.osgidemo
NetBeans Plugin Development org.netbeans.modules.apisupport.kit
PaintApp Platform Sample org.netbeans.modules.apisupport.paintapp
RCP Installers org.netbeans.modules.apisupport.installer


websvccommon

Display Name Module Comments
Amazon Services org.netbeans.modules.websvc.saas.services.amazon
Delicious Services org.netbeans.modules.websvc.saas.services.delicious
FaceBook Services org.netbeans.modules.websvc.saas.services.facebook
Flickr Services org.netbeans.modules.websvc.saas.services.flickr
Google Services org.netbeans.modules.websvc.saas.services.google
JAX-WS Models API org.netbeans.modules.websvc.jaxwsmodelapi
SaaS Services API org.netbeans.modules.websvc.saas.api
SaaS Services Code Generation org.netbeans.modules.websvc.saas.codegen
SaaS Services UI org.netbeans.modules.websvc.saas.ui
Software as a Service org.netbeans.modules.websvc.saas.kit
StrikeIron Services org.netbeans.modules.websvc.saas.services.strikeiron
Twitter Services org.netbeans.modules.websvc.saas.services.twitter
WeatherBug Services org.netbeans.modules.websvc.saas.services.weatherbug
Yahoo Services org.netbeans.modules.websvc.saas.services.yahoo
Zillow Services org.netbeans.modules.websvc.saas.services.zillow
Zvents Services org.netbeans.modules.websvc.saas.services.zvents


profiler

Display Name Module Comments
Java Profiler org.netbeans.modules.profiler
Java Profiler (Attach - Generic J2EE Server Support) org.netbeans.modules.profiler.j2ee.generic
Java Profiler (Attach - GlassFish Support) org.netbeans.modules.profiler.j2ee.sunas
Java Profiler (Attach - JBoss Support) org.netbeans.modules.profiler.j2ee.jboss
Java Profiler (Attach Support) org.netbeans.modules.profiler.attach
Java Profiler (Attach - Tomcat Support) org.netbeans.modules.profiler.j2ee.tomcat
Java Profiler (Attach - WebLogic Support) org.netbeans.modules.profiler.j2ee.weblogic
Java Profiler (Attach Wizard) org.netbeans.modules.profiler.attach.impl
Java Profiler (Charts) org.netbeans.modules.websvc.saas.ui
Java Profiler (Common) org.netbeans.modules.websvc.saas.kit
Java Profiler (Java Freeform Projects Support) org.netbeans.modules.websvc.saas.services.strikeiron
Java Profiler (Java SE Projects Support) org.netbeans.modules.websvc.saas.services.twitter
Java Profiler (JFluid) org.netbeans.modules.websvc.saas.services.weatherbug
Java Profiler (JFluid-UI) org.netbeans.modules.websvc.saas.services.yahoo
Java Profiler (NetBeans Module Projects Support) org.netbeans.modules.websvc.saas.services.zillow
Java Profiler (OQL) org.netbeans.modules.websvc.saas.services.zvents
Java Profiler (OQL Language Support) org.netbeans.modules.websvc.saas.services.zvents
Java Profiler (Project Support) org.netbeans.modules.websvc.saas.services.zvents
Java Profiler (Root Method Selector - Java Project) org.netbeans.modules.websvc.saas.services.zvents
Java Profiler (Root Method Selector SPI) org.netbeans.modules.websvc.saas.services.zvents
Java Profiler (Root Method Selector UI) org.netbeans.modules.websvc.saas.services.zvents
Java Profiler (Snapshots Tracer) org.netbeans.modules.websvc.saas.services.zvents
Java Profiler (Utilities) org.netbeans.modules.websvc.saas.services.zvents
JPDA Debugger Heap Walker org.netbeans.modules.websvc.saas.services.zvents
Maven Profiler org.netbeans.modules.websvc.saas.services.zvents

Getting support, where to find examples

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.

Examples of how to use various APIs

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 samples/ subdirectory.

The platform/samples/ folder can be browsed online here. But for really trying things out it is usually more useful to have a local copy - then you can open them as projects in the IDE.

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:

Can I get training material for the NetBeans Certification course?

This is a wiki page for NetBeans Certified Engineer Course, read more at our main website.


Exercises/Assignments
Papers
Slides from the Training on the First Day


Slides from the Training on the Second Day

Development issues, module basics and classpath issues, and information about RCP/Platform application configuration

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.8 and above

How do module dependencies/classloading work?

The nuts and bolts of module dependencies are as follows:

What this means is that if

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.8 and above

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

What classloaders 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.8 and above

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.

Note: An (untested) possible workaround is to first call UIManager.put ("ClassLoader", Lookup.getDefault().lookup(ClassLoader.class)).

Applies to: NetBeans 6.8 and above

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.

Since NetBeans 6.8 you can add, remove and assign sources and Javadoc to wrapped libraries in Project Properties dialog, Libraries / Wrapped JARs tab.

Advanced stuff

Before NB 6.8 you could 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.8 and later

See also

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:

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.

Since NetBeans 6.9 NBM files now supports pack200 compression and all jar files in NBMs becomes compressed and have ".pack.gz" appended to the name e.g. modules/org-netbeans-modules-hexeditor.jar.pack.gz.

For more info about pack200 usage see DevFaqNBMPack200.

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

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

Isn't there an easier way?

Of course. Based on the above notes this script has been contributed by our community. Just put this in your suite's build.xml file:

    <target name="-init" depends="suite.-init,init-netbeans,init-hudson">
        <!--Create/Update keystore-->
        <delete file="${keystore.location}${keystore.name}"/>
        <mkdir dir="${keystore.location}"/>
        <genkey alias="${keystore.alias}" storepass="${keystore.password}"
        dname="${keystore.dname}"
        keystore="${keystore.location}${keystore.name}"/>
        <!--Update keystore info in projects-->
        <antcall target="update-keystore-info"/>
    </target>

    <target name="update-keystore-info">
        <for list="${modules}" delimiter=":" param="cur" trim="true">
            <sequential>
                <mkdir dir="@{cur}/nbproject/"/>
                <!--Place the information in the properties file-->
                <propertyfile file="@{cur}/nbproject/project.properties">
                    <entry  key="keystore" value="../${keystore.location}${keystore.name}"/>
                    <entry  key="nbm_alias" value="${keystore.alias}"/>
                </propertyfile>
                <mkdir dir="@{cur}/nbproject/private/"/>
                <!--Place the password in the private properties file-->
                <propertyfile file="@{cur}/nbproject/private/platform-private.properties">
                    <entry  key="storepass" value="${keystore.password}"/>
                </propertyfile>
            </sequential>
        </for>    
</target>

The script use ant-contrib library so make sure to have it available.

You can import it using one of the following:

1. If the ant-contrib-x.jar is in ant directory:

<taskdef resource="net/sf/antcontrib/antcontrib.properties"/>

2. Otherwise:

        <taskdef resource="net/sf/antcontrib/antcontrib.properties">
            <classpath>
                <pathelement location="path/to/ant-contribx.jar"/>
            </classpath>
        </taskdef>

Also you'll need this values defined in your suite's project.properties file:

keystore.dname=CN=x, OU=x, O=x, C=x
keystore.location=x/
keystore.name=x
keystore.alias=x
keystore.password=x

Just replace x with the desired value.

Great! Can you translate that?

Ok, here's a summary:

1. Create a keystore with genkey task.

2. Using the defined module list (${modules} this is defined by the IDE itself) go to all your modules and add the keystore location and alias information in its nbproject/private/platform-private.properties file.

3. Call Netbeans build task so everything keeps going.

Enjoy!

Applies to: NetBeans 6.8 and above

What is an SPI? How is it different from an API?

API is a general term - an acronym for Application Programming Interface - it means something (in Java, usually some Java classes) a piece of software exposes, which allows other software to communicate with it.

SPI stands for Service Provider Interface. It is a subset of all things that can be API specific to situations where a library is providing classes which are called by the application (or API library), and which typically change the things the application is able to do.

The classic example is JavaMail. Its API has two sides:

Users of the API rarely need to see or talk to the SPI classes, and vice-versa.

In NetBeans, when you see the term SPI, it is usually talking about classes that a module can inject at runtime which allow NetBeans to do new things. For example, there is a general SPI for implementing version control systems. Different modules provide implementations of that SPI for CVS, Subversion, Mercurial and other revision control systems. However, the code that deals with files (the API side) does not need to care if there is a version control system, or what it is.

More on API and SPI

My module requires JDK 6 - how do I keep it from being loaded on an older release?

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

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 the Java SE project and then pick up the JAR from the Java SE project's original location. This method provides source association (even if the Java SE project is not open!). You modify a few things in the wrapper project

  1. project.xml
    adjust the <class-path-extension>
  2. project.properties
    specify extra.module.files
  3. remove the wrapper's release directory
  4. build.xml
    to override the release target

The following example demonstrates these steps. harness/README gives the details. See also Issue 70894, which would make it easier.

Example using method 2: 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}" usenativebasedir="true"
         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}" usenativebasedir="true"
         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?

With the library wrapper creation wizard it's possible to choose more than one jar (use the CTRL key to select more than one file in the file dialog). Or enter absolute file paths divided by the path separator (e.g. ; for windows systems) into the (very small) file input field.

To add later more, use the project's properties dialog.

Applies to: NetBeans 6.8 and later

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 and since NetBeans 6.8 it is similarly easy to either edit Library Wrapper Module after it has been created or package library directly to your module via Project Properties > Libraries > Wrapped JARs.

Before NB 6.8 it was more convenient to create Library Wrapper module due to existence of the wizard, but not Project Properties UI. This biased the answer to this question, 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:

  • If it is something very esoteric and your module will be the only module in an installation of NetBeans (or your NetBeans-based app) ever using it
  • You are writing only one module that will use the library, or you want to declare the packages contained in your library in the public packages of your module
  • If you will never want deliver an update of that library by itself, without delivering an update of your module
  • If you wrote the library you want to use
  • You might just want to add the appropriate OpenIDE-Module-* entries directly to its manifest and make it a module that way. Remember to list the packages your module will need to export.
  • Else, you probably want to read DevFaqWrapperModules

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.8 and above

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 [SeeNoteRegardingNormalizedNames]
OSR: 1234 [OSRNumber,ReferToLFIPreviously;SunInternalLegal]
Origin: http://www.xyz.org [WhereFile(s)WereDownloadedFrom]
Files: xyz.jar, xyz-doc.zip, xyz-src.zip [Optional;SeeBelowForExplanation]
Source: URL to source [MandatoryForLGPL,OtherwiseOptional]
Comment: needed until NB runs on JDK 6+ [Optional:WhyIsThisLibraryHere]

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

[TEXTOFTHELICENSE]

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):

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</tt>; \
  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.8 and above

How do I add native libraries?

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.8 and above

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 JAR manifest (which is normally constructed from nbproject/project.xml in sources):

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

My module uses class XYZ 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 to 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

What is a module cluster?

A cluster is a directory on disk. A cluster contains modules. If you are writing a small NetBeans-based application, you probably do not need to be too concerned about clusters, although you may encounter the concept if you need to bundle additional files (native executables, for example) with a module. Clusters become important if you are writing an extensible application (or multiple applications) of your own, where you are sharing some common modules between multiple applications.

The NetBeans launcher is passed a list of cluster directories on startup (see $NB_HOME/etc/netbeans.clusters in the IDE - the names in this file are relative paths from the IDE install directory - but they could also be absolute paths on disk). The launcher looks for the modules (JAR files) which it should load in those "cluster directories". A NetBeans-based application typically consists of, at a minimum, the platform cluster and at least one application-specific cluster which contains modules that implement the business logic of that application.

Cluster directories are not necessarily all located under the same parent directory. They just happen to be in a typical NetBeans IDE install.

The NetBeans platform expects cluster directories to have a certain minimal structure:

A cluster may contain additional files and folders as needed. For example, it is common for modules which bundle 3rd-party libraries to include those JAR files in modules/ext/. A cluster can contain whatever other files a module needs at runtime - for example, a module that installs a mobile phone emulator would probably include the native emulator executable.

To include additional files in your cluster, simply create a directory release/ underneath your module's project directory (not the src/ directory for your module, but its parent folder - the one that is your module project). Anything under $PROJECT/release/ will be copied into your cluster by the build process. To find the file at runtime, use InstalledFileLocator, e.g.

File emulatorBinary = InstalledFileLocator.getDefault().locate(
  "phone/bin/emulator.exe", "com.foo.my.module.code.name", false);
Suites vs. Clusters

The result of compiling a module suite is typically a cluster. A cluster is something the runtime understands; a suite is a a project you develop. For more information see the suite-versus-cluster FAQ.

Why Have Clusters?

Here's the history of clusters:

In short, while it is typical for all of the parts of an application to be under a common parent directory, that is neither required nor guaranteed.

What Does A Cluster Look Like?

Here is the structure of the (comparatively small - it contains only one module) ergonomics cluster in a NetBeans 6.9 development build.

In a larger cluster, all of the child directories described above would contain one file for each module (i.e. module JAR file, etc.).

Metadata

The metadata in $CLUSTER/config/Modules/$MODULE.xml is fairly simple and straightforward - it enables the NetBeans module-system to determine when a module should be loaded:

<?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&quot;>
<module name="org.netbeans.modules.ide.ergonomics">
    <param name="autoload">false</param>
    <param name="eager">false</param>
    <param name="enabled">true</param>
    <param name="jar">modules/org-netbeans-modules-ide-ergonomics.jar</param>
    <param name="reloadable">false</param>
</module>

Similarly, the metadata in $CLUSTER/update_tracking/$MODULE.xml contains data about the module generated when it is installed:

<?xml version="1.0" encoding="UTF-8"?>
<module codename="org.netbeans.modules.ide.ergonomics">
    <module_version install_time="1266357743218" last="true"
                    origin="installer" specification_version="1.7">
        <file crc="3871934416"
              name="config/Modules/org-netbeans-modules-ide-ergonomics.xml"/>
        <file crc="1925067367"
              name="modules/org-netbeans-modules-ide-ergonomics.jar"/>
    </module_version>
</module>

This data allows the Tools > Plugins updater functionality to determine if the version of the module on an update server is a newer version than the copy which the user has installed, so that it can decide if it should offer an update. More importantly, since this is done with checksums, it can do this check without sending data about what is on the user's machine to a remote server, users privacy is maintained.

Clusters and Compatibility

A cluster is a compatibility unit and has a version. It is set of modules that is developed by the same group of people, built and released at one time.

Most of the reasoning that lead to creation of the concept can be found in: Installation Structure

What is the difference between a suite and a cluster?

A suite is a project which bundles together a number of module projects, lets you build them all together, and puts the resulting JARs in a directory structure the NetBeans Platform understands.

That directory structure is a cluster. A cluster is a directory structure which the application launcher and module system understand. A cluster is a runtime artifact where the module system can find the modules that make up an application.

While it is common to think of a suite as being a cluster (the build product of a suite is a cluster, after all), they are not the same thing.

Suites

A suite is a container project used to group module projects into a unit whose members can depend on one another, and also depend on a copy of the NetBeans platform.

The structure generated on disk when you compile a suite project is a cluster.

If you are creating a single module (perhaps an IDE extension or a very simple NetBeans Platform-based application) you can ignore suites, and just build/run/distribute a single stand-alone module. You will still get a cluster structure on disk when you compile the module. However, suite projects offer some additional features, such as building zip and JNLP application distributions.

You can always start with a stand-alone module project and later create a suite project and add your module to the suite. If you are going to bundle multiple third-party libraries, and want the ability to provide updates of those libraries, you probably want a suite.

Inter-suite Dependencies

A suite may depend on

See DevFaqHowToReuseModules for more details.

Clusters

A cluster is typically a subdirectory of a NB-based application's binary installation. Every module in the installation lives in one (and only one) cluster. For details on the structure of clusters, see DevFaqWhatIsACluster.

The installation is divided into clusters for purposes of:

  1. Conceptual clarity.
  2. Mapping to native packaging systems such as RPM, Debian/Ubuntu packages, Solaris packages, etc.

The NetBeans team has a policy of treating inter-cluster module dependencies as more significant than intra-cluster module dependencies with respect to backward compatibility. The goal is to make it possible for product teams building on top of the NetBeans IDE to select a subset of the IDE to use—with cluster granularity rather than with module granularity.

Cluster-granularity is simpler to grasp and integrate with native packaging (if the NetBeans IDE consisted of 500 Debian packages, nobody would be particularly happy about that). But there is nothing preventing you from reusing a subset with module granularity.

The NetBeans 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. The entire contents of the platform cluster may not be exactly what you want for every "platform" application, so a suite project allows you to exclude modules you do not wish to include.

Clusters are supposed to be medium-grained or coarse-grained, unlike modules which are generally fine-grained units.

See also:

No Suites In NetBeans IDE Sources

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

The resulting build artifacts are, nonetheless, clusters. These clusters are simply built using a different build-infrastructure, where the cluster names and contents are defined in .properties files in $NB_SRC/nbbuild/.

How can I reuse my modules in several RCP applications?

Assuming you are using version 6.8 or later, this is supported by the module development infrastructure:

  1. Open Suite B in the IDE
  2. Right-click on Suite B in the IDE
  3. Click properties
  4. Click libraries on the left of the suite properties dialog
  5. Click 'Add project...' at the bottom of the suite properties dialog
  6. Locate the directory containing the source code for Suite A

You can then select which modules from suite A you want to include in suite B.

Source: posting by Tom Wheeler

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

It's possible to use non-netbeans.org modules (yours or 3rd party) directly in your suite and perform this configuration via the GUI. To do this, go to the Properties of your suite project, Libraries tab:

[image - see online version]

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

If you want to use 3rd party binary modules, just unpack them into a 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 a team environment easier. Then click the Add Cluster... button and browse for the cluster folder:

[image - see online version]

You can also add sources and/or Javadoc for binary modules, just like for the 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.

Using an Update Center for a Stand Alone Module

This was suggested as a patch but rejected (https://netbeans.org/bugzilla/show_bug.cgi?id=185283)

Add the following to the module's build.xml file:

<target name="create-update-center" depends="harness.taskdefs, nbm">
        <mkdir dir="${update.dir}"/>
        <pathfileset id="updater.jar">
            <path refid="cluster.path.id"/>
            <filename name="modules/ext/updater.jar"/>
        </pathfileset>
        <makeupdatedesc desc="${update.dir}/updates.xml" distbase="."
automaticgrouping="true" uselicenseurl="${use.license.url.in.catalog}">
            <fileset dir="./build">
                <include name="*.nbm"/>
                <include name="*.jar"/>
            </fileset>
            <updaterjar>
                <resources refid="updater.jar"/>
            </updaterjar>
        </makeupdatedesc>
        <!--Copy the files to the folder-->
        <copy todir="${update.dir}">
            <fileset dir="./build">
                <include name="*.nbm"/>
                <include name="*.jar"/>
            </fileset>
        </copy>
    </target>

This will create an update center for the stand alone module!

Note: Nothing magic about it. Just used the Netbeans task makeupdatedesc. Feel free to change the target name and change ./build with something smarter (I couldn't find a pre-defined variable for that in the stand alone modules).

Can I use modules from update center in my RCP application?

Assuming you are using version 6.8 or later, this is supported by the module development infrastructure:

  1. Open Suite B in the IDE
  2. Right-click on Suite B in the IDE
  3. Click properties
  4. Click libraries on the left of the suite properties dialog
  5. Click 'Add project...' at the bottom of the suite properties dialog
  6. Locate the directory containing the source code for Suite A

You can then select which modules from suite A you want to include in suite B.

Source: posting by Tom Wheeler

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

It's possible to use non-netbeans.org modules (yours or 3rd party) directly in your suite and perform this configuration via the GUI. To do this, go to the Properties of your suite project, Libraries tab:

[image - see online version]

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

If you want to use 3rd party binary modules, just unpack them into a 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 a team environment easier. Then click the Add Cluster... button and browse for the cluster folder:

[image - see online version]

You can also add sources and/or Javadoc for binary modules, just like for the 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.

Using an Update Center for a Stand Alone Module

This was suggested as a patch but rejected (https://netbeans.org/bugzilla/show_bug.cgi?id=185283)

Add the following to the module's build.xml file:

<target name="create-update-center" depends="harness.taskdefs, nbm">
        <mkdir dir="${update.dir}"/>
        <pathfileset id="updater.jar">
            <path refid="cluster.path.id"/>
            <filename name="modules/ext/updater.jar"/>
        </pathfileset>
        <makeupdatedesc desc="${update.dir}/updates.xml" distbase="."
automaticgrouping="true" uselicenseurl="${use.license.url.in.catalog}">
            <fileset dir="./build">
                <include name="*.nbm"/>
                <include name="*.jar"/>
            </fileset>
            <updaterjar>
                <resources refid="updater.jar"/>
            </updaterjar>
        </makeupdatedesc>
        <!--Copy the files to the folder-->
        <copy todir="${update.dir}">
            <fileset dir="./build">
                <include name="*.nbm"/>
                <include name="*.jar"/>
            </fileset>
        </copy>
    </target>

This will create an update center for the stand alone module!

Note: Nothing magic about it. Just used the Netbeans task makeupdatedesc. Feel free to change the target name and change ./build with something smarter (I couldn't find a pre-defined variable for that in the stand alone modules).

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.8 and above

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. As an alternative, you can work on "orphan" modules from the netbeans.org source base (Issue 143236 has details). 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.
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 the 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

Applies to: NetBeans 6.8 and above

Is there a standard way to provide user documentation (help) 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

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+

There is a class under org.netbeans.core that does what I need. Can I 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.8 and above

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.8 and above

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 ide/modules/org-openide-example.jar you make a JAR like ide/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

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.

The simplest way to set this up is to use Tools > NetBeans Platform Manager in IDE add/switch to the platform you want to change and select harness on Harness tab. Note that in-IDE module development support defaults to using the harness included with the IDE, ignoring the harness bundled with the platform. You can also configure your module or suite manually 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

I am developing a NetBeans module. What performance criteria should it satisfy?

All NetBeans modules should behave responsibly with regard to performance. They must not affect startup time negatively, they must not increase memory footprint significantly, and they must be responsive at all times.

Applies to: NetBeans 6.5 and above

Platforms: All

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 and above

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 through 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. See also FitnessMemoryLeaks.

Timers/counters module can be used to register objects of interest in the code, then inspect them during IDE run via Runtime Watches window.

Advanced: 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 and above

Platforms: All

What is a WeakListener?

When you attach a listener to another object, via, for example, an addPropertyChangeListener() method, that other object now holds a reference to that listener.

In Java, any object that is referenced by another object which is still in use (i.e. referenced by something else that is still alive, and so forth) cannot be garbage collected. One of the most frequent sources of memory leaks in Swing applications is attaching a listener to some long-lived object and never detaching the listener. The entire object graph of the listener and anything it references is held in memory, whether it is needed or not, until the object being listened to is finally garbage collected.

Since listeners are often implemented as inner (non-static) classes of some other object, and an inner class keeps a reference to the object that created it, the outer object instance is kept in memory too.

WeakListeners is a factory class which wraps your event listener in another one, but it only weakly (using java.lang.ref.WeakReference) references your actual listener. That means that, even though you are listening for changes, that will not block your listener from being garbage collected if nothing else still references it.

There is one caveat to using WeakListeners - if you do something like this:

someObject.addPropertyChangeListener(WeakListeners.propertyChange(new PropertyChangeListener() {
   public void propertyChange(PropertyChangeEvent evt) {
     ...
   }
}, someObject);

in fact you are not listening on someObject for any amount of time - the anonymous PropertyChangeListener you created will be instantly garbage-collected. So keep a reference to your listener when using WeakListeners.

When should I use a WeakListener?

You should use a WeakListener any time you are adding a listener to an object, but there is no code - and possibly no opportunity - to explicitly remove it.

If the thing you are listening to does have some kind of observable life-cycle, it is preferable to explicitly add and detach listeners.

But in the case that you are adding a listener which is never explicitly removed, it is good form to use WeakListeners

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:

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

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/platform/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 and above

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:

This property is set by default when you:

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 can I customize the build process?

Problem: Customization of the build process is not documented properly

Solution:

<target name="-init" depends="suite.-init,custom-task1,...">
        <!--Perform your actions here-->
</target>

The key part is calling the suite.-init task as it initializes a lot of stuff used by the rest of the process. Depending on which things you need to initialize, this target may not work and you may need to pick another one; look at what common.xml in the harness is initializing when.

Applies to: NetBeans IDE 6.8 and 6.9 Platforms: All See also DevFaqSignNbm for an example using this.

How can I customize the default project directory for my application, replacing "NetBeansProjects"?

You configure such things either in the launcher (netbeans.conf for the NB IDE, some other *.conf for a custom app), or at runtime in a ModuleInstall.

File userDir = new File(System.getProperty("user.home"));
File myProjectsDir = new File(userDir, "My Projects");
if (!myProjectsDir.exists()) {
    myProjectsDir.mkdirs();
}
System.setProperty("netbeans.projects.dir", myProjectsDir.getAbsolutePath());

Source:

http://osdir.com/ml/java.netbeans.modules.openide.devel/2007-12/msg00195.html

Migrating to a newer version of the Platform

[no content found]

How can I launch an Ant Task on all modules of my suite?

I needed to launch the fix-dependencies target on all the modules of my suite, but doing manually is very boring. So I added this target into my suite build.xml that runs the target in each module

<target name="fix-dependencies" depends="-init">

       <subant target="fix-dependencies" buildpath="${modules.sorted}" inheritrefs="false" inheritall="false"/>

</target>

You can change the code so it works with any target.

Applies to: NetBeans IDE 6.5 and newer Platforms: All

Configuration: How Modules Install Things

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, using this annotation is the preferred technique.

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. At build-time, registration files are generated into META-INF/services in your module's JAR file. The default lookup (or JDK 6's ServiceLoader) knows how to read such files. Typically the classes need to be public and have a public no-argument constructor.

Any module can specify interfaces or classes that it would like other modules to implement and register instances of. For example, the Project API module asks that each module that implements a project type (the things you see in the New Project wizard in NetBeans) register their ProjectFactorys in default lookup.

To get an instance of something registered this way, call

TheInterface i = Lookup.getDefault().lookup(TheInterface.class);

If there might 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 configuration when registering objects. It is a virtual filesystem composed of XML fragments (see DevFaqModulesLayerFile) from 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; which folders exist and are meaningful depends on which modules you have installed. For example, the core window system defines the folder Menu/, which contains one subfolder 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 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.7 and later

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. (In JDK 6, ServiceLoader operates on the same principle.) The default lookup searches in two places:

Objects contained in the default lookup are instantiated lazily when first requested. Objects returned by the default lookup may (or may not) be garbage collected if they become unreferenced.

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 and later

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 and later

What is an XML 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 (DevFaqFileObject) and FileSystems (DevFaqFileSystem), 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

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

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 an empty 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:

There are several things which affect how objects are used, all or some of which may be specified by a module's API:

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 and newer

How can I see the filesystem?

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 6.7 and later

What are .instance files?

*.instance files represent an "instance", i.e. arbitrary Java 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(FileUtil.getConfigFile(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.7 and later

What are .settings files?

.settings files are similar to .instance files, with the difference that they are XML format, and can contain serialized data rather than just default instances.

Since 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 to persist the state of opened windows/tabs (caret position, what file is opened, or other state that should be restored when reopening a TopComponent after a restart) across application runs.

A .settings file can encode the entire parent class and interface hierarchy of the object it represents, so that a query about whether an object of a given type is present (such as using Lookups.forPath("path/to/folder").allItems()) can be answered without actually creating an instance of the object.

Settings files are also useful if you are declaring some objects in a layer file (see DevFaqModulesLayerFile) and intend to write them back out to disk after they have been modified in-memory (note this involves writing ugly and inefficient hexadecimal-encoded serialized data into XML files - if the object is a singleton, using NbPreferences will be both more efficient and more readable).

Example
<?xml version="1.0"?>
<!DOCTYPE settings PUBLIC "-//NetBeans//DTD Session settings 1.0//EN"
                          "http://www.netbeans.org/dtds/sessionsettings-1_0.dtd">
<settings version="1.0">
    <module name="org.netbeans.core.io.ui/1" spec="1.6"/>
    <instanceof class="org.openide.windows.TopComponent"/>
    <instanceof class="org.netbeans.core.io.ui.IOWindow$IOWindowImpl"/>
    <serialdata class="org.netbeans.core.io.ui.IOWindow$IOWindowImpl">
        ACED0005737200296F72672E6F70656E6964652E7...
    </serialdata>
</settings>

What are .shadow files?

*.shadow files are mainly used in the system filesystem 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 is created in the module's layer file, 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.

Creating Shadow Files Programmatically

If you need to create .shadow files programmatically, use DataShadow.create() — do not write FileObjects and try to set attributes on them. In an XML layer, a DataShadow's original file is pointed to by a file attribute. On disk, that is accomplished via the file's content instead. To reliably create DataShadows, let the infrastructure do it for you - do not make assumptions about how the original file is pointed to.

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.

Some new modules installed by Plugin Manager will also be installed here, as if it were a "cluster" directory (such as platform or similar in a NetBeans IDE or Platform installation). NBMs which specify a particular cluster name will not be placed in the user directory, however.

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 and later

How do I specify the order for my menu items/toolbar buttons/files in the system filesystem?

If you are using module development support the IDE, you can manage the order of menu or toolbar items by the help of special node XML Layer which can be found underneath your Important Files. Just find your menu/toolbar item and drag and drop it wherever you need. Appropriate content in the project metadata (layer file) will be generated for you. If this does not work, or you want to know more, read on.

FileObjects (DevFaqFileObject) in a folder have no defined order by default. You can use FileUtil.getOrder to sort them. (DataObjects (DevFaqDataObject) in a folder are always sorted this way.) The order is determined by numeric position attributes. For all details, see: FolderOrdering103187

Applies to: NetBeans 6.5 and later

Can I dynamically change the contents of the System Filesystem at runtime?

Yes. This technique is commonly used in platform applications which require the user to log in, to keep menu contents/toolbar actions/keyboard shortcuts/window definitions hidden until the user is authenticated.

There are two ways to do it. The most obvious way is to programmatically write files to disk at runtime (call FileUtil.getConfigRoot().createFolder(), etc.). This technique is appropriate if you are creating files which should be preserved across restarts (for example, adding folders to the Favorites window). It is completely inappropriate in the case of authentication, or any other case where you do not want the added files to be present after restart. You cannot depend on the application always being shut down normally and having a chance to clean such files up - since they are actually written to disk.

Using Dynamically Added Layers

The alternative is quite simple: Write a subclass of MultiFileSystem. Put it in the default lookup.

At runtime, when you want to add contents to the system filesystem, simply add additional filesystems to your MultiFileSystem. To remove the contents, simply remove those filesystems.

A convenient way to do this is to use XMLFileSystem - this is a filesystem created with exactly the same syntax as normal module XML layer files (see DevFaqModulesLayerFile). The following code loads an XML filesystem, which is in an XML file in the same package as the class, called dynamicContent.xml:

@ServiceProvider(service=FileSystem.class)
public class DynamicLayerContent extends MultiFileSystem {
    private static DynamicLayerContent INSTANCE;
    public DynamicLayerContent() {
        // will be created on startup, exactly once
        INSTANCE = this;
        setPropagateMasks(true); // permit *_hidden masks to be used
    }
    static boolean hasContent() {
        return INSTANCE.getDelegates().length > 0;
    }
    static void enable() {
        if (!hasContent()) {
            try {
                INSTANCE.setDelegates(new XMLFileSystem(
                        DynamicLayerContent.class.getResource(
                        "dynamicContent.xml")));
            } catch (SAXException ex) {
                Exceptions.printStackTrace(ex);
            }
        }
    }
    static void disable() {
        INSTANCE.setDelegates();
    }
}

If finer grained control of what is added is needed at runtime, there are two possibilities, using this general approach:

Can I bundle some additional files with my module? If so, how can I find those files to use them from my module?

Sometimes you need to bundle some additional files with your module (for example native libraries or native executables).

Bundling External File With Your Module

NetBeans provides a simple and straightforward way to bundle whatever files you want into a module project:

The result is:

Note: If you are bundling third party software which has its own installer there is a way to run that installer during module installation.

Finding External Files At Runtime

Now your module includes the files you need. You still need to get access to them at runtime.

To do that, use InstalledFileLocator. That is a class which can find a file which was installed by a module. You simply give it your module's code-name (the thing you typed when you created the module, which looks like a package name) and a relative path (i.e. not including the release/ directory):

File emulator = InstalledFileLocator.getDefault().locate(
    "javacard/bin/jcre.exe",
    "org.netbeans.modules.javacard.referenceimpl",
    false);

Always handle the case that the user (or disk crash, whatever) might have deleted it.

If you are wondering why you don't just find the directory NetBeans is installed in and look in that directory, see the background information about clusters

Actions: How to add things to Files, Folders, Menus, Toolbars and more

How do I add an action to the main menu?

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 an action to a toolbar in the main window?

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 make an action that is automatically enabled/disabled depending on what's selected?

There are several ways to do this, depending on what exactly you need. The basic problems all of the available solutions are addressing is that:

NetBeans 6.9 allows context-sensitive actions to be registered declaratively in your module's XML layer file. In the IDE, File > New File > Module Development > Action will generate some rather opaque layer-based registration code for you (on the first page of the wizard, specify that you want a context sensitive action):

    <file name="mypackage-SomeAction.instance">
      <attr name="delegate" methodvalue="org.openide.awt.Actions.inject"/>
      <attr name="displayName" bundlevalue="mypackage.Bundle#CTL_SomeAction"/>
      <attr name="injectable" stringvalue="mypackage.SomeAction"/>
      <attr name="instanceCreate" methodvalue="org.openide.awt.Actions.context"/>
      <attr name="noIconInMenu" boolvalue="true"/>
      <attr name="selectionType" stringvalue="ANY"/>
      <attr name="type" stringvalue="org.netbeans.api.project.Project"
/>
    </file>

and a somewhat inscrutable ActionListener implementation

 public final class SomeAction implements ActionListener {
   private final List<Project> context;
   public SomeAction(List<Project> context) {
     this.context = context;
   }
   public void actionPerformed(ActionEvent ev) {
     for (Project project : context) {
       // TODO use project
     }
   }
 }

which will be called if and only if one or more projects is selected. The good news is that the code is lightweight, simple and works; the bad news is that it is utterly non-obvious how it ever gets called, and doesn't handle more complicated enablement logic.

If you want to add this action into a context menu of a node you have to overwrite the getActions() method as follows:

 public Action[] getActions(boolean context) {
        List<? extends Action> myActions =
                Utilities.actionsForPath("Actions/YOUR_FOLDER");
        return myActions.toArray(new Action[myActions.size()]);
    }

If you need something more featureful, there are a few options, old and new:

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"));
        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();
        for (Whatever instance : lkpInfo.allInstances()) {
            // use it somehow...
        }
    }
 
    public void resultChanged(LookupEvent ev) {
        setEnabled(!lkpInfo.allInstances().isEmpty());
    }
 
    public Action createContextAwareInstance(Lookup context) {
        return new FooAction(context);
    }
}
Deprecated CookieAction

In many older (pre-NB 6.8) examples you may find CookieAction. It should be (but is not) deprecated. The original info is left here for reference and/or old code maintenance:

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.

Not-Yet-Official spi.actions

This module is part of the platform as of 6.8, but has not yet become official API (and nobody seems to be willing to make it stable API, so judge your own decisions based on this fact). Nonetheless it is there, it is not changing and straightforward to use. The example below opens a visual editor window if an instance of RAFDataObject is selected and has a RandomAccessFile in its lookup:

public final class CustomOpenAction extends org.netbeans.spi.actions.Single<RAFDataObject>
 {
    public CustomOpenAction() {
      super(RAFDataObject.class, "Open", null);
    }
    @Override
    protected void actionPerformed(RAFDataObject target) {
      //If an editor is already open, just give it focus
      for (TopComponent tc : TopComponent.getRegistry().getOpened()) {
        if (tc instanceof RAFEditor && tc.getLookup().lookup(RAFDataObject.class) == target) {
          tc.requestActive();
          return;
        }
      }
      //Nope, need a new editor
      TopComponent editorWindow = null;
      editorWindow = new RAFEditor(target);
      editorWindow.open();
      editorWindow.requestActive();
    }
    @Override
    protected boolean isEnabled(RAFDataObject target) {
      //Make sure there really is a file on disk
      return target.getLookup().lookup(RandomAccessFile.class) != null;
    }
  }

Use ContextAction instead of Single to create actions that operate on multi-selections.

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 and above

How do I add an action to all files 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 the text-editor popup menu?

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

<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 need to set an additional flag (available starting in 6.9).

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 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.filesystems.FileUtil;
import org.openide.util.ContextAwareAction;
import org.openide.util.Lookup;
public class DemoAction extends AbstractAction implements ContextAwareAction {
    public @Override void actionPerformed(ActionEvent e) {assert false;}
    public @Override Action createContextAwareInstance(Lookup context) {
        return new ContextAction(context);
    }
    private static final class ContextAction extends AbstractAction {
        private final Project p;
        public ContextAction(Lookup context) {
            p = context.lookup(Project.class);
            String name = ProjectUtils.getInformation(p).getDisplayName();
            // TODO state for which projects action should be enabled
            char c = name.charAt(0);
            setEnabled(c >= 'A' && c <= 'M');
            putValue(DynamicMenuContent.HIDE_WHEN_DISABLED, true);
            // TODO menu item label with optional mnemonics
            putValue(NAME, "&Info on " + name);
        }
        public @Override void actionPerformed(ActionEvent e) {
            // TODO what to do when run
            String msg = "Project location: "
                    + FileUtil.getFileDisplayName(p.getProjectDirectory());
            DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(msg));
        }
    }
}

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 6.9+

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

    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);
        }
    }
}
    1. Add these implementations to your project's lookup:
lookup = Lookups.fixed(
    // ... as before
    new AddActionOperation(this),
    new AddActionActions(this),
);
    1. 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;
}

See also: Common Project Actions

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 my custom node?

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 make my Node have a submenu on its popup menu?

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 and above Platforms: All

How do I add a dropdown menu to toolbar?

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

How do I add a dropdown menu to toolbar that is selectively enabled/disabled?

Create an Action as described in the general FAQ for to add a dropdown menu to a toolbar.

In this case, your action also needs to implement ContextAwareAction. A ContextAwareAction is a factory for other Action instances which are tied to a specific Lookup (so that, if selection changes after the popup menu for a Node is shown, the Action does not operate on the wrong object). You can start with a subclass of javax.swing.AbstractAction, and you will need two constructors:

private final Lookup lookup;
public MyAction() {
  this (Utilities.actionsGlobalContext());
}
 
private MyAction(Lookup lookup) {
  this.lookup = lookup;
  Icon icon = ImageUtilities.image2Icon(
    ImageUtilities.loadImage("com/foo/icon.gif"));
  putValue(SMALL_ICON, icon);
  //set the initial enabled state
  setEnabled(false);
}

You will also need to implement the one method of ContextAwareAction:

public Action createContextAwareInstance(Lookup actionContext) {
  return new MyAction(actionContext);
}

To enable and disable the action, we will need to listen on the lookup for the presence or absence of some object type. If it is there, the action will be enabled; if it is not, it will be disabled.

Since we do not want to start listening on the global selection context until something actually cares whether the action is enabled or not, so we will override add/removePropertyChangeListener() to notice that and listen or not.

First, we must modify our class signature to implement LookupListener:

public class MyAction extends AbstractAction implements ContextAwareAction, LookupListener, Presenter.Toolbar {
...

Now we will handle listening on the Lookup.Result. We want to stop listening to it when there are no PropertyChangeListeners left, so that our action can be garbage collected if not in use:

private LookupResult<? extends DataObject> res;
 
@Override
public synchronized void addPropertyChangeListener(PropertyChangeListener l) {
  boolean startListening = getPropertyChangeListeners().length == 0;
  super.addPropertyChangeListener(l);
  if (startListening) {
    res = lookup.lookupResult(MyType.class);
    res.addLookupListener(this);
  }
}
 
@Override
public synchronized void removePropertyChangeListener(PropertyChangeListener l) {
  super.removePropertyChangeListener(l);
  if (getPropertyChangeListeners().length == 0) {
    res.removeLookupListener(this);
    res = null;
  }
}

Now comes the actual implementation of LookupListener:

public void resultChanged(LookupEvent ev) {
  setEnabled(!res.allItems().isEmpty());
}

A bit of bookkeeping is required in getToolbarPresenter() - at least until issue 179814 is fixed, we will need to manually enable/disable the actions for our menu items:

  private final Set<Action> popupMenuActions = new WeakSet<Action>();
  @Override
  public Component getToolbarPresenter() {
    JPopupMenu menu = new JPopupMenu();
    Action actionOne = new DemoMenuAction("One");
    Action actionTwo = new DemoMenuAction("Two");
    menu.add(new JMenuItem(actionOne));
    menu.add(new JMenuItem(actionTwo));
    popupMenuActions.add(actionOne);
    popupMenuActions.add(actionTwo);
    //add action listeners to the menu items to do what you want
    Icon icon = (Icon) getValue(SMALL_ICON);
    JButton result = DropDownButtonFactory.createDropDownButton(icon, menu);
    result.setAction(this);
    return result;
  }
 
  @Override
  public void setEnabled(boolean enabled) {
    super.setEnabled(enabled);
    for (Action a : popupMenuActions) {
      if (a != null) { //WeakSet iterator can return null
        a.setEnabled(enabled);
      }
    }
  }
 
  private class DemoMenuAction extends AbstractAction {
    DemoMenuAction(String name) {
      putValue(NAME, name);
      setEnabled (MyAction.this.isEnabled());
    }
 
    @Override
    public void actionPerformed(ActionEvent e) {
      DataObject ob = res.allInstances().iterator().next();
      DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(
              ob.getName()));
    }
  }

If we want the drop-down button to do something when it is clicked on the right side (not in the popup area with the down-arrow), we can implement actionPerformed(ActionEvent) to do whatever that is.

For an older detailed example of manually creating a context-aware drop-down toolbar button (without DropDownButtonFactory, circa NetBeans 6.0), see see this post, posted in on the old dev@openide NetBeans mailing lists.

How do I hide/show toolbar dynamically?

To hide/show a toolbar dynamically in the NetBeans Platform, you should predefine a toolbar configuration first, then activate it.

1. Define toolbar configuration files alongside the module's layer: Standard.xml:

<?xml version="1.0"?>
<!DOCTYPE Configuration PUBLIC "-//NetBeans IDE//DTD toolbar//EN"
 "http://www.netbeans.org/dtds/toolbar.dtd">
<Configuration>
    <Row>
        <Toolbar name="View" />
        <Toolbar name="Control" />
        <Toolbar name="Indicator" />
        <Toolbar name="Draw" />
        <Toolbar name="Memory" />
    </Row>
    <Row>
        <Toolbar name="File" position="2" visible="false" />
        <Toolbar name="Edit" position="2" visible="false" />
        <Toolbar name="Build" position="2" visible="false" />
        <Toolbar name="Debug" position="2" visible="false" />
        <Toolbar name="Versioning" position="2" visible="false" />
    </Row>
</Configuration>

Developing.xml:

<?xml version="1.0"?>
<!DOCTYPE Configuration PUBLIC "-//NetBeans IDE//DTD toolbar//EN"
"http://www.netbeans.org/dtds/toolbar.dtd">
<Configuration>
    <Row>
        <Toolbar name="View" />
        <Toolbar name="Control" />
        <Toolbar name="Indicator" />
        <Toolbar name="Draw" />
        <Toolbar name="Memory" />
    </Row>
    <Row>
        <Toolbar name="File" position="2" />
        <Toolbar name="Edit" position="2" />
        <Toolbar name="Build" position="2" />
        <Toolbar name="Debug" position="2" visible="false" />
        <Toolbar name="Versioning" position="2" visible="false" />
    </Row>
</Configuration>

2. Register the configuration files in layer.xml:

<?xml version="1.0"?>
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.0//EN"
 "http://www.netbeans.org/dtds/filesystem-1_0.dtd">
<filesystem>
    <folder name="Toolbars">
        <file name="Standard.xml" url="Standard.xml"/>
        <file name="Developing.xml" url="Developing.xml"/>
    </folder>
</filesystem>

3. At runtime, set the toolbar configuration that you want:

ToolbarPool.getDefault().setConfiguration("Developing");

Some module in the IDE etc. already has a menu item I like, but I just want to rename it. Can I?

If you are creating a custom application (e.g. Standalone Application in suite project properties) you specify a branding for the application. You can then override localized text strings from platform modules without modifying those modules directly; the overrides will be active whenever your branding is selected (this part is taken care of for you by the suite build harness). You will need to locate the module which defines the menu item and find the localized Bundle.properties which gives a label for it. Then you can create a file in your suite project like

branding/modules/jarname.jar/path/Bundle.properties

containing definitions of overridden labels.

When you enable branding on a suite the IDE automatically brands a few bundle strings for the main window title and so on, so you can look at these files for examples.

See also Technical details

Applies to: NetBeans 5.0, 5.5, 6.x

Can I change the contents of a menu according to the selected file in the editor, or hide or show a whole menu?

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.

Note that to hide the Navigate menu one has to declare GoTo_hidden instead of Navigate_hidden (the menu was originally named GoTo, but was later renamed to Navigate by the means of Bundle.properties).

Can I install submenus into popups or other menus, instead of a regular action?

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 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 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. It must be also added to the suite (your suite > Project properties, Libraries > ide > User Utilities)

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

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

How do I remove Menu Item, Toolbar Button from plug-in's XML Layer?

Refer to TaT_HackingNetBeansXMLLayerPartOne for more details on where to use the following tricks.

Trick #1
<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
<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
<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
<folder name="Actions">
    <folder name="Tools">        
        <file name="org-nvarun-tat-SayCheez.instance"/>
    </folder>
</folder>
<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>
<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>
<folder name="Shortcuts">
    <file name="O-F3.shadow">
        <attr name="originalFile"
              stringvalue="Actions/Tools/org-nvarun-tat-SayCheez.instance"/>
    </file>
</folder>
Trick #2
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.)

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 do I invoke the IDE-Log upon Startup?

Problem: In a NetBeans Platform application, it is conceivable that the Output window's only use could be to show logging messages to the user. In this case, since the Output TopComponent is always persisted, and the IDE log is only attached via an Action, the Action should be invoked whenever the Output window is open.

Solution: We can create an Installer class which will search for the existence of the Output window, and conditionally fire the action which attaches the IDE Log.

Waiting for the Windows System to be ready

Installer classes (those that extend ModuleInstall) will fire their restored() methods before the Windows System is available. This is a problem, since we need to be able to interrogate the TopComponent.Registry to determine if the Output window is open.

The answer is to use the WindowManager.getDefault().invokeWhenUIReady() method.

    @Override
    public void restored()
    {
        //The TopComponent we're interested in isn't immediately available. 
        //This method allows us to delay start of our procedure until later.
        WindowManager.getDefault().invokeWhenUIReady(new Runnable()
        {
            @Override
            public void run()
            {
                 //Do something
            }
        });
    }
Finding the Output TopComponent

We find the Output TopComponent by the WindowManager.getDefault().findTopComponent() method. We must know the ID of the TopComponent we are searching for. In this case, it is "output".

            @Override
            public void run()
            {
                //Locate the Output Window instance                
                final String OUTPUT_ID = "output";
                TopComponent outputWindow = WindowManager.getDefault().findTopComponent(OUTPUT_ID);
Determining if the Output window is open

This is easily accomplished by using the methods of the TopComponent class.

               if (outputWindow != null && outputWindow.isOpened())
Locating our Action from the System Filesystem (Layer)

We can get a Lookup for a portion of the System Filesystem using Lookups.forPath(). Browse your layer file in context to determine where the instance of the action is stored. In our case, it is in Actions/View.

                   final String FOLDER = "Actions/View/";
                   Lookup pathLookup = Lookups.forPath(FOLDER);
Getting the Instance from our Lookup

Now that we have a lookup to the appropriate folder of the System Filesystem, we need to know the instance file name of the Action we want to retrieve and invoke. We get this information from browsing our layer file in context. In our case, it is "org-netbeans-core-actions-LogAction". We construct a Lookup.Template, naming the ID of the item. We can then use this Template to obtain a Lookup.Result, and finally our instance. We then invoke actionPerformed() to fire the action.

                    final String INSTANCE_FILE = "org-netbeans-core-actions-LogAction";
                    Template<Action> actionTemplate = new Template<Action>(Action.class, FOLDER + INSTANCE_FILE, null);
                    Result<Action> lookupResult = pathLookup.lookup(actionTemplate);
                    Collection<? extends Action> foundActions = lookupResult.allInstances();

                    //For each instance (should ony be one) call actionPerformed()
                    for (Action action : foundActions)
                    {
                        action.actionPerformed(null);
                    } 
Putting it all together

Here is the completed Installer class, with logging.

/**
 * This class makes it so that the action View/IDE-Logs is performed upon startup
 * whenever the Output window is open.
 */
public class ViewLogsInstaller extends ModuleInstall
{
    private static final Logger logger = Logger.getLogger(ViewLogsInstaller.class.getName(), ViewLogsInstaller.class.getPackage().getName() + ".Log");

    @Override
    public void restored()
    {
        //The TopComponent we're interested in isn't immediately available. 
        //This method allows us to delay start of our procedure until later.
        WindowManager.getDefault().invokeWhenUIReady(new Runnable()
        {
            @Override
            public void run()
            {
                //Locate the Output Window instance                
                final String OUTPUT_ID = "output";
                logger.log(Level.FINE, "LOG_FindingWindow", OUTPUT_ID);
                TopComponent outputWindow = WindowManager.getDefault().findTopComponent(OUTPUT_ID);
                
                //Determine if it is opened
                if (outputWindow != null && outputWindow.isOpened())
                {
                    logger.log(Level.FINE, "LOG_WindowOpen", OUTPUT_ID);
                    final String FOLDER = "Actions/View/";
                    final String INSTANCE_FILE = "org-netbeans-core-actions-LogAction";

                    //Use Lookup to find the instance in the file system
                    logger.log(Level.FINE, "LOG_LookupAction", new Object[]{FOLDER, INSTANCE_FILE});
                    Lookup pathLookup = Lookups.forPath(FOLDER);
                    Template<Action> actionTemplate = new Template<Action>(Action.class, FOLDER + INSTANCE_FILE, null);
                    Result<Action> lookupResult = pathLookup.lookup(actionTemplate);
                    Collection<? extends Action> foundActions = lookupResult.allInstances();
                    
                    //For each instance (should ony be one) call actionPerformed()
                    for (Action action : foundActions)
                    {
                        logger.log(Level.FINE, "LOG_FoundAction", action);
                        action.actionPerformed(null);
                    } 
                }
                else
                {
                    logger.log(Level.FINE, "LOG_WindowClosed", OUTPUT_ID);
                }
            }
        });
    }
}
Log.properties file

Place this file in the root package of your installer.

LOG_FindingWindow=Attempting to locate TopComponent with ID ''{0}''
LOG_WindowOpen=TopComponent with ID ''{0}'' is open
LOG_LookupAction=Attempting to find Action instance at {0}{1}
LOG_FoundAction=Found Action ''{0}''; calling actionPerformed()
LOG_WindowClosed=TopComponent with ID ''{0}'' is closed or not instantiated

Lookup

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 Openable - 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:

Lookup selectedContext = Utilities.actionsGlobalContext();
Openable o = selectedContext.lookup(Openable.class);
if (o != null) {
  o.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 Openable. So either one can be replaced without affecting the other at all.

This brings the MVC design pattern into modular loosely coupled world.

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);
   Openable oc = dob.getLookup().lookup(Openable.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 and Lookup.Result.allInstances(), because the lookupAll() method was not created until 6.0.

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.

If you need to merge together more than one lookup (for example, the lookup provided from Node.getCookieSet().getLookup() and one of your own which you will add and remove objects from), you can simply use ProxyLookup - i.e. new ProxyLookup (lookup1, lookup2, Lookups.singleton(someObject), ...)

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.

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:

Why use Lookup - 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 of type X unless it can load/access the X.class. The module trying to look up an X will not be able to see X.class unless it declares a dependency on the module that defines X and the module which defines X says that it allows access to the Java package X lives in. (A 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.
  3. Lookup supports listening to changes in the result.
  4. Lookup supports multiple instances for one key - if you call lookup(X.class) you get one instance. If you call lookupAll(X.class) you get a Collection<? extends X> (so with lookupAll() it is more like a Map<Class<T>,List<T>>)

There are some other capabilities of Lookup (such as getting the specific type or number of results without actually creating objects, and providing named 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.

See also the javadoc: org.openide.util.Lookup

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 (assume that lkp is a Lookup):

NB 5.x Code NB 6 Code
DataObject dob = (DataObject) lkp.lookup(DataObject.class) DataObject dob = lkp.lookup(DataObject.class)
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);
Lookup.Template t = new Lookup.Template(X.class);

Lookup.Result r = lkp.lookup(t);
Collection c = r.allInstances();
for (Iterator it=c.iterator(); it.hasNext();) {   X x = (X) it.next();
  //do something with x
}

for (X x : lkp.lookupAll(X.class)) {

  //do something with x
}


Generics work well with JDK-5-style for-loops:

for (SomeService s : Lookup.getDefault().lookupAll(SomeService.class)) {
    // ...
}

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. (In JDK 6, ServiceLoader operates on the same principle.) The default lookup searches in two places:

Objects contained in the default lookup are instantiated lazily when first requested. Objects returned by the default lookup may (or may not) be garbage collected if they become unreferenced.

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 and later

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.

What is the difference between getCookie(Class), SharedClassObject.findObject(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

How do I implement my own lookup or proxy another one?

It is not uncommon to be subclassing a 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.

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.lookupAll(Class) 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.

How can I find out what is in a Lookup

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:

Collection<?> c = theLookup.lookupAll(Object.class);
for (Object o : c) {
  //do what you want
}

Do not do either of these things in production code!

How can I add support for lookups on nodes representing my file type?

Any object you create can implement Lookup.Provider. The simplest way to create a mutable lookup is by using InstanceContent and AbstractLookup. Simplified typical usage:

public SomeObject implements Lookup.Provider {
   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.

If you are using ProxyLookup to proxy another (or multiple) lookups, and you want to change the set of Lookups you are proxying on the fly, you will need to subclass ProxyLookup and call the protected method setLookups(Lookup... lookups).

When should I use Lookup in my own APIs?

For most things in NetBeans coding, you will want to write normal Java code - if you need an object of a particular type, just call it.

When you need to use any of the following patterns, Lookup can be helpful:

System-level-decoupling

You provide some interface. Some other module will actually implement the interface. You want modules to be able to use your API, without caring who implements it, just that some implementation is there. Example: The status line.

StatusDisplayer.getDefault()

returns some implementation of StatusDisplayer. In NetBeans typically it is provided by the window system. But I once wrote an implementation that would instead hide the status bar and instead show the message in a translucent popup that appears over the main window. That would not have been possible if all code that wanted to display status messages was tied at compile-time to the implementation class provided by the window system.

Designing an API for a not-well-defined problem space

An example of this is Project.getLookup(). In the case of projects, when that API was designed, the only things that could be known for sure about a project were that:

Designing a Project API that would provide for everything C/C++, Ruby, Java, DocBook, HTML, Web, J2EE, J2ME, etc. projects (this had been tried) would end up with something bloated and filled with functionality that any random client would never use - a very noisy, hard-to-use API. Since in that case the requirements were not and could not be known, the lookup pattern made it possible to create an API and let clients define additional APIs (like ClassPathProvider for Java projects, which would make no sense in a DocBook project), and provide client access to them through the project's Lookup. Granular decoupling

The uses of Lookup in Node and TopComponent: Here, you have some API type. You make it available in the Lookup of files of a certain type. You don't necessarily know all the ways your UI will change in the future. Other modules want to add actions (to popup menus, toolbars, whatever) that can operate on your type. Those actions should be enabled whenever the selection contains one (or more) of your object. By writing actions sensitive to your type in the global selection lookup (Utilities.actionsGlobalContext()), no rewrite of those actions is required if, at some point, you write a new window component that shows, say, virtual files or some random tree of objects that contain your type.

Mutable Capabilities

You are designing an API for an object whose capabilities are actually mutable. Listening for a particular type in a Lookup is much less code, and much clearer, than defining a bunch of event types, listener classes and addThisListener(), addThatListener(). Example: In the Java Card modules, there is a class Card. A Card has a lookup. Now a card might be a physical device plugged into your computer. Or it might be a virtual card definition used by an emulator for testing. A virtual card has capabilities like Stop, Start and Resume. When you call StartCapability.start(), the StartCapability disappears from the Card's lookup and a StopCapability appears. But if it is a physical card, Start and Stop make no sense whatsoever - so for a real card they are not there. Other capabilities, such as PortProvider, which will tell you what TCP ports to use to send code to, attach a debugger to, etc., are present for both virtual cards and some real cards, if HTTP is the mechanism to deploy code to them - but other cards may have you run a native executable to deploy code and use no ports. So PortProvider is another optional capability.

Note that you can add typing to Lookup-based APIs if you find it useful or it makes your API easier (with Find Usages or Javadoc) to use. In org.netbeans.modules.javacard.spi.Card, in fact, there is

public <T extends ICardCapability> T getCapability(Class<T> type);

which delegates to Lookup but guarantees the return value is a subtype of something you can search on. I don't recommend that for all situations (part of the birth of Lookup was that Node.getCookie() returned something that implemented the marker interface Node.Cookie, and for things that wanted lookup-like functionality but had no connection to Nodes whatsoever, it made no sense to make them drag around a JAR with the Nodes API just for a marker interface). But in restricted situations, it can make an API more usable.

Composable Objects

Some NetBeans-based applications use Lookup as a mechanism to allow modules to plug in aspects that are applied to existing objects. For example, say you write an extensible Node whose display name is implemented as

public String getDisplayName() {
  return getLookup().lookup(Displayable.class).getDisplayName();
}

Some other module can then contribute (most likely via a layer file and Lookups.forPath()) a Displayable for that object. This is a rather extreme form of extensibility and can be hard to debug, but if you need it, Lookup can be used for that.

Conclusion

These cover most of the typical cases. If you're not doing something like these examples - if using Lookup adds complexity to your code without adding needed flexibility or future-proofing - then it's the wrong tool for the job.

For a more detailed discussion, which this FAQ entry was assembled from, see this thread on the dev@platform mailing list

See also: When To Use Various Declarative Registration Mechanisms

After adding my class to Lookup I get a "ClassNotFoundException" when trying to look it up, why?

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.

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

public final class Token {
 
    private final long id;
 
    public Token(long id) {
        this.id = id;
    }
 
    public long getId() {
       return id;
    }
}

Now we will write a converter. Until the first time something calls theLookup.lookup(AnExpensiveClass.class), only our quick-to-create Token object is in memory. On the first such lookup call, the following code is run:

public class LazyLoadingDelegate implements InstanceContent.Convertor<Token, AnExpensiveClass> {
 
    @Override
    public AnExpensiveClass convert(Token token) {
        // 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());

Your context-sensitive action will behave normally—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 implements ActionListener {
    private final AnExpensiveClass expensiveClass;
    public ExpensiveClassAction(AnExpensiveClass a) {
      this.expensiveClass = a;
    }
 
    public void actionPerformed(ActionEvent ev) {
        // now you have the actual do AnExpensiveClass instance, 
        // in variable expensiveClass
        // so do something with it...
    }
}
Lifecycle With InstanceContent.Converter

Objects created using an InstanceContent.Converter are only weakly cached by default. That means that, after AnExpensiveClass is instantiated, it can be garbage collected if no object holds a reference to it in a field. If the object is going to be queried for repeatedly, you may want your InstanceContent.Converter to cache the last-created value, either for some period of time, or using a SoftReference or hard reference or other caching strategy.

How can I register services into the 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="wheeler-sample">
            <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...

Converting between common data types and finding things

FileObjects versus Files

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:

However a FileObject must always really exist on disk (or whatever backing storage is used), unlike File.

In case translation from one to the other is necessary:

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:

Also note that, unlike java.net.URL, URI.equals() does not make a network connection to determine equality. Never put URLs into a HashSet or similar equality-testing collection for this reason.

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

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

FileUtil.toFile(FileObject fo)

How do I get a FileObject for a File?

FileUtil.toFileObject (FileUtil.normalizeFile(theFile));

How do I get a DataObject for a FileObject?

DataObject.find (theFileObject)

How do I get a FileObject for a DataObject?

theDataObject.getPrimaryFile()

How do I get a Node for a DataObject?

Very simply:

theDataObject.getNodeDelegate()

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 get a reference to the system filesystem?

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

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 = dob.getLookup().lookup(InstanceCookie.class);
MyObject obj = (MyObject) ck.instanceCreate();

(you can and should call ck.instanceClass() to ensure the type cast is correct ahead of time)

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

Often registries of objects are created by placing files with the extension .instance into some folder in the system filesystem. The task, then, is to turn a folder full of files into a collection of objects, and make sure we only get objects of the type we are interested in. In NetBeans 6 it is very simple to do that:

Lookup myObjects = Lookups.forPath ("path/to/folder/in/sysfs");
Collection <? extends MyType> c = myObjects.lookupAll(MyType.class);

(note the separator is always / with NetBeans filesystems).

If you have a single .instance file and need to get an object for that, see this FAQ entry.

File Management (within the IDE/Application)

How can I open a file in the IDE programatically?

[no content found]

Nodes and Explorer

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</tt> 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 "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.

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:

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 do I show a Node in 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.

I need to create my own Nodes. What should I subclass?

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 Nodes, 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 to 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:

I need to show Nodes for objects that are slow to create. How do I compute Node children on a background thread?

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

How do I create a TopComponent (tab in the main window) to show some Nodes?

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

I have a reference to an existing Node from some other module. Can I add cookies/properties/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, remove or reorder 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

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

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

In general, it shall be enough to request a FileObject via Lookup:

Node n = ...;
FileObject fo = n.getLookup().lookup(FileObject.class);
if (fo != null) {
    File f = FileUtil.toFile (fo);
    if (f != null) { //if it is null, it is a virtual file -
                     //its filesystem does not represent disk-based storage
       //do something
    }
}

If this does not work for some (strange) reason. You may fallback to old good way and get the DataObject the node represents, and drill down to a file from there

Node n = ...;
DataObject dob = n.getLookup().lookup(DataObject.class);
if (dob == null) {
    // definitely not a file node
} else {
    // could also get all files in the data object, if desired:
    FileObject fo = dob.getPrimaryFile();
    // and if you really need java.io.File
    File f = FileUtil.toFile (fo);
    if (f != null) { //if it is null, it is a virtual file -
                     //its filesystem does not represent disk-based storage
       //do something
    }
}

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.

Tracking selections in the Explorer

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 need to add to/remove from/customize the content of my Node/DataObject/TopComponent'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.

Custom Lookup Contents with DataObjects

DataObjects have a Lookup, but also use an older variant on the Lookup pattern, called a CookieSet. Since this is a somewhat bewildering term, and CookieSet will eventually be deprecated, you may want to avoid using it. A CookieSet ordinarily provides the Lookup for a DataObject; and certain APIs such as DataEditorSupport require it.

However, it is possible to work with the more modern idioms of Lookup as described above, with a few caveats. Such a DataObject typically looks like:

public class FooDataObject extends MultiDataObject {
  private final Lookup lookup;
  private final InstanceContent lookupContents = new InstanceContent();
  public FooDataObject(FileObject pf, MultiFileLoader loader) throws DataObjectExistsException, IOException {
    super(pf, loader);
    lookup = new ProxyLookup(getCookieSet().getLookup(), new AbstractLookup(lookupContents));
    lookupContents.add (...whatever...);
  }
 
  @Override
  public Lookup getLookup() {
    return lookup;
  }
 
  @Override
  protected Node createNodeDelegate() {
    return new DataNode (this, Children.LEAF, getLookup());
  }
 //...

You can then add and remove objects from your InstanceContent and the DataObject will behave as expected.

Caveat 1: You really must override createNodeDelegate() or otherwise (in your DataNode subclass) pass your DataObject's Lookup to your DataNode's constructor. Otherwise its lookup will be getCookieSet().getLookup() and nothing added to your InstanceContent will appear in the Lookup of your Node. So, if you use AbstractLookup in a DataObject, make sure its Node is really using your DataObject's Lookup.

Caveat 2: A DataObject should always appear in its own Lookup — If you are really sure that nothing is going to use your DataObject's CookieSet at all, you can omit merging getCookieSet().getLookup() into the ProxyLookup in the constructor. However, many things will not work correctly if the DataObject itself cannot be found in its own Lookup. If you are going to do that, replace getCookieSet().getLookup() with Lookups.singleton(this) to ensure it is present and cannot be removed or replaced.

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.

For other types of code, use Utilities.actionsGlobalContext(). This is a Lookup which shows the contents of whatever TopComponent has focus. When component A has focus, the Lookup returned by Utilities.actionsGlobalContext() contains whatever A.getLookup() contains. When the user sends focus to component B, the contents change - and events are fired if you are listening for changes.

Think of Utilities.actionsGlobalContext() as watching a news program on television. If there is something exciting happening in Lichtenstein, you do not have to go to Lichtenstein to learn about it - the people in the studio show you their reporter in Lichtenstein. Similarly, if you want to know what the user has selected, with Utilities.actionsGlobalContext() you do not have to pay attention to which component has focus, or even the fact that there is a component! You can just tune to the sports channel (well, in NetBeans, more likely, the DataObject channel) and get all the news about what is happening. Or, to use another metaphor, you are looking down one end of a hose. The platform takes care of moving the other end of the hose around so that you are always looking at the place where the user is working.

In practice, 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). Say that we are interested in what is happening with - whether the user has selected - objects of the type SomeApiClass:

//You must hold a reference to your Lookup.Result as long as you are interested 
//in changes in it, or it will be garbage collected and you will stop getting 
//notifications
Lookup.Result res = Utilities.actionsGlobalContext().lookupResult (SomeApiClass.class);
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 do I "decorate" nodes that come from another module (i.e. add icons, actions)?

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 {
 
    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[result.size()]);
          }
      }
 
    public FileFilteredNode (Node original, FileFilter fileFilter) {
        super(original, new FileFilteredChildren(original, 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.

How do I preserve the 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]);
                }
            }
        });
    }

How do I remove the "..." buttons of a TreeTableView?

See the blog entry "How to Suppress Editing in a TreeTableView" in Geertjan's blog:

http://blogs.sun.com/geertjan/entry/how_to_suppress_editing_in

How can I make sortable columns in a TreeTableView?

See "How to Sort Columns in a TreeTableView" in Geertjan's blog:

http://blogs.sun.com/geertjan/entry/enriching_your_treetableview

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:

How can I implement "Select all/Deselect all/Invert selection" features?

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

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

How can I graphically create a ChoiceView?

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. --Tboudreau 02:40, 24 January 2010 (UTC)

I have a Node.Property for a file. How can I control the file chooser that is the custom editor?

A number of the built-in property editors in NetBeans can have their behavior controlled by passing "hints" to them. Hints are providing by calling setValue("something", someValue) on the Node.Property. For example, to suppress the custom editor button for a property, use

 Node.Property<String> myProp = new MyStringProp();
 myProp.setValue ("suppressCustomEditor", Boolean.TRUE);

The built-in property editors for files and arrays of files support a number of hints:

String Hint Name Value Type Effect
filter java.io.FilenameFilter or javax.swing.filechooser.FileFilter or java.io.FileFilter Sets the file filter used by the file chooser
directories java.lang.Boolean Set the file chooser to accept only directories. If combined with the "files" hint set to true (see below), will accept both directories and files.
files java.lang.Boolean Set the file chooser to accept only files (unless combined with the "directories" hint set to true above - in which case simply not using either hint has the same effect
currentDir java.io.File The directory the file chooser should default to when it is first opened
baseDir java.io.File The base directory for the file property. This is needed only if the file has a relative path. Java files are just wrappers for a path name, and need not exist on disk. So if the file property is foo/MyFile.txt that is a perfectly legal file name (presumably the Java Bean or Node the property belongs to knows how to find the parent directory of "foo"). The file chooser needs to know the full path to foo/ - so you would pass a file here to provide the parent folder for foo/. For example, if the complete path to MyFile.txt is /Users/tim/Documents/foo/MyFile.txt, you would call setValue("baseDir", new File("/Users/tim/Documents")
file_hiding java.lang.Boolean Value to call JFileChooser.setFileHidingEnabled() with (remember, if your filter filters out directories and you set file hiding enabled, the user will not be able to usefully change directories)


The built-in bean property editors in NetBeans are found in the package org.netbeans.beaninfo editors in the module o.n.core in NetBeans' sources.

I have a Node.Property. I want to control its appearance or custom editor somehow. Can I do that without writing my own property editor?

NetBeans built-in property editors support a number of "hints" which will affect how the property editor behaves. A few are global to all property editors; the rest are specific to property editors for specific types.

Note that all of these are hints - a property editor is free to ignore them or not support them in the future. However all of these have been present since NetBeans 3.6 and are should still work as of NetBeans 6.9.

Property Type Hint Name Value Type Effect
Any suppressCustomEditor java.lang.Boolean Causes the property not to show a [...] button in the property sheet
Any valueIcon javax.swing.Icon Causes the property not to show an icon beside the value (should be 16x16 or smaller) when not in edit mode
Most editors (string, etc.) htmlDisplayValue java.lang.String An HTML-ized string which should be rendered using HTML rendering, not literally. The subset of HTML supported by org.openide.awt.HtmlRenderer is supported. Generally the value should be a formatted variant of the actual value - otherwise when the user edits the value, it will suddenly seem to have changed.
All property editors nameIcon java.awt.Image or javax.swing.Icon An icon which should be displayed next to the property name in the property sheet (16x16 or smaller)
All property editors helpID java.lang.String A JavaHelp help ID to provide custom help for this property's custom editor (not when the property sheet has focus)
All property editors postSetAction javax.swing.Action An action which should be invoked after the property sheet has updated the property's value from the property editor (not very useful unless you need access to the TableCellEditor - not sure what this was used for)
java.lang.String and editors which show a combo box initialEditValue java.lang.String A string which should be the initial value when the user starts editing, even if the actual property value is null
Most editors (string, etc.) htmlDisplayValue java.lang.String An HTML-ized string which should be rendered using HTML rendering. Has effect only when a cell in the property sheet or tree table or outline is not in edit mode.
Any editor that shows a combo box in the property sheet canEditAsText java.lang.Boolean Causes the combo box to be editable by text entry
java.io.File and java.io.File[] See the separate FAQ entry for File properties
java.lang.String[] (array of strings) item.separator java.lang.String The delimiter for splitting a user entered string into an array (the default is a , character)
java.lang.Integer stringKeys java.lang.String[] (array of strings) Keys - allows an integer editor to show a combo box with strings, instead of a text editor. If this property is used, the additional hint intValues; for custom code generation in the form editor, optionally codeValues may also be set.
java.lang.Integer intValues int[] (not java.lang.Integer - array of ints) The values that map to the strings passed in the stringKeys hint
java.lang.Integer codeValues java.lang.String[] (array of strings) The value that should be returned by the property editor's getJavaInitializationString() method if the corresponding value is selected
java.lang.Boolean stringValues java.lang.String[] (array of strings) Alternate names to show instead of true and false (note, this will result in a radio-button boolean editor instead of a checkbox; to use radio buttons in all boolean editors, set the system property netbeans.ps.forceRadioButtons to true)
java.lang.String instructions java.lang.String Localized instructions to the user which should be visible above the text field/area in the custom editor
java.lang.String oneline java.lang.Boolean Instruct the custom editor to use a single-line JTextField instead of a mult-line JTextArea
java.awt.Image images java.awt.Image[] An array of images the user can select from
java.awt.Image values java.lang.String[] Names for the images passed in the images hint
java.awt.Image descriptions java.lang.String[] An array of descriptions corresponding to the array of images passed in the images hint
java.lang.Object (yes, you can have a property of Object and there is an editor for it - the user can select from all objects of a type in the default Lookup or a specific lookup [see below] using a combo box) superClass java.lang.Class The superclass, passed to Lookup.getDefault().lookupAll() to find all possible values
java.lang.Object nullValue java.lang.Object (must be of the same type as the type passed in the superClass hint) The value the editor should show if the property initially has a value of null
java.lang.Object lookup org.openide.util.Lookup A specific lookup for this editor to query for possible values, instead of using the default lookup

I want to allow other modules to inject objects into my Node's Lookup, or Actions into its actions

There is a simple general method for allowing you to define your own registry of objects as a folder in the System Filesystem, and look them up on demand.

class BaseNode extends AbstractNode {
  //...
  private static final String PATH_IN_SFS = "path/to/some/folder/actions";
  public Action[] getActions(boolean ignored) {
    return Lookups.forPath(PATH_IN_SFS).lookupAll(Action.class).toArray(new Action[0]);
  }
  //...
}

You can use this pattern for properties, or whatever. If you want your Node to respond to new modules being loaded on the fly, you may want to get a Lookup.Result and listen for changes on it (not necessary in the example above, but necessary for things like Lookup contents or Properties, which are cached).

Injecting Lookup Contents

First, be sure this is something you really need. Typically, you expose some model object from your Node, and write Actions that are sensitive to it.

However, if you want to use built-in actions (such as OpenAction) over your custom Nodes, and the module which created the Node does not provide the Openable or OpenCookie object which, for example, OpenAction needs, then you do need some way for other modules to inject contents into your lookup. If you are both injecting an object into the lookup, and writing an action against that object in the same module (and not expecting other modules to also add actions sensitive to your Converter's type), you can probably skip the injecting of lookup contents, and just go straight to the Node's model object.

Lookup contents should not be added programmatically - that would mean every module that cares about a Node type would have to be called to add contents (which may never be used) to it - meaning a performance penalty. Also this breaks things like FilterNode, which cannot transparently proxy methods that exist on the Node it is acting as a clone of.

It is simple to create a declarative registry for lookup contents. It makes use of the fact that the contents of an AbstractLookup are provided by a mutable InstanceContent object, and that a factory class can be added to an InstanceContent, InstanceContent.Converter. So you can create a folder where other modules will register instances of InstanceContent.Converter for Nodes which hold an object of your type. When you create the Node's lookup, you can collect all such Converters, and add them to your Lookup's contents. Unless the lookup is queried for the type one Converter creates, it will never be called.

Here is an example base Node class that will do this:

public class BaseNode<T> extends AbstractNode {
  final InstanceContent content;
  final Class<T> type;
  public BaseNode(Class<T> type, T modelObject) {
    this(type, modelObject, new InstanceContent());
  }
  public BaseNode(Class<T> type, T modelObject, InstanceContent content){
    super(Children.LEAF, new ProxyLookup(Lookups.fixed(modelObject), new AbstractLookup(content)));
    this.content = content;
    this.type = type;
    //Populate lookup based on declaratively registered factories
    String pathInSystemFS = getRegistrationPath("lookupContents");
    Collection<? extends InstanceContent.Convertor> all = 
       Lookups.forPath(pathInSystemFS).
       lookupAll(InstanceContent.Convertor.class);
    for (InstanceContent.Convertor<T, ?> factory : all) {
      content.add(modelObject, factory);
    }
    //if you want to handle modules being loaded/unloaded in a running app,
    //use lookupResult() instead of lookupAll(), retain a reference to the
    //Lookup.Result, listen on it for changes, and remove all acquired
    //InstanceContent objects if it changes, then rerun the above code
  }
  @Override
  public Action[] getActions(boolean context) {
    return Lookups.forPath(getRegistrationPath("actions")).
         lookupAll(Action.class).toArray(new Action[0]);
  }
  String getRegistrationPath(String subfolder) {
    //e.g. pass "lookupContents" and get 
    //MyModule/com/foo/mymodule/MyType/lookupContents
    return "MyModule/" + type.getName().replace('.', '/') + "/" + subfolder;
  }
}

Suppose that we have some BaseNodes whose model objects are instances of Strings. We want to add a Foo object to their Lookups, and register an action which operates against Foo objects. So, we have an InstanceContent.Converter implementation:

public class FooFactory implements InstanceContent.Convertor<String, Foo> {
  @Override
  public Foo convert(String string) {
    return new Foo(string);
  }
  @Override
  public Class<? extends Foo> type(String obj) {
    return Foo.class;
  }
  @Override
  public String id(String obj) {
    return getClass().getName() + obj;
  }
  @Override
  public String displayName(String obj) {
    return obj;
  }
}

The action implementation can be any Action subclass, so we can omit the code for that - but its classname for this example will be org.netbeans.demo.elookup.FooAction.

All we need to do now is register both of these objects in the System Filesystem and we will have working code.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" 
"http://www.netbeans.org/dtds/filesystem-1_1.dtd">
<filesystem>
    <folder name="MyModule">
        <folder name="java">
            <folder name="lang">
                <folder name="String">
                    <folder name="lookupContents">
                        <file name="org-netbeans-demo-elookup-FooFactory.instance"/>
                    </folder>
                    <folder name="actions">
                        <file name="org-netbeans-demo-elookup-FooAction.instance"/>
                    </folder>
                </folder>
            </folder>
        </folder>
    </folder>
</filesystem>

Note that objects created by such factories will be weakly cached by the lookup - if no object is holding a reference to the object, it can be garbage collected. If such objects are expensive to create, or if you expect callers to attach listeners to the factory-created objects, you may want to cache them in your implementation of InstanceContent.Converter.

How can I add horizontal scrolling support to the OutlineView component?

The OutlineView component already contains a JScrollPane, but the component's default behavior is to fit all the columns in the available space. If you have a large number of columns, say twenty or more, you may find that the horizontal space allocated to any one column is insufficient. In this case, you will likely want to disable table column resizing so that you can scroll left or right to see the data. This can be accomplished by adding one line of code:

outlineView.getOutline().setAutoResizeMode(JTable.AUTO_RESIZE_OFF);

Threading

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 be 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 background thread, but need to modify some Swing component, a simple way to do this is
    EventQueue.invokeLater(new Runnable() {
      public void run() {
        //this code can work with Swing
      }
    });

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

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 and listen to task finish among other.

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 - use with care, only when really necessary).

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 multi-threading, 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.

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.

One of the most common threading bugs in NetBeans happens like this:

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. More threads than CPUs 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 too 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 new 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.

What APIs come with built-in background thread handling?

A few APIs come with built in multi-threading - if you want your code to run on a background thread, you don't have to do any special set up to do that.

Specifically they are

How can I run an 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
  }
}

Settings

How do I let the user set preferences/options/customization/configuration for my module/application?

From 6.0 onwards, you can use the NbPreferences API.

Read the following related blog entries:

Can I add new panels to the Options window?

Yes.

Use the Options Dialog and SPI as explained in the NetBeans Options Window Module Tutorial.

How to register options for export/import to module's layer?

The idea is to register patterns for export/import into module's layer.

For details, see Export/Import Options in NetBeans - Proposal.

Dialogs API

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 a question to users, you'll use a similar mechanism. The msg argument is optional here:

String msg = "Something is going to happen. Do you want to continue?"
NotifyDescriptor nd = new NotifyDescriptor.onfirmation(msg, NotifyDescriptor.YES_NO_OPTION);
Object result = DialogDisplayer.getDefault().notify(nd);
if (NotifyDescriptor.OK_OPTION == result) {
    // do it
} else {
    // don't do it
}

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

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)


When using DialogDescriptors some additional steps need to be taken. Its OK button cannot be enabled/diabled after it has been displyed via a DialogDisplyer. The following is a sample code :

1.  Create a new Action in one of your modules using the wizard in the
NetBeans IDE

2.  Replace the code generated inside that ActionListener with this code below:

   public void actionPerformed(ActionEvent e) {
       MyForm form = new MyForm();

       DialogDescriptor desc = new DialogDescriptor(form,

         "Hello", true, DialogDescriptor.OK_CANCEL_OPTION,
          DialogDescriptor.OK_OPTION, null);

       desc.setValid(false);

       form.setDialogDescriptor(desc);

       DialogDisplayer.getDefault().notify(desc); // displays the dialog
   }


   static class MyForm extends JPanel implements DocumentListener {

       private JTextField field;
       private DialogDescriptor desc;

       MyForm() {
           super(new BorderLayout());
           field = new JTextField();
           add(new JLabel("Type Something Here"), BorderLayout.NORTH);
           add(field, BorderLayout.SOUTH);
       }

       void setDialogDescriptor(DialogDescriptor desc) {
           this.desc = desc;
           field.getDocument().addDocumentListener(this);
       }

       private void doEnablement() {
           if (field.getText().isEmpty()) {
               desc.setValid(false);
           } else {
               desc.setValid(true);
           }
       }

       @Override
       public void insertUpdate(DocumentEvent e) {
           doEnablement();
       }

       @Override
       public void removeUpdate(DocumentEvent e) {
           doEnablement();
       }

       @Override
       public void changedUpdate(DocumentEvent e) {
           doEnablement();
       }
   }

3.  Run your application and invoke the new action you added

Here the OK button in the dialog is initially disabled, but becomes enabled when some characters are typed. Removing all characters will disable it again.

One noteworthy point is that the following alternative fails to enable the OK button and hence the given solution is the appropriate one.

desc.setValid(false);
DialogDisplayer.getDefault().notify(desc);
desc.setValid(true); //OK button doesnot get enabled

Project Handling

How can I open a Project programatically?

[no content found]

Wizards and Templates

How do I make a file template which actually creates a set of files at once?

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

I am creating a non-IDE application. How do I enable/control templates?

If the projectui module is installed, templates are only made available inside projects.

If you want to enable templates outside of a project (like folder is, by default), then you need to remove the projectui module but make sure the favorites (org.netbeans.modules.favorites) module is enabled for your suite.

To make your template available as one of the choices on the New File context menu (as opposed to having to choose the type in the wizard), then you have to list it as a privileged template.

See Tom Wheeler's TodoListManager for an example of code that does these things.

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 obtain the instance of WizardDescriptor in the WizardDescriptor.Panel.readSettings as settings parameter method.

Update in NetBeans 6.8

Two new methods in NotifyDescriptor were added to allow API client to create NotificationLineSupport which allow handling error/warning/info messages in dialogs. If a dialog descriptor creates this support, DialogDisplayer allocates necessary space at the bottom of dialog where API clients can set info/warning/error messages with appropriate icons.

Output Window

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.

See here for a plugin that has a convenient class for all output purposes.

How do I route the output from an external process to the output window?

NetBeans 6.8 and up: Use the External Execution API. Implement a Callable which will actually start the process:

private class ProcessLaunch implements Callable<Process> {
  private final String[] commandLine;
  public ProcessLaunch(String... commandLine) {
    this.commandLine = commandLine;
  }
  public Process call() throws Exception {
    ProcessBuilder pb = new ProcessBuilder(cmdline);
    pb.directory(new File(System.getProperty("user.home"))); //NOI18N
    pb.redirectErrorStream(true);
    return pb.start();
  }
}


Create an ExecutionDescriptor:

ExecutionDescriptor descriptor = new ExecutionDescriptor().controllable(true).frontWindow(true).
  preExecution(new SomeRunnableToCallBeforeStart()).postExecution(new SomeRunnableToCallAfterExit());

The before and after runnables can be used to, say, update the user interface when the process starts and stops.

Then actually launch your process. Standard output and standard error (if you leave in the call to redirectErrorStream(true) above) output will be redirected to the output window, and the tab name in the Output Window will be what you specify below. The variable theCommandLineArguments is an array of strings, just as you would pass to Runtime.exec() - the command-line to run whatever program you want to run.

ExecutionService exeService = ExecutionService.newService(
  new ProcessLaunch(theCommandLineArguments),
  descriptor, "My Process");
Future<Integer> exitCode = exeService.run();

(you can use the returned Future to wait for the process to exit and get its exit code - just don't do that in the Swing event thread).

Applies to: NetBeans 6.8 and up. How to do this in NetBeans 6.7 and older

What about processes using the System.out/System.err?

Sometimes we are using a third party package that we don't have access to its source or we don't want to modify.

In this case you just need to redirect the system streams like this:

private void redirectSystemStreams() {
        out = new OutputStream() {

            @Override
            public void write(int i) throws IOException {
                OutputHandler.output(outputName, String.valueOf((char) i));
            }

            @Override
            public void write(byte[] bytes) throws IOException {
                OutputHandler.output(outputName, new String(bytes));
            }

            @Override
            public void write(byte[] bytes, int off, int len) throws IOException {
                OutputHandler.output(outputName, new String(bytes, off, len));
            }
        };
        System.setOut(new PrintStream(out, true));
        System.setErr(new PrintStream(out, true));
    }

OutputHandler is just a helper class that I've been using for a while. Feel free to use it. You need to add a dependency to I/O APIs package even if you don't use it to avoid run time issues. If you don't use it replace the OutputHandler calls for something like this:

IOProvider.getDefault().getIO(name, true).getOut().println(mess);

The OutputHandler referenced abouve has been transformed into a plugin for easier use. See here for more details.

How to implement custom IOProvider?

Note: You will only do this if you are writing a replacement for the NetBeans output window, which is a fairly unusual activity.

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 or higher

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 to use color text in Output Window?

You can use IO extension classes like IOColorPrint, IOColorLines. Default colors can be changed via IOColors.

InputOutput io = IOProvider.getDefault().getIO("test");

// change default color for output in corresponding tab
if (IOColors.isSupported(io)) {
    IOColors.setColor(io, IOColors.OutputType.OUTPUT, Color.GRAY);
}

// print line in specific color
if (IOColorLines.isSupported(io)) {
    IOColorLines.println(io, "Green line", Color.GREEN);
}


public class L implements OutputListener {
...
}

// print parts of line in specific color
if (IOColorPrint.isSupported(io)) {
    IOColorPrint.print(io, "Green part", Color.GREEN);
    IOColorPrint.print(io, " pink part", Color.PINK);
    IOColorPrint.print(io, " hyperlink with custom color", new L(), false, Color.MAGENTA);
}

See here for a plugin that has a convenient class that takes care of the dirty work and even handles OutputListeners.

Applies to: NetBeans 6.7 or later, (IOColorPrint 6.8 or later).

How to get user input in the Output Window?

[no content found]

Running and Writing tests

Using NbModuleSuite & friends

Right API for starting the test inside NetBeans Runtime Container is provided in form of NbModuleSuite. Add suite method into your test class to fully emulate NetBeans environment:

   public static Test suite() {
     return NbModuleSuite.create(YourTest.class);
   }
JUnit Version

NetBeans 6.5 now supports JUnit 4.x, via the JUnit 4 module in the platform 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.


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:

Now you must set up the structure under your module:

It should now be possible to run a class that extends JellyTestCase, and for the IDE to display this correctly.

Support for functional tests on Maven-based NetBeans applications should be present from 7.0, with the resolution of http://netbeans.org/bugzilla/show_bug.cgi?id=190992 For more information, see http://netbeans.dzone.com/nb-mvn-functional-tests

TODO


NOTES

MockLookup and other classes mentioned on the Useful Test Classes in Modules are not available in the platform.

Running tests on a platform application

The following article describes some of the ways you can run tests (whether unit or functional) on a NetBeans Platform application.

What is a unit test versus a functional test?

Unit test is a test on a method not on the overall functionality of a tool or application. Example of unit test if testing of a method than should return always positive integer. Functional test is testing the overall encryption algorithm that uses that method.

From the NetBeans IDE


From the Command Line Using Ant
Unit Test Code Coverage

The NetBeans Platform has inherently supported unit test code coverage (using Cobertura) since version 6.7. To generate a report which measures unit test code coverage for a single module, type ant display-coverage-report from that module's directory. Likewise, you can generate a report which measures unit test code coverage for all unit tests in the entire suite by typing ant display-coverage-report from the suite's directory.

Debugging Unit Tests From the Command Line

Debugging tests from using the NetBeans IDE should be pretty straightforward, but if you want to debug a unit test from the command line (i.e. because you want to attach the debugger in a different IDE), then you simply need to run the test from the command line as described above but specify -Dtest.run.args="-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005". The test will compile and start to run, but will pause execution until you attach the debugger on port 5005.

NetBeans Developer Test FAQ

Abstract

Contains info how to develop tests for NetBeans plugin.

Starting to writing tests for NetBeans
NetBeans Testing Infrastructure
Test patterns
Test API

Useful test classes in modules

Frequently used patterns
Testing NetBeans Projects
Test Editor
Testing new Java infrastructure
Testing J2EE
Performance tests
UI Tests

Testing things that use FileObjects

If your unit tests use FileObject (including DataObject or DataFolder), then you may be suprised that FileUtil.toFileObject(java.util.File) returns null. This is because the MasterFS filesystem implementation is what maps FileObjects to your local disk and it needs to be on the classpath when tests are run.

See UsingFileSystemsMasterfs for more info on how to fix this.

If for some reason you prefer not to use MasterFS, you can create a new LocalFileSystem, create some files and use that instead of FileUtil.toFileObject in your test. For example, in a NbTestCase subclass:

FileObject dir;
public @Override void setUp() throws Exception {
  super.setUp();
  clearWorkDir();
  LocalFileSystem fs = new LocalFileSystem();
  fs.setRootDirectory(getWorkDir());
  dir = fs.getRoot();
}

If your test just needs some simple data in a FileObject or two, you can avoid writing to disk at all as follows:

FileObject dir;
public @Override void setUp() throws Exception {
  super.setUp();
  dir = FileUtil.createMemoryFileSystem().getRoot();
  //write out data your tests will use to files under dir/ here
}

If you want to write tests for a DataObject or DataLoader, you may also want to set the mime type correctly: DevFaqTestDataObject

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?

There is a fake System FileSystem provided by as soon as FileSystem API is on classpath. It understands NetBeans layer definitions and is generally suitable for running unit tests.

In case you see difference from expected behavior:

Authentication and Authorization in Platform Apps

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 class should exist in a JAR file in the startup classpath (you can put it alongside core.jar in the platform/core directory). This class must also have a main method which can invoke whatever authorization logic you like. If authorization fails, you'll probably want to show a dialog and call System.exit. If it succeeds, you can invoke the org.netbeans.core.startup.Main class' main method yourself to continue the normal NetBeans startup procedure. But because org.netbeans.core.startup.Main is not a public API, you will need to invoke it indirectly using reflection. Here is an example of a custom startup class that does this:

package com.tomwheeler;

import java.lang.reflect.Method;

public class CustomStartup {

    private static final String NB_MAIN_CLASS = "org.netbeans.core.startup.Main";

    public static void main(String[] args) throws Exception {
        // do whatever you need here (e.g. show a custom login form)
        System.out.println("Hello world! I am a custom startup class");


        // once you're done with that, hand control back to NetBeans
        ClassLoader classloader = Thread.currentThread().getContextClassLoader();
        Class<?> mainClass = Class.forName(NB_MAIN_CLASS, true, classloader);

        Object mainObject = mainClass.newInstance();
        Method mainMethod = mainClass.getDeclaredMethod("main", new Class[]{String[].class});
        mainMethod.invoke(mainObject, (Object) args);
    }
}

The easiest thing to do is create a Java Class Library project (not a module project) in the NetBeans IDE, create a class like the one above and then build the project to create a JAR file. Copy that JAR file to the platform/core directory of your platform and then start your application using the following command line:

    myapp.exe -J-Dnetbeans.mainclass=com.tomwheeler.CustomStartup

Obviously, the user can simply edit the command line in most circumstances; even in the "conf" file. Therefore, without further considerations, the security of this approach is limited.

It is important to note that because the platform has not been initialized at this point, none of the usual platform capabilities will be available. Also, if successful authentication produces a login token of some kind, it may be difficult to provide this token to code in your modules.

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

JavaHelp

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

Why doesn't my JavaHelp content show up?

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

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

Deploying Changes through AutoUpdate and using Autoupdate API

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 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):

<property file="${suite.dir}/nbproject/project.properties"/>
<target name="netbeans-extra" depends="init">
    <branding cluster="${cluster}" overrides="${suite.dir}/branding" token="${app.name}"/>
</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.name}
extra.module.files=\
        core/locale/core_${app.name}.jar,\
        modules/ext/locale/updater_${app.name}.jar,\
        modules/locale/org-netbeans-core-windows_${app.name}.jar,\
        modules/locale/org-netbeans-core_${app.name}.jar,\
        modules/locale/org-netbeans-modules-autoupdate-ui_${app.name}.jar,\
        modules/locale/org-netbeans-modules-favorites_${app.name}.jar,\
        modules/locale/org-netbeans-modules-javahelp_${app.name}.jar,\
        modules/locale/org-netbeans-modules-projectui_${app.name}.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.

How can I set the interval at which AutoUpdate checks its servers?

There are several possibilities to customize behavior of Plugin Manager (Tools|Plugins) to show more items or to change its behavior.

Note: for NetBeans expert only. Use of these options at your own risk.

Show all modules

In default view, Plugin Manager shows all plugins unless specify its visibility flag to false (AutoUpdate-Show-In-Client=false) - in other words, Plugin Manager filters out most of like service modules as hidden in plugin infrastructure. To make Plugin Manager to be showing all modules being run in your IDE with switch plugin.manager.modules.only set to true (i.e.-J-Dplugin.manager.modules.only=true).

Show plugin's code name base

Each NetBeans plugin has own code name what should be unique in NetBeans distribution, this code name will not show in plugin's details. To show this code name just run your IDE with switch plugin.manager.extended.description set to true (i.e.-J-Dplugin.manager.extended.description=true)

Install all plugins into NetBeans installation directory

How to Plugin Manager chooses a directory where NBM will install?

  1. If NetBeans install dir is not writable, install to userdir.
  2. If an update, overwrite the existing location, wherever that is.
  3. Otherwise (new module), if a cluster name is specified in NBM (targetcluster), put it there (creating the cluster if necessary).
  4. Otherwise (no cluster name specified), if marked global, maybe put it into an extra cluster
  5. Otherwise (global set false or unspecified), put it in userdir.


If plugin.manager.install.global is set to true then NBM will go into installation directory for all cases unless the install directory is read-only.

Check for new plugins just after IDE startup

Plugin Manager checks for updates of already installed plugins right after IDE startup, not for new plugins. To force Plugin Manager to check for new plugins as well, just run IDE with a option -J-Dplugin.manager.check.new.plugins=true. New plugins will be notified in IDE status line.

Check for updates just after IDE startup

As was written above, Plugin Manager is checking for updates of already installed plugins right after IDE startup. If you would like to suppress it, just run IDE with a option -J-Dplugin.manager.check.updates=false.

To customize Interval of Automatically Check for Updates (since NB6.1)

Use a launcher option plugin.manager.check.interval with possible values: EVERY_STARTUP, EVERY_DAY, EVERY_WEEK, EVERY_2WEEKS, EVERY_MONTH or NEVER or also it's possible set the interval in minutes, like this -J-Dplugin.manager.check.interval=60 - to check it every hour. This option can force default value for Plugin Manager, i.e. if your application is launched with -J-Dplugin.manager.check.interval=EVERY_STARTUP (or with modified in etc/netbeans.conf), content of all subscribed Update Centers will be checked on every startup. If an user changes the check interval in Plugin Manager | Settings tab then future Autoupdate invocations will read user's values regardless the plugin.manager.check.interval, as usual.

To give precedence to dedicated module while updating (since NB6.1)

If Plugin Manager does install all available updates, it's possible to determinate set of modules which must be handled in exclusive mode before others. For example, update of Plugin Manager plugin should be installed as the first, in preference of common plugins because its update might be important for handling update of rest of plugins. In that case, Plugin Manager will notify users about availability of update Plugin Manager only (swallows down updates of rest) and when Plugin Manager is up-to-date, it will handle update of other plugins.

To make Autoupdate/Plugin Manager high verbose in console

Just use a common logging capability for force Autoupdate/Plugin Manager to be running in high verbose mode, like this -J-Dorg.netbeans.modules.autoupdate.level=FINEST, you also can specify the scope for logging in more detail (-J-Dorg.netbeans.modules.autoupdate.ui.actions.AutoupdateSettings.level=FINE). Do not forget to switch on logging into console -J-Dnetbeans.logger.console=true.

Applies to: NetBeans 6.0 or newer

Platforms: All

Do not hesitate to contact me on jrechtacek@netbeans.org if you have any question.

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.

Related articles
Other resources

What other documentation is available about AutoUpdate?

There are several possibilities to customize behavior of Plugin Manager (Tools|Plugins) to show more items or to change its behavior.

Note: for NetBeans expert only. Use of these options at your own risk.

Show all modules

In default view, Plugin Manager shows all plugins unless specify its visibility flag to false (AutoUpdate-Show-In-Client=false) - in other words, Plugin Manager filters out most of like service modules as hidden in plugin infrastructure. To make Plugin Manager to be showing all modules being run in your IDE with switch plugin.manager.modules.only set to true (i.e.-J-Dplugin.manager.modules.only=true).

Show plugin's code name base

Each NetBeans plugin has own code name what should be unique in NetBeans distribution, this code name will not show in plugin's details. To show this code name just run your IDE with switch plugin.manager.extended.description set to true (i.e.-J-Dplugin.manager.extended.description=true)

Install all plugins into NetBeans installation directory

How to Plugin Manager chooses a directory where NBM will install?

  1. If NetBeans install dir is not writable, install to userdir.
  2. If an update, overwrite the existing location, wherever that is.
  3. Otherwise (new module), if a cluster name is specified in NBM (targetcluster), put it there (creating the cluster if necessary).
  4. Otherwise (no cluster name specified), if marked global, maybe put it into an extra cluster
  5. Otherwise (global set false or unspecified), put it in userdir.


If plugin.manager.install.global is set to true then NBM will go into installation directory for all cases unless the install directory is read-only.

Check for new plugins just after IDE startup

Plugin Manager checks for updates of already installed plugins right after IDE startup, not for new plugins. To force Plugin Manager to check for new plugins as well, just run IDE with a option -J-Dplugin.manager.check.new.plugins=true. New plugins will be notified in IDE status line.

Check for updates just after IDE startup

As was written above, Plugin Manager is checking for updates of already installed plugins right after IDE startup. If you would like to suppress it, just run IDE with a option -J-Dplugin.manager.check.updates=false.

To customize Interval of Automatically Check for Updates (since NB6.1)

Use a launcher option plugin.manager.check.interval with possible values: EVERY_STARTUP, EVERY_DAY, EVERY_WEEK, EVERY_2WEEKS, EVERY_MONTH or NEVER or also it's possible set the interval in minutes, like this -J-Dplugin.manager.check.interval=60 - to check it every hour. This option can force default value for Plugin Manager, i.e. if your application is launched with -J-Dplugin.manager.check.interval=EVERY_STARTUP (or with modified in etc/netbeans.conf), content of all subscribed Update Centers will be checked on every startup. If an user changes the check interval in Plugin Manager | Settings tab then future Autoupdate invocations will read user's values regardless the plugin.manager.check.interval, as usual.

To give precedence to dedicated module while updating (since NB6.1)

If Plugin Manager does install all available updates, it's possible to determinate set of modules which must be handled in exclusive mode before others. For example, update of Plugin Manager plugin should be installed as the first, in preference of common plugins because its update might be important for handling update of rest of plugins. In that case, Plugin Manager will notify users about availability of update Plugin Manager only (swallows down updates of rest) and when Plugin Manager is up-to-date, it will handle update of other plugins.

To make Autoupdate/Plugin Manager high verbose in console

Just use a common logging capability for force Autoupdate/Plugin Manager to be running in high verbose mode, like this -J-Dorg.netbeans.modules.autoupdate.level=FINEST, you also can specify the scope for logging in more detail (-J-Dorg.netbeans.modules.autoupdate.ui.actions.AutoupdateSettings.level=FINE). Do not forget to switch on logging into console -J-Dnetbeans.logger.console=true.

Applies to: NetBeans 6.0 or newer

Platforms: All

Do not hesitate to contact me on jrechtacek@netbeans.org if you have any question.

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:

Property Value
mainClass name of the main class, run after module installation from the NBM
relativeClassPath classpath elements, may contain more elements
jvm.parameters properties for JVM, arguments inserted before the main class name
mainClass.arguments more 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:

Variable Value
 %IDE_HOME% platform directory
 %IDE_USER% user directory 1
 %FS% file separator char
 %PS% path separator char
 %JAVA_HOME% the current Java home


Example
  • Using properties mainClass, relativeClassPath, jvm.parameters etc.
  • Reads all special variables like %IDE_HOME%, %JAVA_HOME% etc.
  • Opens some GUI
  • Runs a JDK demo

To see that samplepostinstall project in action

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

How can I run the installer for something else during module installation?

Sometimes you are distributing some software with your module which has its own installer, or some other similar code which needs to be run once to get everything needed installed on the user's system. If you are distributing some software (which perhaps you did not write), and it has its own installer, it is less work to just run its installer to be sure it is set up correctly, than to have your module do everything which that installer does too (and possibly get something wrong).

Autoupdate Services primary handles NetBeans plugins based on NBM packaging.

In addition, Autoupdate Services offers the possibility to install/uninstall components which are not in NBM format. This possibility has been designed to support such use-cases - for example, to install an application Servers such as GlassFish by running its own installer.

Using a native installer ensures that, if there are any problems with the way the software gets installed, it is a problem with the native installer, not your code.

To enable such possibility, Autoupdate Services API provides:

How to setup a Update Provider providing custom components?

Implement interface UpdateProvider to make a provider for your component that has its own installer. This provider has to:

A code snippet showing that provider
public class FooNativeComponentProvider implements org.netbeans.spi.autoupdate.UpdateProvider {...}

It has simple methods describing the provider, like this:

    public String getName () {
        return "Foo Update Provider";
    }

    public String getDisplayName () {
        return getName ();
    }

    public String getDescription () {
        return "Providing components with custom installers";
    }

    public CATEGORY getCategory () {
        return CATEGORY.STANDARD;
    }

The essential method getUpdateItems will return UpdateItems which matches these components. It has to return an UpdateItem both for installed component and for available component what has not been installed yet.

    public Map<String, UpdateItem> getUpdateItems () throws IOException {
        Map<String, UpdateItem> res = new HashMap<String, UpdateItem> ();


        // 1. provide already installed version

        // get installed version
        String installed = NbPreferences.forModule (FooNativeComponentProvider.class).get (FOO_CODE_NAME, null);

        // some foo-native-runtime is installed
        if (installed != null) {
            res.put (FOO_CODE_NAME + installed, getInstalledUpdateItem (installed));
        }

        // 2. provide also version available to install

        // for this example: If none version hasn't been installed yet then provider the version 3.0
        if (installed == null) {
            res.put (FOO_CODE_NAME + "_3.0", getAvailableUpdateItem ("3.0"));

        // if the version 3.0 is installed then provide newer version 3.1
        } else if ("3.0".equals (installed)) {
            res.put (FOO_CODE_NAME + "_3.1", getAvailableUpdateItem ("3.1"));
        }
        
        return res;
    }

There are two factory methods getInstalledUpdateItem and getAvailableUpdateItem. Both are using SPI UpdateItem.create(Installed)NativeComponent

Add an UpdateItem matching available component first. The provider has to specify a name, display name, download size and so forth.

The most important parts are CustomInstaller and CustomUninstaller. For example:

    private static UpdateItem getAvailableUpdateItem (String specificationVersion) {
        String displayName = "Foo Runtime " + specificationVersion;
        String description = "Foo Runtime " + specificationVersion + " with native installer";
        String downloadSize = "2815";
        CustomInstaller ci = FooInstaller.getInstaller ();
        assert ci != null;
        UpdateLicense license = UpdateLicense.createUpdateLicense ("none-license", "no-license");
        UpdateItem item = UpdateItem.createNativeComponent (
                                                    FOO_CODE_NAME,
                                                    specificationVersion,
                                                    downloadSize,
                                                    null, // dependencies
                                                    displayName,
                                                    description,
                                                    false, false, "my-cluster",
                                                    ci,
                                                    license);
        return item;
    }

Now, for an already-installed copy of the software:

    private static UpdateItem getInstalledUpdateItem (String specificationVersion) {
        String displayName = "Foo Runtime " + specificationVersion;
        String description = "Foo Runtime " + specificationVersion + " with own installer";
        CustomUninstaller cu = FooUninstaller.getUninstaller ();
        assert cu != null;
        UpdateItem item = UpdateItem.createInstalledNativeComponent (
                                                    FOO_CODE_NAME,
                                                    specificationVersion,
                                                    null, // dependencies
                                                    displayName,
                                                    description,
                                                    cu);
        return item;
    }

So, what does a custom installer look like? It it quite simple, look on

public class FooInstaller implements org.netbeans.spi.autoupdate.CustomInstaller {
    /** This code will be called back while installing the corresponding native component
     * from Plugin Manager Install Wizard.
     */
    public boolean install (String codeName, String specificationVersion, ProgressHandle handle) throws OperationException {
        // CustomInstaller has to start <code>org.netbeans.api.progress.ProgressHandle</code> !!!
        handle.start ();

        // a custom code which invokes installation of native component actually
        .......
    }
}
How to register UpdateProvider in my application?

Using META-INF/services or (in NetBeans 6.9) the @ServiceProvider annotation (see Geertjan's blog for more info):

  1. Make a META-INF/services folder in sources of your NetBeans project where the provider is,
  2. Make a file org.netbeans.spi.autoupdate.UpdateProvider in this folder,
  3. Type name of class where UpdateProvider implemented, i.e. org.netbeans.modules.fooupdateprovider.FooNativeComponentProvider

And , that's it, the NetBeans Lookup system will read it and includes that provider among other providers registered in NetBeans application.

A sample project having this UpdateProvider
Important Note

Don't apply this Update Provider earlier than NetBeans 6.5 release will be out. There were several problem which had to be fixed in NetBeans 6.5. Use NetBeans 6.5 or some of recent Development builds rather than previous releases 6.1 or 6.0!

Do not hesitate to contact me on mailto:jrechtacek@netbeans.org if you have any question.

How to deal with pack200 compression in NBM?

Starting with NetBeans 6.9 we have possibility to significantly decrease NBM file size by using pack200 compression. By default, all modules are now compressed during the build. There are several options to override that behaviour :

More info: FitnessForNBMs

When things go wrong: Troubleshooting

I've got a class not found error/exception. 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.

I find files missing from the source ZIP file

If you've downloaded and unpacked the ZIP file containing NetBeans sources but find that it seems incomplete, try using another application to unpack the ZIP file. It seems that the popular WinZip application cannot properly handle this file.

The 7-Zip application is free, open source and is known to correctly handle the NetBeans ZIP sources.

Info-ZIP is a free command-line unzip utility for Windows and OS/2 which has been around for more than a decade.

Alternatively, you could write a simple Ant script to use the unzip task for decompressing the archive, or use a ported version of a Unix unzip utility for Windows.

External FAQ Entries

The following FAQ entries are not hosted in the NetBeans wiki and could not be included: