NetBeans Developer Faq

Generated on Wed May 22 05:39:15 UTC 2013 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.

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 Help > Javadoc References (View > Documentation Indices in NetBeans 5.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, 7.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.

Update for NBM projects generated by NetBeans 7.0 and later

Now the the platform can get downloaded automatically with some minor tweaks! This is great for usage in Continuous Integration servers like Hudson/Jenkins.

See here for more details.

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
Git org.netbeans.modules.git
Git Library org.netbeans.libs.git
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 Some basic user utilities like Menu -> Open File
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 Visual Debugger org.netbeans.modules.debugger.jpda.visual
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@platform.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!


NOTE: If you get an warning about your plugins not being trusted (and you're using self-signed certificates), you need to create and register your own implementation of org.netbeans.spi.autoupdate.KeyStoreProvider which provides access to a truststore into which your self-signed certificate has been imported as a trusted entry. In other words, the keystore (private key) is used at compile time to sign the NBM file, while the truststore (created by exporting the key from the keystore, then importing it into a new store to mark it trusted) is needed at runtime to validate the signature). All of this may not be necessary if you are signing with a certificate issued by a well-known CA.


Applies to: NetBeans 6.8 and above

Can I sign Maven based NBMs I create?

Yes. NetBeans module artifact builder utility will sign your NBM files if you set keystore, alias and password parameters correctly.

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.

Also check if class you are trying to use from other module is mark as public to outside modules (right-click on module and select Properties, then API Versioning and in Public Packages check whether package of your class is ticked).

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.

I want to use modules installed in my IDE in my RCP applications. How to do it?

First make sure that you have the IDE to install the downloaded plugins into shared directories. To do this go to Tool>Plugins then the Settings tab. Enable the check box at the bottom in the advance section. You might be warned about not having permission to save files into a location. Just make sure to run NetBeans as an administrator.

Now install the plugins you are interested in (using the Update center or manual install). They'll be installed in a different place within the NetBeans platform depending on the classification of the plugin. Verify in the platform, you might have a new cluster named extra.

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

I want to use modules installed in my IDE in my RCP applications. How to do it?

First make sure that you have the IDE to install the downloaded plugins into shared directories. To do this go to Tool>Plugins then the Settings tab. Enable the check box at the bottom in the advance section. You might be warned about not having permission to save files into a location. Just make sure to run NetBeans as an administrator.

Now install the plugins you are interested in (using the Update center or manual install). They'll be installed in a different place within the NetBeans platform depending on the classification of the plugin. Verify in the platform, you might have a new cluster named extra.

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

How to run module with more PermGen and Heap memory?

When we run the module from NetBeans IDE and we want to pass JVM options to increase PermGen and Heap Memory then add the following settings to the project.properties file of your module, or module suite.

run.args.extra=-J-Xmx512m 
-J-XX:+UseConcMarkSweepGC 
-J-XX:+CMSClassUnloadingEnabled 
-J-XX:+CMSPermGenSweepingEnabled
-J-XX:MaxPermSize=256m

Please write the complete setting in one line.

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

Do I need to restart NetBeans every time to debug new changes?

[no content found]

How can I have my application compiled in a specific version of the platform?

[no content found]

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>

More and 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();
}

(FileUtil.getConfigObject is available for this purpose in NB 7.1+.)

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 Places.getUserDirectory to find the userdir or 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();
    }
}

In NetBeans 7.2 and later, the above code can be simplified by using Repository.LayerProvider. See its Javadoc for a usage example.

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

https://bitbucket.org/jglick/dynamicmenudemo/ tries to automate this kind of task.

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 allows context-sensitive actions to be registered declaratively using annotations.. In the IDE, File > New File > Module Development > Action will generate (on the first page of the wizard, specify that you want a context sensitive action):

 @ActionID(...)
 @ActionRegistration(...)
 @ActionReference(...)
 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 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.

How do I make a checkable action that represents a preference option?

See org-openide-awt/org.openide.awt.Actions.checkbox(...)

Here an example for a checkable action which represents the state of the "ignoreCase" property within the property file "org/netbeans/modules/diff.properties"

   <folder name="Actions">
       <folder name="Diff">
           <file name="toggle-ignore-case-diff-option.instance">
               <attr bundlevalue="org.netbeans.modules.diff.Bundle#CTL_IgnoreCaseOptionAction" name="displayName"/>
               <attr name="Name" stringvalue="toggle-ignore-case-diff-option"/>
               <attr name="preferencesNode" stringvalue="/org/netbeans/modules/diff" />
               <attr name="preferencesKey" stringvalue="ignoreCase"/>
               <attr name="instanceCreate" methodvalue="org.openide.awt.Actions.checkbox"/>
           </file>
       </folder>
   </folder>

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

When you use @ActionRegistration the META-INF/generated-layer.xml may contain:

<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 use text/html, text/x-java, text/x-ant+xml, text/x-jsp, image/png, etc.

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 use path="Editors/Popup" to add an action to all editor kits.

See also:

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

Just use @ActionReference(path="Projects/Actions"). The action should take a context parameter in its constructor.

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:

@ActionID(...)
@ActionRegistration(...)
@ActionReference(path="Projects/Actions")
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));
        }
    }
}

Certain project types also read their context menu actions from type-specific folders.

Applies to: NetBeans 7.0+

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?

Use @ActionReference.

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?

@ActionReference(path="Editors/TabActions")

Applies to: NetBeans IDE 7.1 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.

The Branding menu item on a suite (or Maven app project) lets you search for other strings and override them easily.

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?

https://bitbucket.org/jglick/dynamicmenudemo/ also does something similar.

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?

<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>
<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 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>
<folder name="Toolbars">
    <folder name="Build">
        <file name="org-nvarun-tat-SayCheez_hidden"/>
    </folder>
</folder>

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 then invoke actionPerformed() to fire the action.

Action a = FileUtil.getConfigObject("Actions/org-netbeans-core-actions-LogAction.instance", Action.class);
if (a != null) {
    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

How do I add content to the Global Context?

The NetBeans Platform provides the ability to enable and disable Actions based upon what is selected in the current logical window--this is known as the "global selection". In this article I show how to extend this selection concept to include objects that are global to the entire application. Using this technique, you'll be able to leverage existing idioms for creating context-sensitive actions and querying the global selection, but the scope of your operations will be expanded from the context of the current window to the context of the entire application. That's a pretty powerful extension point that demonstrates the strength and versatility of the NetBeans Platform APIs.

This FAQ will add a Project instance to the global selection. However, you could add any object, for instance a NavigatorHint, or perhaps you could keep track of the last used "widget".

Use Cases

Consider the following use cases. Each one interacts with the global selection in some way. Each one would benefit by giving the currently selected project an application-wide scope.

Use Case #1

You want to create a context sensitive action that is enabled when a project is selected in the Projects window, and that remains enabled when the focus changes to another window. For example:

@ActionID(...)
@ActionRegistration(...)
@ActionReference(...)
public final class CloseProjectAction implements ActionListener
{
    private final Project project;
 
    public CloseProjectAction(Project context)
    {
        this.project = context;
    }
 
    @Override
    public void actionPerformed(ActionEvent e)
    {
        OpenProjects.getDefault().close(new Project[] { project });
    }
}
Use Case #2

You want an Action to interact with a capability found in the current project. Your Action is in a loosely coupled module that knows nothing about projects other than the NetBeans Project API and your capability's API. For example:

@ActionID(...)
@ActionRegistration(...)
@ActionReference(...)
public final class SomeAction implements ActionListener
{
    @Override
    public void actionPerformed(ActionEvent event)
    {
        Project project = Utilities.actionsGlobalContext().lookup(Project.class);
        if (project != null)
        {            
            SomeCapability capability = project.getLookup().lookup(SomeCapability.class);
            if (capability != null)
            {
                 ...
            }
            ...
        }
    }
}
Use Case #3

You want to update the main window title based on an attribute in the current project, for instance, the name. You want to use a simple LookupListener that listens for the selected projects in the global selection. For example:

/**
 * This class provides the application's window title with the selected 
 * project's name.
 */
public class MainWindowTitleManager
{
    private static Lookup.Result<Project> lookupResults;
    private static LookupListener lookupListener;
 
    /**
     * Creates a LookupListener on the Project.class that 
     * handles changes in the project selection.
     */
    public static void activate()
    {
        if (lookupResults == null)
        {
            // Monitor the existance of Projects in the global context lookup
            lookupResults = Utilities.actionsGlobalContext().lookupResult(Project.class);
            // Create the listener on the lookupResults
            lookupListener = new LookupListener()
            {
                // Update window title when the Project changes
                @Override
                public void resultChanged(LookupEvent ignored)
                {
                    String projectName;
                    Collection<? extends Project> projects = lookupResults.allInstances();
                    if (projects.isEmpty())
                    {
                        projectName = "<No Project>";
                    }
                    else if (projects.size() == 1)
                    {
                        Project project = projects.iterator().next();
                        projectName = ProjectUtils.getInformation(project).getDisplayName();
                    }
                    else
                    {
                        projectName = "Multiple Projects";
                    }
                    demonstrateUpdateWindowTitle(projectName);
                }
            };
            // Activate the listener
            lookupResults.addLookupListener(lookupListener);
            lookupListener.resultChanged(null);
        }
    }
 
    static void demonstrateUpdateWindowTitle(final String projectName)
    {
        // We have to do this on the AWT thread, so we use the invokeWhenUIReady
        // method which can be called from any thread.
        {
            WindowManager.getDefault().invokeWhenUIReady(new Runnable()
            {
                @Override
                public void run()
                {
                    Frame mainWindow = WindowManager.getDefault().getMainWindow();
                    mainWindow.setTitle(projectName);
                }
            });
        }
    }
}


All of these examples work fine when a project is selected in the Projects window, but not when the focus is switched to another window, nor when a child node of a project is selected. What we want is for the selected project to be universally available throughout the scope of the entire application. What better way than to simply expand the scope of the Lookup contents provided by Utilities.actionsGlobalContext(). We can do this by creating a ProxyLookup that merges the default "global selection" with our own content that we control.

Basic Implementation

The first step is to create a service provider that implements the ContextGlobalProvider interface. Our service provider will supersede the default NetBeans implementation: GlobalActionContextImpl. When Utilities.actionsGlobalContext() is called, our class will return a ProxyLookup that includes the default implementation for the logical window-scope context, plus our own application-wide content. What you place in the application content is up to you, but some examples that I've used are Projects and NavigatorHints.

We'll start by creating a GlobalActionContextProxy class. Note the class comment about the Window System API dependency. Without it, we won't have access to the GlobalActionContextImpl class. To change the dependency, right-click your class' module and select: Properties > Libraries > Module Dependencies > Window System API > Edit… > Implementation Version.

/**
 * This class proxies the original ContextGlobalProvider.  It provides the ability 
 * to add and remove objects from the application-wide global selection.
 *
 * To use this class you must edit the Windows System API module dependency: 
 * change the dependency to an implementation version so that the 
 * org.netbeans.modules.openide.windows package is on the classpath.
 */
@ServiceProvider(service = ContextGlobalProvider.class, 
                 supersedes = "org.netbeans.modules.openide.windows.GlobalActionContextImpl")
public class GlobalActionContextProxy implements ContextGlobalProvider
{
    /** The native NetBeans global context Lookup provider  */
    private final GlobalActionContextImpl globalContextProvider;
    /** The primary lookup managed by the platform  */
    private Lookup globalContextLookup;
    /** The project lookup managed by this class  */
    private Lookup projectLookup;
    /** The actual Lookup returned by this class  */
    private Lookup proxyLookup;
    /** The additional content for our proxy lookup  */
    private final InstanceContent content;
 
    public GlobalActionContextProxy()
    {
        this.content = new InstanceContent();
 
        // Create the default GlobalContextProvider
        this.globalContextProvider = new GlobalActionContextImpl();
        this.globalContextLookup = this.globalContextProvider.createGlobalContext();
    }
 
    /**
     * Returns a ProxyLookup that adds the application-wide content to the original lookup
     * returned by Utilities.actionsGlobalContext().
     *
     * @return a ProxyLookup that includes the default global context plus our own content
     */
    @Override
    public Lookup createGlobalContext()
    {
        if (this.proxyLookup == null)
        {
            // Merge the two lookups that make up the proxy
            this.projectLookup = new AbstractLookup(content);
            this.proxyLookup = new ProxyLookup(this.globalContextLookup, this.projectLookup);
        }
        return this.proxyLookup;
    }
 
    /**
     * Adds an Object to the application scope global selection.
     */
    public void add(Object obj)
    {
        this.content.add(obj);
    }
 
    /**
     * Removes an Object from the application scope global selection.
     */
    public void remove(Object obj)
    {
        this.content.remove(obj);
    }
}
Complete Implementation

Here's a complete GlobalActionContextProxy that satisfies the three use cases described above. This implementation ensures that the currently selected Project remains in the global selection regardless of the current TopComponent. This is accomplished with the following:

package com.emxsys.projectassistant;
 
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectUtils;
import org.netbeans.api.project.ui.OpenProjects;
import org.netbeans.modules.openide.windows.GlobalActionContextImpl;
import org.openide.explorer.ExplorerManager;
import org.openide.loaders.DataObject;
import org.openide.nodes.Node;
import org.openide.util.ContextGlobalProvider;
import org.openide.util.Lookup;
import org.openide.util.Lookup.Result;
import org.openide.util.Lookup.Template;
import org.openide.util.LookupEvent;
import org.openide.util.LookupListener;
import org.openide.util.lookup.AbstractLookup;
import org.openide.util.lookup.InstanceContent;
import org.openide.util.lookup.ProxyLookup;
import org.openide.util.lookup.ServiceProvider;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;
 
 
/**
 * This class proxies the original ContextGlobalProvider and ensures the current project remains in
 * the GlobalContext regardless of the TopComponent selection. The class also ensures that when a
 * child node is selected within the in Projects tab, the parent Project will be in the lookup.
 *
 * To use this class you must edit the Windows System API module dependency: change the dependency
 * to an implementation version so that the org.netbeans.modules.openide.windows package is on the
 * classpath.
 *
 * @see ContextGlobalProvider
 * @see GlobalActionContextImpl
 * @author Bruce Schubert
 */
@ServiceProvider(service = ContextGlobalProvider.class,
                 supersedes = "org.netbeans.modules.openide.windows.GlobalActionContextImpl")
public class GlobalActionContextProxy implements ContextGlobalProvider
{
 
    /** The native NetBeans global context Lookup provider */
    private final GlobalActionContextImpl globalContextProvider;
    /** Additional content for our proxy lookup */
    private final InstanceContent content;
    /** The primary lookup managed by the platform */
    private Lookup globalContextLookup;
    /** The project lookup managed by resultChanged */
    private Lookup projectLookup;
    /** The actual proxyLookup returned by this class */
    private Lookup proxyLookup;
    /** A lookup result that we listen to for Projects */
    private Result<Project> resultProjects;
    /** Listener for changes resultProjects */
    private final LookupListener resultListener;
    /** Listener for changes on the TopComponent registry */
    private final PropertyChangeListener registryListener;
    /** The last project selected */
    private Project lastProject;
    /** Critical section lock */
    private final Object lock = new Object();
    private static final Logger logger = Logger.getLogger(GlobalActionContextProxy.class.getName());
    public static final String PROJECT_LOGICAL_TAB_ID = "projectTabLogical_tc";
    public static final String PROJECT_FILE_TAB_ID = "projectTab_tc";
 
    public GlobalActionContextProxy()
    {
        this.content = new InstanceContent();
 
        // The default GlobalContextProvider
        this.globalContextProvider = new GlobalActionContextImpl();
        this.globalContextLookup = this.globalContextProvider.createGlobalContext();
 
        // Monitor the activation of the Projects Tab TopComponent
        this.registryListener = new RegistryPropertyChangeListener();
        TopComponent.getRegistry().addPropertyChangeListener(this.registryListener);
 
        // Monitor the existance of a Project in the principle lookup
        this.resultProjects = globalContextLookup.lookupResult(Project.class);
        this.resultListener = new LookupListenerImpl();
        this.resultProjects.addLookupListener(this.resultListener);
 
        WindowManager.getDefault().invokeWhenUIReady(new Runnable()
        {
            @Override
            public void run()
            {
                // Hack to force the current Project selection when the application starts up
                TopComponent tc = WindowManager.getDefault().findTopComponent(PROJECT_LOGICAL_TAB_ID);
                if (tc != null)
                {
                    tc.requestActive();
                }
            }
        });
    }
 
    /**
     * Returns a ProxyLookup that adds the current Project instance to the global selection 
     * returned by Utilities.actionsGlobalContext().
     *
     * @return a ProxyLookup that includes the original global context lookup.
     */
    @Override
    public Lookup createGlobalContext()
    {
        if (proxyLookup == null)
        {
            logger.config("Creating a proxy for Utilities.actionsGlobalContext()");
            // Create the two lookups that will make up the proxy
            projectLookup = new AbstractLookup(content);
            proxyLookup = new ProxyLookup(globalContextLookup, projectLookup);
        }
        return proxyLookup;
    }
 
    /**
     * This class populates the proxy lookup with the currently selected project 
     * found in the Projects tab.
     */
    private class RegistryPropertyChangeListener implements PropertyChangeListener
    {
        private TopComponent projectsTab = null;
 
        @Override
        public void propertyChange(PropertyChangeEvent event)
        {
            if (event.getPropertyName().equals(TopComponent.Registry.PROP_ACTIVATED_NODES)
                || event.getPropertyName().equals(TopComponent.Registry.PROP_ACTIVATED))
            {
                // Get a reference to the Projects window
                if (projectsTab == null)
                {
                    projectsTab = WindowManager.getDefault().findTopComponent(PROJECT_LOGICAL_TAB_ID);
                    if (projectsTab == null)
                    {
                        logger.severe("propertyChange: cannot find the Projects logical window ("
                                     + PROJECT_LOGICAL_TAB_ID + ")");
                        return;
                    }
                }
                // Look for the current project in the Projects window when activated and handle 
                // special case at startup when lastProject hasn't been initialized.            
                Node[] nodes = null;
                TopComponent activated = TopComponent.getRegistry().getActivated();
                if (activated != null && activated.equals(projectsTab))
                {
                    logger.finer("propertyChange: processing activated nodes");
                    nodes = projectsTab.getActivatedNodes();
                }
                else if (lastProject == null)
                {
                    logger.finer("propertyChange: processing selected nodes");
                    ExplorerManager em = ((ExplorerManager.Provider) projectsTab).getExplorerManager();
                    nodes = em.getSelectedNodes();
                }
                // Find and use the first project that owns a node
                if (nodes != null)
                {
                    for (Node node : nodes)
                    {
                        Project project = findProjectThatOwnsNode(node);
                        if (project != null)
                        {
                            synchronized (lock)
                            {
                                // Remember this project for when the Project Tab goes out of focus
                                lastProject = project;
 
                                // Add this project to the proxy if it's not in the global lookup
                                if (!resultProjects.allInstances().contains(lastProject))
                                {
                                    logger.finer("propertyChange: Found project [" 
                                    + ProjectUtils.getInformation(lastProject).getDisplayName() 
                                    + "] that owns current node.");
 
                                    updateProjectLookup(lastProject);
                                }
                            }
                            break;
                        }
                    }
                }
            }
        }
    }
 
    /**
     * This class listens for changes in the Project results, and ensures a Project remains in the
     * Utilities.actionsGlobalContext() if a project is open.
     */
    private class LookupListenerImpl implements LookupListener
    {
        @Override
        public void resultChanged(LookupEvent event)
        {
            logger.finer("resultChanged: Entered...");
            synchronized (lock)
            {
                // First, handle projects in the principle lookup
                if (resultProjects.allInstances().size() > 0)
                {
                    // Clear the proxy, and remember this project. 
                    // Note: not handling multiple selection of projects.
                    clearProjectLookup();
                    lastProject = resultProjects.allInstances().iterator().next();
 
                    logger.finer("resultChanged: Found project [" 
                    + ProjectUtils.getInformation(lastProject).getDisplayName() 
                    + "] in the normal lookup.");
                }
                else if (OpenProjects.getDefault().getOpenProjects().length==0) 
                {
                    clearProjectLookup();
                    lastProject = null;
                }
                else
                {
                    if (lastProject == null)
                    {
                        // Find the project that owns the current Node
                        Node currrentNode = globalContextLookup.lookup(Node.class);
                        Project project = findProjectThatOwnsNode(currrentNode);
                        if (project != null)
                        {
                            lastProject = project;
                            logger.finer("resultChanged: Found project [" 
                            + ProjectUtils.getInformation(lastProject).getDisplayName() 
                            + "] that owns current node.");
                        }
                    }
                    // Add the last used project to our internal lookup
                    if (lastProject != null)
                    {
                        updateProjectLookup(lastProject);
                    }
                }
            }
        }
    }
 
    /**
     * Unconditionally clears the project lookup.
     */
    private void clearProjectLookup()
    {
        Collection<? extends Project> projects = projectLookup.lookupAll(Project.class);
        for (Project project : projects)
        {
            content.remove(project);
        }
    }
 
    /**
     * Replaces the project lookup content.
     * @param project to place in the project lookup.
     */
    private void updateProjectLookup(Project project)
    {
        if (project == null)
        {
            throw new IllegalArgumentException("project cannot be null.");
        }
        // Add the project if an instance of it is not already in the lookup
        Template<Project> template = new Template<Project>(Project.class, null, project);
        if (projectLookup.lookupItem(template) == null)
        {
            clearProjectLookup();
            content.add(project);
            logger.fine("updateProjectLookup: added [" 
            + ProjectUtils.getInformation(lastProject).getDisplayName() 
            + "] to the proxy lookup.");
        }
    }
 
    /**
     * Recursively searches the node hierarchy for the project that owns a node.
     *
     * @param node a node to test for a Project in its or its ancestor's lookup.
     * @return the Project that owns the node, or null if not found
     */
    private static Project findProjectThatOwnsNode(Node node)
    {
        if (node != null)
        {
            Project project = node.getLookup().lookup(Project.class);
            if (project == null)
            {
                DataObject dataObject = node.getLookup().lookup(DataObject.class);
                if (dataObject != null)
                {
                    project = FileOwnerQuery.getOwner(dataObject.getPrimaryFile());
                }
            }
            return (project == null) ? findProjectThatOwnsNode(node.getParentNode()) : project;
        }
        else
        {
            return null;
        }
    }
}

Tested with NetBeans IDE 7.2

How do I add an icon to the context menu?

NOTE: This is not recommended for NB RCP (i read something weeks ago, TODO add link here, markiewb), but is still possible.

Steps:

@ActionID(
        category = "Build",
        id = "sample.contextmenu.HelloIconAction")
@ActionReferences({
    @ActionReference(path = "Menu/File", position = 0),
    @ActionReference(path = "Loaders/Languages/Actions", position = 0),
    @ActionReference(path="Projects/Actions")
})
@ActionRegistration(
        displayName = "#CTL_HelloIconAction")

@Messages("CTL_HelloIconAction=Hello Icon Action")
public final class HelloIconAction extends AbstractAction implements Presenter.Popup {

    @StaticResource
    private static final String ICON = "sample/contextmenu/sample.gif";
    private static final long serialVersionUID = 1L;
    private final Lookup context;

    public HelloIconAction() {
        context = Utilities.actionsGlobalContext();
        putValue(SMALL_ICON, ImageUtilities.loadImageIcon(ICON, false));
        putValue(NAME, Bundle.CTL_HelloIconAction());
    }

    @Override
    public boolean isEnabled() {
        return null != context.lookup(Project.class);
    }

    @Override
    public void actionPerformed(ActionEvent ev) {
        JOptionPane.showMessageDialog(null, "Hello colorful project.\n" + context.lookup(Project.class).toString());
    }

    @Override
    public JMenuItem getPopupPresenter() {
        return new JMenuItem(this);
    }
}

[1] http://wiki.netbeans.org/DevFaqChangeMenuItemToolbarAppearanceForAction
[2] http://forums.netbeans.org/topic40762.html
[3] http://benkiew.wordpress.com/2012/12/28/netbeans-how-to-create-a-context-aware-action-with-an-icon-for-the-context-menu/

How do I add an action to the context menu of the members or hierarchy view?

Since 7.3 ([1], [2]) it is possible to extend the context menu of the newly redesigned members and hierarchy view.

Plugin your action at the following extension points

Navigator/Actions/Members/text/x-java
Navigator/Actions/Hierarchy/text/x-java

Then you get the "TreePathHandle" from the Node's lookup.

A more or less complete example:
package de.markiewb.netbeans.sample.extendMembersAndHierarchyView;

import java.util.ArrayList;
import java.util.List;
import static javax.swing.Action.NAME;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import org.netbeans.api.java.source.TreePathHandle;
import org.openide.awt.*;
import org.openide.nodes.Node;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;
import org.openide.util.actions.CookieAction;
import org.openide.util.actions.Presenter;

@ActionID(category = "Edit",
	id = "de.markiewb.netbeans.sample.extendMembersAndHierarchyView.SampleAction")
@ActionRegistration(
	displayName = "SampleAction")
@ActionReferences({
    @ActionReference(path = "Navigator/Actions/Members/text/x-java", position = 1150),
    @ActionReference(path = "Navigator/Actions/Hierarchy/text/x-java", position = 1150),
    @ActionReference(path = "Menu/File", position = 0)
})
/**
 * Shows the usage of the extensionpoints of the context menu in the members and
 * hierarchy views. This is new to NetBeans 7.3. See
 * http://netbeans.org/bugzilla/show_bug.cgi?id=220057 and
 * http://netbeans.org/bugzilla/show_bug.cgi?id=224499.
 *
 * @author markiewb@netbeans.org
 */
public final class SampleAction extends CookieAction implements Presenter.Popup {
    public SampleAction() {
	putValue(NAME, "Hello TreePathHandle(s)");
    }

    @Override
    public String getName() {
	return "Hello TreePathHandle(s)";
    }

    @Override
    public JMenuItem getPopupPresenter() {
	return new JMenuItem(this);
    }

    @Override
    public HelpCtx getHelpCtx() {
	return null;
    }

    @Override
    protected boolean enable(Node[] activatedNodes) {
	//.. use tph from lookup in node
	for (Node node : activatedNodes) {
	    if (null != node.getLookup().lookup(TreePathHandle.class)) {
		return true;
	    };
	}
	return false;
    }

    @Override
    protected int mode() {
	return CookieAction.MODE_ALL;
    }

    @Override
    protected Class[] cookieClasses() {
	return new Class[]{Node.class};
    }

    @Override
    protected void performAction(Node[] nodes) {

	List<TreePathHandle> treePathHandles = new ArrayList<TreePathHandle>();
	for (Node node : nodes) {
	    treePathHandles.add(node.getLookup().lookup(TreePathHandle.class));
	}

	//show all treePathHandles
	JOptionPane.showMessageDialog(null, "Hello\n" + treePathHandles);
    }
}

See
[1] http://netbeans.org/bugzilla/show_bug.cgi?id=220057
[2] http://netbeans.org/bugzilla/show_bug.cgi?id=224499
[3] https://github.com/markiewb/nb-api-samples/tree/master/ExtendMembersAndHierarchyView
[4] http://benkiew.wordpress.com/2013/01/06/netbeans-ide-7-3-how-to-extend-the-context-menu-of-the-members-and-hierarchy-view/

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)

Alternative:
T obj=FileUtil.getConfigObject("Actions/Window/org-foo-B.instance", T.class) 
 
//for example:
Action action=FileUtil.getConfigObject("Actions/Window/org-netbeans-core-windows-actions-ResetWindowsAction.instance", Action.class)

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?

Answer from this post:

FileObject fo = FileUtil.toFileObject(new File("test.js").getAbsoluteFile()); 
DataObject newDo = DataObject.find(fo); 
final Node node = newDo.getNodeDelegate(); 
Action a = node.getPreferredAction(); 
if (a instanceof ContextAwareAction) { 
       a = ((ContextAwareAction) a).createContextAwareInstance(node.getLookup()); 
} 
if (a != null) { 
      a.actionPerformed(new ActionEvent(node, ActionEvent.ACTION_PERFORMED, "")); // NOI18N 
}

Keep in mind that this must be called from the EDT thread, it'll raise a RuntimeException otherwise.

Approach 2
FileObject fileObject=...
DataObject.find(fileObject).getLookup().lookup(OpenCookie.class).open();

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

See also: How to Add Content to the Global Context

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:

https://blogs.oracle.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:

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.

Remove the expander, if you know the parent-/child-hierarchy at creation time

(Taken from platform-dev mailinglist - author Mark J.Koch - mark@maehem.com)

In my case, our Nodes are backed by actual objects that know their own parent/child hierarchy. First we create our Nodes always as LEAF nodes by default and then set the children (if there are children) later. I have a method in my Node that get's called whenever our data model changes. First we check if we are already a LEAF node, and if we are, and we have children, we simply initialize the children. If we already have children, we check if our current data model has children here and either update our children keys or explicitly set Children.LEAF if there are no children.

This will properly make the expander disappear when there are no children.

void myModelChanged() {
    if (this.isLeaf()) {
        if (getObject().hasChildren()) {
            initChildren();
        }
    } else {
        if (getObject().hasChildren()) {
            // Cause children to regenerate it's key list.
            this.getChildren().addNotify();
        } else {
            // We no longer have children. Change to leaf.
            setChildren(Children.LEAF);
        }
    }
} 

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

Command Line Parsing

Can something that the user sets on the command line determine whether a menu item is enabled?

Info on this here.

Same as the above, but this time for enabling/disabling modules?

Info on this here.

How to pass command line arguments to a NetBeans Platform application when run inside the IDE

Open "nbproject/project.properties" and add there:

run.args.extra=-arg1 --argument2

Platform parsing command line arguments

A new features since NetBeans Platform 6 is the ability to parse the command line.

So, let’s try to parse the command line to automatically open a document when the NetBeans Platform starts up. The example below uses the Sketsa SVG Editor as an example:

      public class SketsaOptionProcessor extends OptionProcessor {
 
          private Option openOption = Option.defaultArguments();
          private Option openOption2 = Option.additionalArguments(
                                                      'o', "open");
 
          @Override       
          public Set getOptions() {
              HashSet set = new HashSet();
              set.add(openOption);
              set.add(openOption2);
              return set;
          }
 
          @Override
          public void process(Env env, Map values) 
                              throws CommandException {
              List<string> filenameList = new ArrayList<string>();
              Object obj = values.get(openOption);
              if (obj != null) {
                  filenameList.addAll(Arrays.asList((String[]) obj));
              }
              obj = values.get(openOption2);
              if (obj != null) {
                  filenameList.addAll(Arrays.asList((String[]) obj));
              }
 
              for (int i = 0; i &lt; filenameList.size(); i++) {
                  File file = new File(filenameList.get(i));
                  if (!file.isAbsolute()) {
                      file = new File(env.getCurrentDirectory(),
                           filenameList.get(i));
                  }
 
                  //System.out.println(file.toString());
 
                  try {
                      DataObject data = DataObject.find(
                          FileUtil.toFileObject(file));
                      OpenCookie cookie = data.getCookie(OpenCookie.class);
                      cookie.open();
                  } catch (OutOfMemoryError ex) {
                      String msg = Application.getMessage(
                             "MSG_OutOfMemoryError.Text");
                      NotifyDescriptor nd = new NotifyDescriptor.Message(
                              msg, 
                              NotifyDescriptor.ERROR_MESSAGE);
                      DialogDisplayer.getDefault().notify(nd);
                  } catch (Exception ex) {
                      NotifyDescriptor nd = new NotifyDescriptor.Message(
                              ex.getMessage(), 
                              NotifyDescriptor.ERROR_MESSAGE);
                      DialogDisplayer.getDefault().notify(nd);
                  }
              }
          }


The important parts here are the two overidden methods "getOptions()" and "process(Env,Map)". The getOptions indicate which command line you want to capture, in this case we want to capture defaultArgument and -open some_file or -o some_file. So the following will work:

      sketsa artwork.svg
      sketsa --open artwork.svg
      sketsa -o artwork.svg
@ServiceProvider(service=OptionProcessor.class)
public class SketsaOptionProcessor extends OptionProcessor {
// trimmed
}

This indicates generates appropriate META-INF/services/org.netbeans.spi.sendopts.OptionProcessor file during compilation.

Creating a Custom Programming Language

How do I add syntax highlighting for my language?

Problem: I have a custom programming language that I want to make available in the NetBeans platform. How do I add syntax highlighting for my language?

Solution: Here is a tutorial on syntax highlighting for custom languages: http://wiki.netbeans.org/SyntaxColoringANTLR

How can I create a custom Debugger for my language?

Problem: I have a debugger built for my custom programming language. How do I integrate it into the NetBeans Platform?

Solution: Here is a tutorial on integrating a custom Debugger: http://netbeans.dzone.com/how-reuse-netbeans-debugger

Window System

What is the window system

The windowing system is what creates the main application window, and makes it possible to open components in the UI. The API for the windowing system is in the package org.openide.windows. The implementation of the windowing system is in the module org.netbeans.core.windows (core.windows in Mercurial repository, was core/windows in CVS).

The window system defines Modes which are places in the main window occupied by tabbed containers. TopComponents are GUI components (instances or subclasses of org.openide.windows.TopComponent which can be put into these tabbed containers.

There is a programmatic API for creating/opening TopComponents - this is useful for testing components under development - just create an Action which calls new MyTopComponent().open() to quickly try out GUI components.

However, the main API modules use the declarative XML Window System API to install their components, for the following reasons:

What are Modes?

"Mode" refers to "docking mode". A Mode is a place in a main window, a place between splitters. Separate "floating" window is also backed by Mode. Mode is usually visually represented by a tabbed container. Programmatically it is represented by the class org.openide.windows.Mode

Think of a Mode as synonymous with a one of the tabbed containers you see in the IDE's main window. The name "Mode" is historical, and a bit unfortunate. When you hear "Mode," think tabbed container and you'll be fine.

A Mode is not a GUI component. There is no legitimate programmatic way to fetch the component that represents a Mode on-screen, and the windowing system makes no guarantees about what that component is.

Modes can contain one or more TopComponents. They may be visible or non-visible at any given time.

The DevFaqCustomWindowMode page has a visual representation of the available modes, and http://bits.netbeans.org/dev/javadoc/org-openide-windows/org/openide/windows/doc-files/api.html has details about the contents of wstcref and settings files.

Pre-Defined Modes

NetBeans defines six modes in core.ui:

NetBeans defines additional modes in other places:

Docking a TopComponent into a Mode

To dock a TopComponent into the 'editor' mode:

Mode myMode = WindowManager.getDefault().findMode("editor");
TopComponent myTopComponent = WindowManager.getDefault().findTopComponent("MyTopComponent");
myMode.dockInto(myTopComponent);

The ID string of the TopComponent can usually be found in that TopComponent's Java file where it gets registered using annotations, or in the layer.xml.

What are TopComponents?

org.openide.windows.TopComponent is a JComponent subclass which knows how to work with the NetBeans window system. If you want to add components to the main window, typically you will subclass TopComponent, using it the same way you would a JPanel.

TopComponents live inside Modes - docking containers.

TopComponents can have various states:

Each TopComponent has a Lookup and one or more activated Nodes. These define the selection context for the window system, which determines what actions (menu items, toolbar buttons, etc.) are enabled, and in some cases, what they will do or operate on if invoked.

TopComponents are part of the Windows API.

TopComponents that were already open may be deserialized and reopened on restart. The template that NetBeans 5.0 provides includes code for this - it is actually using saved using the Externalizable interface. Whether or not it is saved is determined by what you return from getPersistenceType().

For information on how and when these are reconstructed on startup, see the gory details of the window system on startup.

How do I use Matisse/GroupLayout (new form editor/layout manager in 5.0) in my windowing system components

When you create a new window system component ( TopComponent) using the template wizard in NB 5.0 or greater, the default layout manager is GroupLayout (the new, super-easy-to-design-with layout manager in NB 5.0). So you do not need to do anything special. Your module will have a declared dependency on the corresponding library module which is in the NB Platform as of 5.0.

GroupLayout is included in JDK 6; as long as JDK 5 needs to be supported (until JDK 8 is released at a minimum), NetBeans will use the library version rather than the JDK 6 version.

Applies to: NetBeans 5.0, 5.5, 6.x

I want to show my own component(s) in the main window - where do I start?

Use File -> New File wizard, Module Development category and Window Component item. It will generate all necessary background code for you and open GUI Builder to design UI of your own component.

But what is behind the scenes, created by wizard?
public class MyAction extends AbstractAction {
   public MyAction() {
      putValue (Action.NAME, "Open My Component");
   }

   public void actionPerformed(ActionEvent ae) {
      new MyComponent().open();
   }
}

TopComponents are part of the Windows API.

Windows and dialogs

Can I just open up my own frames and dialogs?
What are the steps to create a simple Wizard?

__Easiest way is to use File -> New File wizard, Module Development category and Wizard item, which will generate all needed boilerplate code for you. Essentially what wizard does is described below:__

Create Panels:

You should start with creating a set (at least one) on WizardDescriptor.Panel objects (see Wizard Panel Performance Guide for more information about the best way to create a panel).

Create WizardDescriptor

Use the panels to tell the a WizardDescriptor instance the sequence of panels it should display. This you can do either directly by WizardDescriptor wd = WizardDescriptor(wizardPanelArray) Or you can create a WizardDescriptor.Iterator with these panels, which gives you more control over the sequencing.

Set Properties

Set certain properties on the WizardDescriptor which can influence the appearence of the wizard. If you like to add a help pane for example you call: wd.putProperty("WizardPanel_autoWizardStyle",Boolean.TRUE); wd.putProperty("WizardPanel_helpDisplayed",Boolean.TRUE);

This will display a help html file which has to be defined on each panel by setting a clientProperty in the JComponent superclass of the panel that is the wizard content. In this case it would look like:

putClientProperty("WizardPanel_helpURL",new URL("http://path/to/help/html/file/panelHelp.html"));

Show Wizard

Finally you set the Wizard to screen using the DialogDisplayer

Dialog d = DialogDisplayer.getDefault().createDialog(wd);

        d.setVisible(true);

        d.toFront();

How does the XML API for installing window system components work?

The API is not hard, just a bit baroque.

On startup, the window system needs to know some things to construct the main window, and possibly restore the state it was in before shutdown:

It would be a disaster for performance if all possible components in the system had to be instantiated/deserialized during startup just to figure out if they actually need to be on screen. The XML definitions for window system components allow a module to completely declaratively provide all the information described above.

There are three main file types to be concerned with - these are put in the System Filesystem by declaring them in your module's layer file:

See also:

How do I use .wstcrf/.wsmode/.settings files to install my module's components in the window system?

The window system on screen is composed of tabbed areas called "modes" (originally this was intended as "docking mode" as in the way a component is docked into the main window - yes, it's a lousy name). These correspond to the class org.openide.windows.Mode. In the system filesystem, each Mode is represented by a folder.

At least in theory, a TopComponent can exist in more than one Mode, so there is a one-to-many relationship. The pre-NetBeans 3.6 windowing system had a concept of "workspaces", and a Mode could be opened on multiple workspaces. So instead of putting TopComponents (as represented by the .settings files) into the folders directly, you put those settings files into the Windows2Local/Components folder. And you put a Window System Top Component Reference - or .wstcrf - lovely to pronounce - in the mode folder. It's like a symbolic link, pointing to the .settings file in the Windows2Local/Components folder via its ID. That way, one TopComponent could be linked to by several Modes.

Modes have configuration data too, such as the constraints for where in the main window they should appear - what side, what TopComponent should be selected etc. So for each Mode defined in Windows2/Modes, there is also a .wsmode file that contains that information.

The system filesystem is read-write - so changed information (for example, the user dragged a tab to a different Mode or opened or closed it) is saved to the user's settings directory, transparently. On a restart, the saved information will be read in and restored.

So what happens is, if the user changes the position of windows, the selected tab, the splitter positions, etc., then new versions of the .settings, .wsmode or .wstcref files will be saved in the userdir in order to restore the state on restart to how the user had configured it.

One handy way to generate all of those files, rather than doing it by hand, is to just create an action in your module that will open your TopComponent. Run it on a clean userdir, open your TopComponent, and put it where you want it to appear. Shut down. Go into your user dir, and copy the files the IDE persisted into your module. Edit to taste, add references in your module's layer file (any module that opens a component is a good example - try core/navigation) and voila.

You may want to look at the samples - there are example modules that use all of the declarative window system APIs and file formats.

My TopComponent always opens in the editor area, but I want it to open in the same place as XYZ

By default, TopComponent.open() opens all components in the central editor area of the main window. Overriding this is simple:

public MyTopComponent extends TopComponent {
  public void open() {
     Mode m = WindowManager.getDefault().findMode ("output");
     if (m != null) {
        m.dockInto(this);
     }
     super.open();
  }
}

You need to know the ID of the Mode you want to put the component in. Common IDs are "output" for the bottom of the screen, and "explorer" for the left side. For other Modes, you may need to find a module that puts something there and read its layer files, or browse the System Filesystem.

Eventually you will probably want to specify what mode to dock your component into using the XML API for installing components, but the above technique works for simple modules, testing, etc.

Why does TopComponent have a getLookup() method? What is it for?

The windowing system is what manages global selection. In olden times, selection meant the activated Node.

In modern NetBeans, the global selection is really whatever objects are in the focused TopComponent's Lookup. It so happens that most standard TopComponents display Nodes - so for most TopComponents, the component's Lookup is just proxying the Lookup of the selected Node.

Rather than thinking of the selection as some specific object or Node, it is more useful to think of it as a grab bag of stuff provided by whatever component happens to have focus. If you use Utilities.actionsGlobalContext(), you do not have to track all the different grab-bags of stuff provided by different components - you can get one grab bag of stuff which whose content will simply change (notifying you in the process) when focus moves to a different component.

So the TopComponent's Lookup is a way to provide your particular grab bag of stuff - it can be the lookup of a Node if you want, or it can be/contain whatever else or in addition you'd like to put there.

I want to disable the popup menu on the toolbars in the main window. How do I do that?

There is no canonical (or pretty) way to do this, but there is a hack you can do - it works in NetBeans 5.0, 5.5 and 6.x (and probably earlier versions but this wasn't tested).

Create the following ModuleInstall class (remember to add a reference to it in the module manifest, e.g.

OpenIDE-Module-Install: org/netbeans/modules/toolbarthing/Installer.class

If you are using 5.0's update 1 of module development support or later, you can just use New File > NetBeans Plug-In Modules > Module Installer):

package org.netbeans.modules.toolbarthing;
import java.awt.Component;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JToolBar;
import org.openide.modules.ModuleInstall;
import org.openide.windows.WindowManager;
public class Installer extends ModuleInstall implements Runnable {

    public void restored() {
         WindowManager.getDefault().invokeWhenUIReady(this);
    }

    public void run() {
        JToolBar[] tb = findToolbars();
        for (int i = 0; i < tb.length; i++) {
            processToolbar (tb[I]);
        }
    }

    private JToolBar[] findToolbars() {
        List l = new ArrayList();
        JFrame jf = (JFrame) WindowManager.getDefault().getMainWindow();
        findToolbars (jf.getContentPane(), l);
        JToolBar[[ | ]] tb = (JToolBar[[ | ]]) l.toArray(new JToolBar[L.size()]);
        return tb;
    }

    private void findToolbars(Component c, List l) {
        if (c instanceof JToolBar) {
            l.add(c);
        } else if (c instanceof Container) {
            Component[] cc = ((Container) c).getComponents();
            for (int i=0; i < cc.length; i++) {
                findToolbars(cc[I], l);
            }
        }
    }

    private void processToolbar (JToolBar bar) {
        MouseListener[] ml = bar.getMouseListeners();
        for (int i = 0; i < ml.length; i++) {
            if (ml[I].getClass().getName().indexOf("PopupListener") >= 0) {
                bar.removeMouseListener (ml[I]);
            }
        }
    }
}

The above doesn't seems to work in 6.9.1. This is another similar module installer hack to achieve this:

public class Installer extends ModuleInstall
{

  public void restored()
  {
    removeToolbarPopupMenu();
  }

  private void removeToolbarPopupMenu()
  {
    WindowManager.getDefault().invokeWhenUIReady(
      new Runnable()
      {
        @Override
        public void run()
        {
          removeAllPopupListeners(ToolbarPool.getDefault());
        }
      });
  }

  private static void removeAllPopupListeners(Component c)
  {
    if(c instanceof Container)
    {
      for(Component c2 : ((Container)c).getComponents())
      {
        for(MouseListener l : c2.getMouseListeners())
        {
          if(l.getClass().getName().contains("PopupListener"))
          {
            c2.removeMouseListener(l);
            // Uncomment to obtain a similar console output
            // Removing: org.openide.awt.ToolbarPool$PopupListener@1535ac from javax.swing.JPanel[...]
            // Removing: org.openide.awt.ToolbarPool$PopupListener@1535ac from org.openide.awt.Toolbar[File,...]
            //System.out.println("Removing: " + l + " from " + c2);
          }
        }
        findToolbars(c2);
      }
    }
  }
}

How can I change the executable's icon?

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

'Application Icon' Images

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

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

Windows Icons

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

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

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

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

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

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

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

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

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

Mac Icons

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

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

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

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

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

Since Netbeans 6.9 (Issue #182230) is possible to specify the Mac dock icon just by setting the property app.icon.icns in your build.xml

   <import file="nbproject/build-impl.xml"/>
   <property name="app.icon.icns" value="${basedir}/myappicon.icns"/>
Related links

How does the window system really work?

Below is a blow-by-blow account of what actually goes on during NetBeans startup, put together by, well, reading the code. It's here as much for the author's edification (if you read through it and document it, you understand it) as yours.

The three and a half models model

The NetBeans window system is extremely defensively coded - one of the main goals of rewriting it for 3.6 was robustness in the face of components that throw exceptions, do evil things to other components, and so forth. The way the robustness of the current system is achieved is by very cleanly separating the model of how the UI should be, the model of how the UI actually is and the AWT component hierarchy, which is a model of sorts itself, but cannot be relied upon, because in an extensible application any component may do something evil. On top of this is the persistence model.

UIs are hierarchical, with components inside containers inside other containers - so each model we'll describe is hierarchical to represent this. TopComponents (panels in tabbed container) get a little special handling because there's a potential one-to-many relationship between TC's and tabbed containers (an implication of winsys v1, where one component could live in more than one docking Mode (tabbed container) per workspace).

So, the models (names made up for the purpose of this document):

Reading the source to the window system can be a little complicated, because there are multiple models of the same thing all being synchronized, and just about everything follows a chain of single-method-call methods back to Central or WindowManagerImpl. Hence this document.

In its essence, though it's simple: all changes in the window system simply mean synchronizing the two runtime models. It's only the number of classes that requires that make it look complex.

The Window System Startup Sequence

Loading the window system is a distinct phase in NetBeans startup. A set of model objects representing the window manager (data like SDI vs. MDI, frame size/location/state), its Modes (docking containers - bounds, contents), and references to TopComponents by ID (not the components themselves, but unique String ids for them).

Once all this is done, we'll have a set of model objects representing all the persisted data. Note that these model objects are not the ones used by the model of the window system at runtime, there are different classes for that.

Here's the load sequence:

WindowSystemImpl

  • that gets an XML parser
  • the parser creates a WindowManagerConfig from data it finds in XML files. A WindowManagerConfig just has a lot of public fields from parsed data, that refers to other similar objects
  • ModeConfig - information about a docking container, placement, contents
  • TcRefConfig - references to a TopComponent by ID, no component there yet
  • GroupConfig - Refers to a Group of TopComponents (like form editor + its palettes)
  • TcGroupConfig - Reference to a TopComponent by a GroupConfig
  • InternalConfig - Just notes what version of the window system saved the date we loaded

Now we're back out in PersistenceManager. We:

Now we have a model for the contents of the window system as it was persisted...

Back in PersistenceHandler.load() now, we build the runtime model of the window system (note that except for deserializing TopComponents, we're not creating any components yet, we're just creating model objects that will be represented by GUI components in the UI):

  • for each, deserialize the TopComponent in question
  • for each, create a ModeImpl (note this is a model object, not a tabbed container)
  • if the mode was active at shutdown last time, remember that fact in a local variable
  • if the mode was persisted as maximized, remember that fact in a local variable
  • initialize each one from the ModeConfig it was created for
  • iterate all TcRefConfigs in the ModeConfig, extract some persisted data about the "previous mode" the TopComponent was in, and pass that data to the window system - this is so that sliding windows know where they should land if the user presses the "pin" button to put them in a tabbed container
  • For each TcGroupConfig (PersistenceHanponent reference), add the ID into the list of IDs in the TcGroup
  • Check the boolean open flag for the TcGroupConfig. If true, it's a component that, when opened, should open the entire group
  • Check the boolean flag whether the TopComponent was closed explicitly by the user. If true, when the group of components are all opened, leave that one closed
  • Check the boolean flag whether the TopComponent was reopened explicitly by the user, and if so, ignore the result of the closed flag - add it to the list of ids that should open

Note the group handling code is a little different than the rest in terms of the way it's modelled - this should probably be corrected - it appears that for some reason, PersistenceHandler holds the data for that, there is no corresponding model object for TC's in a group (not necessarily bad, but inconsistent), and the data is passed to the window manager before its initialized (harmless, but odd). On the other hand, it's less complicated.

We're not done yet.

We now have a singleton instance of WindowManagerImpl, with its model fully initialized from persisted data (or a semi-sane default if de-persisting failed). It will be available from WindowManager.getDefault();

Showing/creating the UI

The next phase happens when setVisible(true) is called on the window system. A thing to know here if you read the code is that all requests to do anything in the window system are funneled through one class called Central (yes, Central is the God Object anti-pattern). So pretty much any method that you look at in the model objects will call back through a method in Central, sometimes to itself, sometimes to some other object.

So...

  • asserts we're on the EDT
  • installs the global KeyEventDispatcher on Swing's KeyboardFocusManager to handle action bindings
  • calls WindowManagerImpl.getInstance().setVisible(true) - that in turn checks that its a state change and calls
  • Central.setVisible(true) which calls DefaultModel.setVisible(true) (this just stores the boolean value in a field)
  • calls ViewRequestor.scheduleRequest() - enqueues a runnable that will set the window system's visibility property to true, which
    • has a special check if it's a visibility change request, and if so tries to run it immediately if on the EDT (semi-BUG: it will always be the EDT, unless the assertion is turned off)

Now we're into the runtime behavior of the window system - this system of enqueuing requests is how code that will change window system state operates: A change is made to the model of the expected state of the window system, and the requested change is encoded in an object that will be processed in a subsequent event on the EQ. ViewRequestor keeps a list of all pending changes, and coalesces changes to the same value. When the request is processed, the state of the UI (open components, positions, splitter positions, everything) as described by the model is composed into a "snapshot", which is then used to set the necessary parameters on the UI components.

But right now, we're still just showing the window system, period. Here's what happens:


  • For each, create a ViewEvent and add it to a list of events to be processed
  • and passes that to ViewRequestor.dispatchRequest, which
  • passes them to DefaultView.changeGUI(). View is an interface representing the UI state of the entire window system. It's another set of model objects, this time modelling the state of the component. For each model object (ViewElement, ModeContainer, ModeView are interfaces the winsys implements elsewhere...), there is also an "accessor" object, which is what actually talks to the UI component.

DefaultView.changeGUI is what will actually modify the UI. A ViewEvent is pretty much like a PropertyChangeEvent, with an old value and a new value, but with an integer type instead of a property name. What it does:

  • for each, check the type, and for each type, cast the new value and old value to the proper types, and
  • call a setter on the UI-view-model object that in turn should call something on the actual UI component

But we're getting ahead of ourselves here - as you may have noticed above, if it's a window system visibility request, we actually exit before we've gotten to iterating all the ViewEvents the second time, to change component state and so forth.

I should mention ViewHierarchy here - it's not a very exciting class, but it's the root model for the UI model objects, so when you have one of those Accessor objects for a Mode or a component in a mode, it's where you get the corresponding model object whose setters will actually call the real UI component.

So let's go back to where we call windowSystemVisibilityChanged(). What that does:


  • set the icon
  • add a WindowListener that will call LifecycleManager.exit() on WindowClosing, and close menus if the window is deactivated
  • set the menu bar (this calls a whole bunch of code that generates the menu from folders of actions in the system filesystem - we won't cover it here)
  • install the toolbar panel
  • Install the statusbar (and check the special constant for putting it in the menubar for screen real estate freaks)
  • Install a JPanel at BorderLayout.CENTER, called desktopPanel, which our window system will live in in MDI mode
  • Install a hack listener on MenuSelectionManager to focus the main window if a menu is activated - this is SDI mode specific - you can invoke a menu by mnemonic but then the keyboard doesn't work unless you send focus to the main window - see issue #38810

Now we're back out in DefaultView.windowSystemVisibilityChanged(). What we do now:

  • Calls back to WindowManagerImpl and gets the main window bounds (different calls for MDI and SDI). We stored this value there when we loaded the window system data, from WindowManagerConfig
  • If not empty, set those bounds on the main window

MKLEINT: again this is a hacky workaround to the fact that one cannot prepare a maximized version of the frame before it's shown.

At this point we've got our main window up and ready to go.

Obvious questions for those unfamiliar with the winsys:

Q: So where do all the tabbed containers and split panes come from? You didn't mention those.

A: The actual implementations of ViewElement (things that own ViewEvents), like org.netbeans.core.windows.view.ModeView actually create the UI components they talk to in their constructors

Q: Why are TopComponents treated so differently and what's this reference stuff in the de-persisting process?

A: In the pre-3.5 window system, a component could be open in more than one tabbed container at the same time. What??? It is because of workspaces, which we got rid of. A workspace was a switchable window system configuration or set of windows. The interface is still there, but there is only ever one workspace in the post 3.5 winsys. So any given Mode, for legacy reasons, is not sole owner of a TopComponent, it just has a handle for one.

How can I replace the Window System?

Perhaps your users are a bit confused by the ability to close, slide or dock windows or maybe you're trying to retain the behavior of some existing application's window system. There are times, however rare, in which you want to replace the typical NetBeans Window Manager org.netbeans.core.windows.WindowManagerImpl with a different one.

Before doing this you should know that starting with NetBeans 6.5, it will be easy to change certain behaviors of the window system. So needing to replace the window manager is rare already and will be needed even less often in the future.

But if you still want to do it, you can:

Of course, there's a lot of work involved in creating your own WindowManager implementation, but you can have a look at the org.openide.windows.DummyWindowManager class for starters. It's a simple implementation that opens all TopComponents in their own frame but which can also make windows invisible which is handy for testing.

The DummyWindowManager is used as a last resort when no other window manager is present; you will not need to register it in the default Lookup as described earlier. If you want to use it, keep in mind these two tips:

How do I set the initial size of the main window?

The default initial size of an application based on NetBeans platform is 90% of the whole screen area and the main window is also centered. These defaults can be redefined quite easily:

    <folder name="Windows2">
        <file name="WindowManager.wswmgr" url="WindowManager.wswmgr"/>
    </folder>
    <main-window> 
        <joined-properties centered-horizontally="true" centered-vertically="true"
                           relative-width="0.5" relative-height="0.5" />
        <separated-properties centered-horizontally="true" relative-y="0.1"
                           relative-width="0.8" relative-height="0.08" />
    </main-window>

The snippet from windowmanager.wswmgr above makes the default main window size to be half of the whole screen area.

    <main-window>
      <joined-properties x="0" y="0"   width="800"   height="600"
                  relative-x="0.0"   relative-y="0.0"   relative-width="0.0"   relative-height="0.0"   centered-horizontally="false"   centered-vertically="false"
                  maximize-if-width-below="0"   maximize-if-height-below="0"   frame-state="6"/>
     <separated-properties   x="160"   y="116"   width="1280"   height="93"
	   relative-x="0.0"   relative-y="0.0"   relative-width="0.0"   relative-height="0.0"   centered-horizontally="false"   centered-vertically="false"   frame-state="0" />
  </main-window>

The snippet from windowmanager.wswmgr above opens the main window in the upper left corner of the screen and makes its size 800x600 pixels.

Note: This way you can also define the default main window state - maximized/minimized/restored, see JavaDoc for possible values.

I want to create a TopComponent class to use as an editor, not a singleton

This entry is about creating non-text-editor (e.g. graphical) editors for files or other objects. If you want a text editor, NetBeans has a lot of built-in support for text editors and you will probably want to use DataEditorSupport.create() and its relatives (hint: New > File Type will get you basic text editor support which you can build on).

If you want to create some other kind of editor, you will probably want to start by creating a non-singleton TopComponent - a logical window, or tab, that can be opened in the editor area and can show your file or object in some way.

Our editor component will be fairly simple. It will have two constructors, one which takes a DataObject (the file) and one which has no arguments:

  public MyEditor() {
  }

  MyEditor(FooDataObject ob) throws IOException {
    init(ob);
  }

and it will have an initialization method. In our case, since this is a simple example, we will use a JTextArea. Our DataObject subclass will have a method setContent(String) which is passed the updated text if the user types into the text area. The DataObject will take care of marking the file modified and saving it when the user invokes the Save action. So we will just pass the text the user changed to the DataObject and update the tab name of the editor to show if the file is modified in-memory or not:

  void init(final FooDataObject file) throws IOException {
    associateLookup(file.getLookup());
    setDisplayName(file.getName());
    setLayout(new BorderLayout());
    add(new JLabel(getDisplayName()), BorderLayout.NORTH);
    //If you expect large files, load the file in a background thread
    //and set the field's text under its Document's lock
    final JTextField field = new JTextField(file.getPrimaryFile().asText());
    add(field, BorderLayout.CENTER);
    field.getDocument().addDocumentListener(new DocumentListener() {

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

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

      @Override
      public void changedUpdate(DocumentEvent e) {
        FooDataObject foo = getLookup().lookup(FooDataObject.class);
        foo.setContent(field.getText());
      }
    });
    file.addPropertyChangeListener(new PropertyChangeListener() {
      @Override
      public void propertyChange(PropertyChangeEvent evt) {
        if (DataObject.PROP_MODIFIED.equals(evt.getPropertyName())) {
          //fire a dummy event
          setDisplayName(Boolean.TRUE.equals(evt.getNewValue()) ? file.getName() + "*" : file.getName());
        }
      }
    });
  }

As of NetBeans 6.8, modified files are usually shown with a boldface tab name, so for consistency we should too:

 @Override
 public String getHtmlDisplayName() {
   DataObject dob = getLookup().lookup(DataObject.class);
   if (dob != null && dob.isModified()) {
     return "<html><b>" + dob.getName();
   }
   return super.getHtmlDisplayName();
 }

The persistence code (described here) will save the file's path on disk, and on restart, reinitialize the editor (if the file still exists).

The code to do this is actually quite simple - it can be boiled down to loading:

init (DataObject.find(FileUtil.toFileObject(FileUtil.normalizeFile(new File(properties.getProperty("path"))));

and saving

 properties.setProperty (FileUtil.toFile(dataObject.getPrimaryFile()).getAbsolutePath());

That is, all we are doing is saving a path on shutdown, and on restart looking that file up, transforming it into a NetBeans FileObject, and initializing with the DataObject for that. It just happens that we have to handle a few corner cases involving missing files and checked exceptions:

So our persistence code looks like this:

 private static final String KEY_FILE_PATH = "path";
 void readProperties(java.util.Properties p) {
   String path = p.getProperty(KEY_FILE_PATH);
   try {
     File f = new File(path);
     if (f.exists()) {
       FileObject fileObject = FileUtil.toFileObject(FileUtil.normalizeFile(f));
       DataObject dob = DataObject.find(fileObject);
       //A DataObject always has itself in its Lookup, so do this to cast
       FooDataObject fooDob = dob.getLookup().lookup(FooDataObject.class);
       if (fooDob == null) {
         throw new IOException("Wrong file type");
       }
       init(fooDob);
       //Ensure Open does not create another editor by telling the DataObject about this editor
       fooDob.editorInitialized(this);
     } else {
       throw new IOException(path + " does not exist");
     }
   } catch (IOException ex) {
     //Could not load the file for some reason
     throw new IllegalStateException(ex);
   }
 }
 void writeProperties(java.util.Properties p) {
   FooDataObject dob = getLookup().lookup(FooDataObject.class);
   if (dob != null) {
     File file = FileUtil.toFile(dob.getPrimaryFile());
     if (file != null) { //could be a virtual template file not really on disk
       String path = file.getAbsolutePath();
       p.setProperty(KEY_FILE_PATH, path);
     }
   }
 }
Implementing A Very Simple DataObject For Our Very Simple Editor

The skeleton of our DataObject class is generated from the New > File Type template - this includes registering our DataObject subclass and associating it with a file extension. What we need to do is

public class FooDataObject extends MultiDataObject {
  private String content;
  private final Saver saver = new Saver();
  public FooDataObject(FileObject pf, MultiFileLoader loader) throws DataObjectExistsException, IOException {
    super(pf, loader);
    CookieSet cookies = getCookieSet();
    cookies.add(new Opener());
  }

  @Override
  public Lookup getLookup() {
    return getCookieSet().getLookup();
  }

  synchronized void setContent(String text) {
    this.content = text;
    if (text != null) {
      setModified(true);
      getCookieSet().add(saver);
    } else {
      setModified(false);
      getCookieSet().remove(saver);
    }
  }

  void editorInitialized(MyEditor ed) {
    Opener op = getLookup().lookup(Opener.class);
    op.editor = ed;
  }

  private class Opener implements OpenCookie {
    private MyEditor editor;
    @Override
    public void open() {
      if (editor == null) {
        try {
          editor = new MyEditor(FooDataObject.this);
        } catch (IOException ex) {
          Exceptions.printStackTrace(ex);
        }
      }
      editor.open();
      editor.requestActive();
    }
  }

  private class Saver implements SaveCookie {
    @Override
    public void save() throws IOException {
      String txt;
      synchronized (FooDataObject.this) {
        //synchronize access to the content field
        txt = content;
        setContent(null);
      }
      FileObject fo = getPrimaryFile();
      OutputStream out = new BufferedOutputStream(fo.getOutputStream());
      PrintWriter writer = new PrintWriter(out);
      try {
        writer.print(txt);
      } finally {
        writer.close();
        out.close();
      }
    }
  }
}
Caveats For Production Use

A few things may be worth considering if you want to use code like this in a production environment:

How can I change my TopComponent to not be a singleton?

The "New Window Component" wizard in the NetBeans IDE generates a singleton TopComponent. That's fine for windows that there should only be one of. Particularly if you are creating some kind of editor, you will want to create multiple instances of your TopComponent.

The really easy way

If you have not already used the New Window template to create your TopComponent subclass, don't.

Instead, use New > JPanel Form. Once the new JPanel is created, switch to the Code tab, and replace extends javax.swing.JPanel with extends TopComponent. Then do the following things:

If you already have a generated singleton TopComponent subclass

The good news is that you won't have to write any code -- you'll just have to delete some of the code that was generated for you.

In your TopComponent's .java source file:

Next we will need to delete the metadata that registers the component:

Creating And Opening Your TopComponents

Now that you have deleted the actions for your TopComponent, presumably they will be created some other way (for example, from a file's popup menu). You can create new instances of your TopComponent, open them and give them focus as follows:

TopComponent win = new MyTopComponent();
win.open();
win.requestActive(); 

If you wrote your persistence code correctly, your components will magically reopen on restart with no further work.

What About PERSISTENCE_ALWAYS?

There is one other value you can return from TopComponent.getPersistenceType(). That value is TopComponent.PERSISTENCE_ALWAYS.

While it is legal to return this value from a non-singleton TopComponent, it is almost never what you want to do. What will happen if you do this is:

PERSISTENCE_ALWAYS is for singleton components that need to be remembered forever across restarts. Don't use it for non-singletons.

If you do not have any persistence code, but your components are reopening on restart...

You are returning either PERSISTENCE_ONLY_OPENED or PERSISTENCE_ALWAYS from getPersistenceType(). If there is no persistence code, but you are returning one of these values, NetBeans will use plain old Java serialization to store and reload your component.

Either use PERSISTENCE_NEVER or write persistence code as described above. Serialization is slower and more fragile than proper persistence, and is never a good option for production code.

I have a non-singleton TopComponent. Can I write actions which show all available instances in the main menu?

Some people applications where there is one primary kind of window component - an editor of some kind, or something that visualizes some data. There may be several such components open at any time, and they all are just instances of the same TopComponent subclass which are showing different data.

In this case, it can be useful to list all such components in the main menu, to facilitate switching between components. This involves three steps:

  1. Track all opened instances of the TopComponent subclass
  2. Write an Action which provides an array of menu items, one for each TopComponent instance
  3. Register that action in one of the main window menus
Tracking TopComponents And Creating Actions For Them

Keeping track of all of the instances of our TopComponent subclass is simple. Whenever a new one is constructed, we will just add it to a list. There are only two caveats:

We will add a static method which creates a list of Actions suitable for use with standard Swing JMenuItems.

//Helper annotation to allow our component to be remembered across restarts.
//The DTD does not have to be defined, it just needs to be a unique name
@ConvertAsProperties(dtd = "-//org.netbeans.demo.multitopcomponent//MultiTopComponent//EN", autostore = false)
public class MultiTopComponent extends TopComponent {
  //A index for our display name, so we can tell the components apart

  static int ix;
  //Keep a list of all components we create.  Synchronize it because
  //they could be deserialized on some random thread;  use WeakReferences
  //so we don't hold a closed TopComponent in memory if it will never
  //be used again
  private static List<Reference<TopComponent>> all =
          Collections.synchronizedList(
          new ArrayList<Reference<TopComponent>>());

  public MultiTopComponent() {
    setDisplayName("Component " + ix++);
    all.add(new WeakReference<TopComponent>(this));
    setLayout(new BorderLayout());
    add(new JLabel(getDisplayName()), BorderLayout.CENTER);
  }

  public static List<Action> allActions() {
    List<Action> result = new ArrayList<Action>();
    for (Iterator<Reference<TopComponent>> it = all.iterator(); it.hasNext();) {
      Reference<TopComponent> tc = it.next();
      TopComponent comp = tc.get();
      if (comp == null) {
        it.remove();
      } else {
        result.add(new ShowAction(comp.getDisplayName(), tc));
      }
    }
    return result;
  }

  private static final class ShowAction extends AbstractAction {
    //Our action should not hold a strong reference to the TopComponent -
    //if it is closed, it should get garbage collected.  If a menu
    //item holds a reference to the component, then it won't be

    private final Reference<TopComponent> tc;

    public ShowAction(String name, Reference<TopComponent> tc) {
      this.tc = tc;
      putValue(NAME, name);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      TopComponent comp = tc.get();
      if (comp != null) { //Could have been garbage collected
        comp.requestActive();
      } else {
        //will almost never happen
        Toolkit.getDefaultToolkit().beep();
      }
    }

    @Override
    public boolean isEnabled() {
      TopComponent comp = tc.get();
      return comp != null && comp.isOpened();
    }
  }

  @Override
  public int getPersistenceType() {
    return PERSISTENCE_ONLY_OPENED;
  }

  void readProperties(java.util.Properties p) {
    setDisplayName(p.getProperty("name"));
  }

  void writeProperties(java.util.Properties p) {
    p.setProperty("name", getDisplayName());
  }
}

This class contains persistence code - particularly the @ConvertAsProperties annotation and the methods readProperties()writeProperties() and getPersistenceType(). These methods save some information about our TopComponent to disk on shutdown, in the form of a Properties object. If we do not want our components to be reopened after an application restart, we can just return PERSISTENCE_NEVER from getPersistenceType(), and delete the other persistence-related methods and the annotation. Note that you can omit the *Properties() methods and the annotation, and the components will be reopened on startup—but without persistence code, this is done by serializing the whole component to disk, which is both slower and stores more data than necessary. Typically, for an editor component, just storing the path to the file being edited is enough.

Writing an Action which provides an array of menu items

The DynamicMenuContent interface allows an Action to act as a factory for menu items - to control what components are shown in a menu to represent it. It also allows a single action to produce multiple menu items.

Here we will create an action which produces an array of menu items. All of them will be shown inline in the main menu:

public class MultiComponentAction extends AbstractAction implements DynamicMenuContent {

    @Override
    public void actionPerformed(ActionEvent e) {
        throw new AssertionError("Should never be called");
    }

    @Override
    public JComponent[] getMenuPresenters() {
        List<Action> actions = MultiTopComponent.allActions();
        List<JComponent> result = new ArrayList<JComponent>(actions.size());
        for (Action a : actions) {
            result.add (new JMenuItem(a));
        }
        return result.toArray(new JComponent[result.size()]);
    }

    @Override
    public JComponent[] synchMenuPresenters(JComponent[] jcs) {
        //We could iterate all of our JMenuItems from the previous call to
        //getMenuPresenters() here, weed out those for dead TopComponents and
        //add entries for newly created TopComponents here
        return getMenuPresenters();
    }
}

This will create an inline array of menu items, not a submenu. If you want a submenu instead, then implement getMenuPresenters() as follows:

        List<Action> actions = MultiTopComponent.allActions();
        JMenu menu = new JMenu("Multi TopComponents");
        for (Action a : actions) {
            menu.add (a);
        }
        return new JComponent[] { menu };
Registering The Action

Now we just need to actually add our multi-item action to the main menu, by registering it in our module's XML layer.

In this example, we register it in the Actions/Window folder and then create a link in the Window menu folder using a .shadow file. Note that we could simply put the .instance file directly in the Menu/Window folder, but this approach is the preferred practice:

<?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="Actions">
        <folder name="Window">
            <file name="org-netbeans-demo-multitopcomponent-MultiComponentAction.instance">
                <attr name="position" intvalue="230"/>
            </file>
        </folder>
    </folder>
    <folder name="Menu">
        <folder name="Window">
            <!-- This is the action that actually shows all available components -->
            <file name="MultiComponent.shadow">
                <attr name="position" intvalue="230"/>
                <attr name="originalFile" 
                stringvalue="Actions/Window/org-netbeans-demo-multitopcomponent-MultiComponentAction.instance"/>
            </file>
        </folder>
    </folder>
</filesystem>

Which TopComponents are open?

[no content found]

How to override the default size of an existing window?

Since the window already exists and has a default size, it must be registered under a specific mode in the filesystem.

Find the file defining the size, i.e., the "wsmode" file that defines the mode under which it is registered, and change it. Then register the changed mode under the same name as the original mode in the layer. If you want to make sure that yours overrides the default, set a dependency in your module on the module that defines the original mode.

Generally it is better to create a whole new mode, since you then will never have a conflict between two different definitions.

How to create a custom window mode?

From time to time the available options are not enough. The available options are displayed below:

[image - see online version]

Here's the yEd file for the above image in case this is incorrect or needs to be modified:

File:Netbeans Window Modes.graphml

If you want a custom "mode" or location for a top component follow this blog from Geertjan's Blog: Creating A New Mode In Your Application

How to change main title contents?

The title of your application is located in a resource bundle:

...\branding\modules\org-netbeans-core-windows.jar\org\netbeans\core\windows\view\ui\Bundle.properties

As of NetBeans 6.9, it is possible to use the Branding Editor to edit this resource.

To remove the version number prior to 6.9, manually edit the file and remove existing {0} tokens:

CTL_MainWindow_Title=AppBrandingName {0}
CTL_MainWindow_Title_No_Project=AppBrandingName {0}

so it will be as:

CTL_MainWindow_Title=AppBrandingName
CTL_MainWindow_Title_No_Project=AppBrandingName

Build number will not show in the application main title.

Change main title at runtime

Inside the ModuleInstaller class for the GUI module:

@Override
public void restored() {
  // some other code may go here...
   WindowManager.getDefault().invokeWhenUIReady(new Runnable() {
     @Override
     public void run() {
      JFrame mainFrame = (JFrame) WindowManager.getDefault().getMainWindow();
      mainFrame.setTitle("Modified main title");
     });
   }
  // some other code may go here...
}


A word of caution related to porting existing Swing applications to NetBeans Platform.

This will not work!

@Override
public void restored() {
  // some other code may go here...
   SwingUtilities.invokeLater(new Runnable(){
     @Override
     public void run() {
      JFrame mainFrame = (JFrame) WindowManager.getDefault().getMainWindow();
      mainFrame.setTitle("Modified main title");
     });
   }
  // some other code may go here...
}

Although it will not show any errors, the main title will not be set! in this case.

Other Options

See also:

How can I customize the window system via the latest 7.1 techniques/enhancements?

It is possible to use any JFrame instance as the main window. Simply create the instance when your module is being loaded (ModuleInstall.restored()) and set its name to NbMainWindow. When the window system loads it will pick this instance and initialize it with menu bar, status bar, toolbars, inner desktop hierarchy etc.

Mixing document and non-document windows

As of NetBeans 7.1 it is possible to mix document and non-document windows. It means it is possible for example to drag Projects window and drop it next to Java source editor. It is also possible to drag any editor window and dock it next to Project or Output windows. If you want to turn this feature off and revert to NetBeans 7.0 behavior use Mix.Editors.And.Views.Enabled branding property in org/netbeans/core/windows/Bundle.properties bundle.

Paint custom background

Boolean property NbMainWindow.showCustomBackground set to true in UIManager will make most of main window components transparent. So anything painted to main window root pane will be showing through its toolbars, menu bar, status bar and window borders. Use this property together with custom JFrame instance (see above) to paint custom images on main window background.

Turn some features on/off on TopComponent level

When creating a new TopComponent using NetBeans New File wizard you are presented a couple of option to modify window behavior. If you need to customize the behavior of an existing TopComponent or behavior of a TopComponent you don't have sources to just use any of client properties listed below. For example:

WindowManager.getDefault().findTopComponent("output").putClientProperty("netbeans.winsys.tc.closing_disabled", Boolean.TRUE);
//nobody can close Output window now!


Turn some features on/off on window system level

If you want to customize features of all windows you can use the following branding properties. (See for example here how NetBeans branding works.)

NetBeans version 7.1 introduced a concept of tab groups. All windows in the same docking spot form a tab group. For example Projects, Files and Services windows in the top-left corner of the main window belong into the same tab group. User can close/minimize/float the whole tab group with a single mouse gesture or keyboard shortcut. The following branding properties define which tab group actions are (not) enabled.

Customize non-document tabs layout

As of NetBeans 7.1 non-document windows in the same docking spot are organized into a tab group (see also above).

[image - see online version]

If you want to revert the tab layout back to the old behavior in NetBeans 7.0 then you must set system property winsys.stretching_view_tabs to true. Window tabs will then stretch to fill the whole width of the docking spot:

[image - see online version]

Please note that tab group actions (close group, float group, move group etc) will still be present in the main menu and in window's context menu. Use the branding propeties above to remove those actions.

External Link

Up to date list of all Window System related properties and brading options should be available at architecture summary page.

How to mix lightweight (Swing) and heavyweight (AWT) components?

Since JDK 6 update 12 and JDK 7, support for mixing of AWT (heavyweight, native widgets) and Swing (lightweight, pure Java widgets) is available and usually works quite well. However, placing a native AWT Component within a Swing container hierarchy with customizations may cause unwanted side-effects and can therefor be disabled.

As of NetBeans 7.3, an additional option has been added to etc/netbeans.conf to disable mixing by default:

-J-Dsun.awt.disableMixing=true

In some cases, such as displaying OpenGL content via JOGL, it may be necessary to add a native component to a NetBeans TopComponent. In that case, the default setting breaks usability of the platform application by incorrectly drawing menus and other lightweight components behind the native component. To re-enable the mixing, the above option needs to be set to false:

-J-Dsun.awt.disableMixing=false

For reference, see Oracle Notes on AWT

Applies to: NetBeans 7.3 and above

Project Types

Is it possible to extend an existing project type?

Yes.

You can add new actions, tabs, nodes, and lookups to an existing project type. See the NetBeans Project Type Extension Module Tutorial for details.

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

Create and register the panel (here for Java SE projects):

@ProjectCustomizer.CompositeCategoryProvider.Registration(
    projectType="org-netbeans-modules-java-j2seproject")
public class BlaPanelProvider implements ProjectCustomizer.CompositeCategoryProvider {
    public @Override Category createCategory(Lookup context) {
        return ProjectCustomizer.Category.create(
                "Bla",
                "Bla",
                null,
                null);
    }
    public @Override JComponent createComponent(Category category, Lookup context) {
        return new BlaPanel();
    }
}

See also Project Properties GUI for custom project templates and Adding New Tabs to the Project Properties Dialog in NetBeans IDE.

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

Just use @ActionReference(path="Projects/Actions"). The action should take a context parameter in its constructor.

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:

@ActionID(...)
@ActionRegistration(...)
@ActionReference(path="Projects/Actions")
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));
        }
    }
}

Certain project types also read their context menu actions from type-specific folders.

Applies to: NetBeans 7.0+

How do I identify the "main project"?

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

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

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


public final class ShowMainProjectAction extends CookieAction {

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

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

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

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

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

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

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

How do I register a "ProjectCustomizer" to multiple project types?

Use the @Registrations annotation to group the multiple @Registration annotations.

For example

@ProjectCustomizer.CompositeCategoryProvider.Registrations({
    @ProjectCustomizer.CompositeCategoryProvider.Registration(projectType = "org-netbeans-modules-java-j2seproject"),
    @ProjectCustomizer.CompositeCategoryProvider.Registration(projectType = "org-netbeans-modules-web-project"),
    @ProjectCustomizer.CompositeCategoryProvider.Registration(projectType = "org-netbeans-modules-maven")
})
public class MyPluginPanelProvider implements ProjectCustomizer.CompositeCategoryProvider {
//...
}

Applies to: NetBeans IDE 7.x Platforms: All

See http://platform.netbeans.org/tutorials/nbm-projecttype.html#projectcustomizer

How determine all available project types?

The project type can be used for extending the project properties - http://wiki.netbeans.org/DevFaqActionAddProjectCustomizer

Example of some available types in NetBeans 7.2

[image - see online version])

org-netbeans-modules-ant-freeform
org-netbeans-modules-apisupport-project
org-netbeans-modules-apisupport-project-suite
org-netbeans-modules-apisupport-project-suite-jnlp
org-netbeans-modules-apisupport-project-suite-osgi
org-netbeans-modules-apisupport-project-suite-package
org-netbeans-modules-autoproject
org-netbeans-modules-j2ee-clientproject
org-netbeans-modules-j2ee-earproject
org-netbeans-modules-j2ee-ejbjarproject
org-netbeans-modules-java-j2seproject
org-netbeans-modules-maven
org-netbeans-modules-web-project
...

Note: The list is incomplete. There will be more project types, if you enable support for JS, PHP, Gradle a.s.o.

Applies to: NetBeans IDE 7.x Platforms: All

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.

How to open files in editor after project creation?

Q: I have created my own project type for my platform application. After project being created I would like to open a file contained in this project. Just like it is done when you create new java application in netbeans. After project creation your main java class is opened in editor.

A: your new project wizard iterator should be a WizardIterator<Set<FileObject>> - and you should just be able to add the files you want opened to that set

Taken from nbdev mailing list. April 2013

How to customize the button text of default buttons of a wizard (Finish, Cancel, etc.)?

Need to customize the button text of the default buttons of a wizard (Finish, Cancel, etc.)?

See posts from mailing list http://forums.netbeans.org/topic55192.html

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, false).getOut().println(mess);

The OutputHandler referenced above 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:

import javax.swing.Action;
import org.openide.windows.IOContainer;
import org.openide.windows.IOProvider;
import org.openide.windows.InputOutput;
import org.openide.windows.OutputWriter;

// registration, you can change default instance returned by IOProvider.getDefault() by adjusting position
@org.openide.util.lookup.ServiceProvider(service=org.openide.windows.IOProvider.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", true);

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


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?

package sample.component;

import java.awt.EventQueue;
import java.io.BufferedReader;
import java.io.IOException;
import org.openide.util.Exceptions;
import org.openide.util.RequestProcessor;
import org.openide.windows.IOProvider;
import org.openide.windows.InputOutput;
import org.openide.windows.OnShowing;

@OnShowing
public class OutputWindowReaderExample implements Runnable {

    /**
     * Open Output Window and ask for some input.
     */
    public static void requestAnswerExample() throws IOException {
        assert !EventQueue.isDispatchThread();
        InputOutput io = IOProvider.getDefault().getIO("ioName", true);
        io.select();
        io.getOut().println("How are you?");
        BufferedReader br = new BufferedReader(io.getIn());
        String answer = br.readLine();
        io.getOut().println("You are " + answer + " today");
        br.close();
        io.getOut().close();
        io.getErr().close();
    }

    /**
     * Call requestAnswerExample from a background thread, after initialization
     * of the user interface.
     */
    @Override
    public void run() {
        RequestProcessor.getDefault().post(new Runnable() {
            @Override
            public void run() {
                try {
                    requestAnswerExample();
                } catch (IOException ex) {
                    Exceptions.printStackTrace(ex);
                }
            }
        });
    }
}

Note: The module that contains this class depends on Window System API (org.openide.windows).

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. See also Code Coverage.

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

===Wr requires.nb.javac=true

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.

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

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

You will probably want to put this system property in the application's configuration file (where you'd add JVM memory flags) so it will be permanent.

Clever users could work around this by editing the command line and bypassing the restriction, so the security of this approach is limited by itself. If this is a concern, you may overcome it by having your custom main class encrypt a flag value (which perhaps contains a nonce/timestamp to prevent replay attacks) and passing it (e.g. as a system property) to your platform application which will then decrypt and verify it. Thus, the logic for validating the user is entirely in the custom main class (or the code which it invokes), while the platform application need only verify that this step has actually been performed.

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.

How can I hook up JavaHelp to property sets or individual properties?

Generally speaking, you can implement HelpCtx.Provider for objects in your platform application to associate them with a JavaHelp context (page). For some reason, this approach does not work with node properties. You can set the "helpID" value to associate JavaHelp with an individual property or an entire set, as shown below:

For Individual Properties

// in the constructor of your property class
public LastNameProperty(String initialValue) {
    super("lastName", String.class, "Last Name", "The user's surname");

    // This is how you associate a given property with a help context.
    setValue("helpID", "my.help.ctx");
}
For a Set of Properties
@Override
protected Sheet createSheet() {
    Sheet s = super.createSheet();

    Sheet.Set ss = s.get(Sheet.PROPERTIES);
    if (ss == null) {
        ss = Sheet.createPropertiesSet();
        s.put(ss);
    }

    // Do this to specify help for a whole sheet set
    ss.setValue("helpID", "my.help.ctx");

    ss.put(new FirstNameProperty("Abe"));
    ss.put(new LastNameProperty("Lincoln"));

    return s;
}

How can I override JavaHelp to display my own custom help or documentation?

Contents
Step 1: HelpCtx.Displayer

First, you must create a HelpCtx.Displayer that is capable of displaying your help and register it as a service provider

@ServiceProviders({
    @ServiceProvider(service = HelpCtx.Displayer.class, position = 1000)
})
public class CustomHelpDisplayer implements HelpCtx.Displayer {
    
    public boolean display(final HelpCtx helpCtx) {
        
        // Put your displaying code here.
        JOptionPane.showMessageDialog(
                WindowManager.getDefault().getMainWindow(),
                helpCtx.getHelpID());

        return true;
    }
}
Step 2: Help.class

An instance of org.netbeans.api.javahelp.Help determines what to do with a particular HelpCtx. In order to use your custom help displayer, you need to create an instance of Help that can display using your custom help displayer. In this case, you want to override the Help class provided with the NetBeans platform, so you set the 'position' attribute low. The purpose of this class is two-fold:

@ServiceProviders({
    @ServiceProvider(service = Help.class, position = 1)
})
public class CustomHelp extends Help {

    @Override
    public Boolean isValidID(final String id, final boolean force) {
        // We return true because even if it's not a valid ID for our purposes, we just pass it
        // to the default help and let it deal with it.
        return true;
    }

    @Override
    public void showHelp(final HelpCtx ctx, final boolean showmaster) {

        // Here, we examine the ID and if it starts with "PREFIX", we find our implementation
        // of HelpCtx.Displayer using the Lookup API and use it to display our help.
        if (ctx.getHelpID().startsWith("PREFIX")) {

            final HelpCtx.Displayer displayer =
                    Lookup.getDefault().lookup(HelpCtx.Displayer.class);

            displayer.display(ctx);
        }

        // If we don't know what do with the ID, we find all the implementations of Help and
        // pass the HelpCtx along to the first one we find that isn't this class.
        else {
            final Collection<? extends Help> helps =
                    Lookup.getDefault().lookupAll(Help.class);
            
            for (Help help : helps) {
                if (help != this) {
                    help.showHelp(ctx, showmaster);
                    
                    break;
                }
            }
        }
    }

    @Override
    public void addChangeListener(final ChangeListener listener) {
        // *** Not sure what to do here.
    }

    @Override
    public void removeChangeListener(final ChangeListener listener) {
        // *** Not sure what to do here.
    }
}
Step 3: Connecting UI To JavaHelp

See Connecting Help In NetBeans.

Step 4: Add the JavaHelp Integration Module

This module is not "eager", so to force it to load, at least one module must depend on it. Simply make JavaHelp Integeration a dependency of one your modules to make Help available. The JavaHelp Integration module is in the 'platform' library.

Summary: Putting It All Together

Applies to: NetBeans IDE 7.2 Platforms: All

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.

a) Using wizards: 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.

b) Using layer.xml:

<folder name="Services">
  <folder name="AutoupdateType">
    <file name="my_update_center.instance">
      <attr name="displayName" stringvalue="My Update Center" />
      <attr name="enabled" boolvalue="true" />
      <attr name="instanceCreate" methodvalue="org.netbeans.modules.autoupdate.updateprovider.AutoupdateCatalogFactory.createUpdateProvider" />
      <attr name="instanceOf" stringvalue="org.netbeans.spi.autoupdate.UpdateProvider" />
      <attr name="url" urlvalue="http://my_site.com/updates.xml" />
    </file>
  </folder>
</folder>

(taken from mailinglist)


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 and AFTER the line

<import file="nbproject/build-impl.xml"/>

insert

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