NetBeans Developer Faq

Generated on Tue Feb 09 05:38:14 UTC 2010 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.

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.

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

It's a good thing to bookmark.

Javadoc

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

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

cd $NB_SRC_ROOT
ant build-javadoc
Using the Javadoc

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

NetBeans Tutorials

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

FAQs

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

Getting the Source Code

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

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

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

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

Here's how to build it.

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

How To Find Useful APIs

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

Get the NetBeans Platform Examples

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

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

You can find several other samples in the module platform in main/misc repository at hg.netbeans.org. They are in the platform/samples/ subdirectory. The platform/samples/ folder can be browsed online here.

Build Platform from Sources

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

To build platform run

cd $NB_SRC_ROOT
ant build-platform
Mining the NetBeans Source Code for Examples

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

Use the Mailing Lists

If you have questions, the best place to go is the developer mailing list. Click this link to subscribe.

You can also browse the archives online, but actually joining the mailing list is the best way to get (and give) help.

Note: dev@platform.netbeans.org was formerly dev@openide.netbeans.org - older archives can be found on Nabble and via a newsreader by going to news://news.gmane.org or access them on the web via Nabble.

Ask questions, and when you can answer them, do that too. There is a very healthy and helpful community there.

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

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

Then, from the command line, you run

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

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

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

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

More info about using Mercurial with NetBeans sources...

How do I get zipped sources for a periodic build?

(as of June, 2009)

1. Go to the nightly build download site:

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

2. Click the link for the build you want.

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

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

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

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

related message in the NetBeans mailing list

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 thusly should remain backward compatible.

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

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

The main reasons for the exe are:

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. You will be shown an index page which makes no mention of how you can get a ZIP file or a source archive, so ignore it.

4. Add "zip/" to the end of the URL in your browser's address bar and hit enter. In other words, the complete URL might look like this: http://bits.netbeans.org/dev/nightly/2008-06-24_02-01-08/zip/

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

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

Applies to: NetBeans 5.x, 6.x

Platforms: all

Where is the Platform and how can I build it?

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

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

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

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

   ant -Dcluster.config=platform build-platform

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


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

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

   ant -Dcluster.config=platform build-platform -Dnbjdk.home=c:/devtools/jdk/jdk-1.5.0_u15
This will build the platform into the
netbeans
subdirectory (i.e. {nbbuild/netbeans}). You can zip or tar up the netbeans directory to create a ZIP distribution.

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

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

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

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


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

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

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

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

Update for NBM projects generated by NetBeans 6.7 and later

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

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

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


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

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

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

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

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

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

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

Getting support, where to find examples

Filing a bug report

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

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

Examples of how to use various APIs

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

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

Where can I find more documentation on certain APIs?

The NetBeans Javadoc has some additional documentation about using certain APIs. Unfortunately, the index page does not link to these and so they can be difficult to find. Here are direct links to these documents from the most recent builds:

Can I get training material for the NetBeans Certification course?

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


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

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

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.
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/private.properties to contain e.g.

storepass=specialsauce

You could also pass -Dstorepass=specialsauce on the command line.

If you specify a keystore but
${storepass
} is undefined, you will be prompted for the password during the build.

5. Build the NBM for the module. (Context menu of the project.) It should be signed.

6. Try installing the NBM. (Expand build folder in Files view and double-click it.) It will not be trusted initially (and so the checkbox to really install it will initially be unchecked), since NetBeans does not know about your signature. But you can click View Certificate to examine the certificate. If you allow installation of this module, NetBeans will remember you approved this certificate and it will not ask you for confirmation next time.

Some notes:

1. You can probably get a root-authorized certificate from VeriSign or the like, and the Auto Update wizard should treat this as more trusted. Not yet investigated (please update this FAQ entry if you experiment with this).

2. Keeping the keystore and its password in the private dir ensures that you will not accidentally commit either to source repository or include it in a source ZIP made with the Project Packager module. It may be safe to put the keystore in a shared directory (e.g. nbproject) if you are sure that the storepass is too hard to guess.

Applies to: NetBeans 6.8 and above

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 and pick up the JAR from the Java SE project's original location with source association (even if the Java SE project is not open!). You modify the wrapper's project.xml (to adjust the <class-path-extension>), project.properties (to specify extra.module.files) and build.xml (to override the release target) as shown in the following example. harness/README gives the details. See also Issue 70894, which would make it easier.

Example: Having the wrapper module clean and build the project

With these changes to a wrapper module, build/clean on the wrapper, or on the module suite that contains the wrapper, also does build/clean on the project.

For this example, my-wrapper is a library wrapper module for the JAR file produced by the regular Java project called my-project. my-project and my-wrapper are in the same directory; this only affects relative path specifications and is not a general requirement. This example was created on NetBeans 5.5. If you have jars from multiple projects in a wrapper, then this example is extended by using <antsub> instead of <ant> and a FileSet in the release target's <copy> task.

Only the my-wrapper project needs modification.

First

In my-wrapper/nbproject/project.xml, change <class-path-extension>'s <binary-origin> to reference the jar created by my-project. This change gives code completion with Javadoc and Go to Source when referencing my-project.

<binary-origin>../my-project/dist/my-project.jar</binary-origin>

Make sure a ../src directory (relative to the JAR location) containing the corresponding sources of the library exists if you want Go to Source functionality to work.

Second

In my-wrapper/nbproject/project.properties specify where my-project's JAR file is installed in the suite's cluster. This puts my-project.jar in the wrapper's NBM; it is needed since the wrapper's release directory is no longer used as a staging area.

extra.module.files=modules/ext/my-project.jar
Third

Delete the directory my-wrapper/release. The original JAR file was copied here when the wrapper was created. It will interfere if it is left around.

Fourth

In my-wrapper/build.xml add the following. Customize the first two properties' value= to specify your project's relative location and JAR. The release target is replaced; now it builds my-project then copies the JAR to the suite's cluster. The clean target first cleans as usual, then cleans my-project.

<property name="original.project.dir" value="../my-project"/>
<property name="original.project.jar"
          value="${original.project.dir}/dist/my-project.jar"/>

<target name="release">
    <echo message="Building ${original.project.dir}"/>
    <ant dir="${original.project.dir}"
         target="jar" inheritall="false" inheritrefs="false"/>
    <echo message="Done building ${original.project.dir}"/>

    <copy todir="${cluster}/modules/ext"
          file="${original.project.jar}"/>
</target>


<target name="clean" depends="projectized-common.clean">
    <echo message="Cleaning ${original.project.dir}"/>
    <ant dir="${original.project.dir}"
         target="clean" inheritall="false" inheritrefs="false"/>
    <echo message="Done cleaning ${original.project.dir}"/>
</target>
How do I include native libraries (*.so or *.dll) in my library wrapper module?

Some libraries come with a native counterpart. The current Library Wrapper wizard doesn't cater to this. As per the JNI section in this document, you simply need to create a lib directory under <my-wrapper>/release/modules (which gets created by the wizard), alongside the ext directory mentioned earlier in this document. This directory is where you place your native libraries.

How do I include more that one jar in my library wrapper module?

As explained in this mail and in this README the library wrapper creation wizard will only add one jar. To add more you need to copy the jars to release/modules/ext/ and edit nbproject/project.xml to add extra <class-path-extension> elements.

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

Applies to: NetBeans 5.5, 6.x

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:

 to make sure that the library license is suitable for use in NetBeans.
 and nowhere else.
 (For the contrib repository, the path will be contrib/<nbmodule>/external.)
  ExternalBinaries describes how the actual binary content is stored outside Hg,
 while the Hg repository actually tracks the SHA-1 hash of the binary.
 ant bootstrap suffices to download all external binaries in a fresh checkout.
 stored in the same directory as the binary itself.  You will upload the binary itself through
 the Web form, but will add the license file directly to Mercurial (e.g. hg add external/somelib-x.y.z-license.txt).
 somelib-x.y.z.jar or somelib-x.y.z.zip where x.y.z is the version number.
 The corresponding license file must be named somelib-x.y.z-license.txt.
 The license file must end with a newline.
 Lines should not exceed 80 characters.
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; details):

release.external/beansbinding-0.6.1.jar=modules/ext/beansbinding-0.6.1.jar
release.external/beansbinding-0.6.1-doc.zip=docs/beansbinding-0.6.1-doc.zip

(Note: if you wish for the binary to be in the classpath of the module as a library, you will still need a <class-path-extension> in your project.xml.) You can also use a ZIP entry on the left side and it will be extracted from the ZIP to your cluster:

release.external/stuff-1.0.zip!/stuff.jar=modules/ext/stuff-1.0.jar
Normalized names

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

NetBeans Samples

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

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

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

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

All rights reserved.

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

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

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

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

Common mistakes

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

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

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

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

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

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

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

cd nb-main
for f in */{build.xml,nbproject/*.{properties,xml</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.

 (Or it can be mentioned in Files header of some license.)
 (Look inside ZIP files for nested JARs.)
 Whitespace-only changes are permitted, e.g. rewrapping lines to make them fit.
 For licenses with templates (e.g. BSD License)
 any tokens between two underscores can match whatever character sequence.
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 manifest:

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

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

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

(requesting any version; not recommended).

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

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

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

OpenIDE-Module-Implementation-Version: 3

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

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

Friend dependencies

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

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

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

Implementation dependencies, Auto Update, and <verifyupdatecenter>

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

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

[Monday]

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

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

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

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

[Tuesday]

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

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

Again, these two modules could be installed together.

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

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

OpenIDE-Module-Implementation-Version: 1

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

spec.version.base=1.0.0

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

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

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

[Monday]

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

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

[Tuesday]

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

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

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

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

[Wednesday]

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

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

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

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

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

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

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

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

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

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

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

Applies to: NetBeans 5.x, 6.x

Platforms: all

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 get full access to all classes in a module, you need to declare an implementation dependency ( DevFaqImplementationDependency). Be sure you really need to use the class you're trying to use, in this case - it will make your module hard to upgrade because generally it will need to be paired with the exact version of the other module's JAR that it was built with - if that module is upgraded, your module may end up being disabled.

Problem #3 may happen if you change your modules name. If some module declared yours as a friend it will no longer recognize it.

Checking for errors eagerly

For a nice way to resolve all module dependencies at once, to force all of the errors to be exposed simultaneously, just add the following to the command line when starting NetBeans:

-J-Dnetbeans.preresolve.classes=true

The message displayed states that when using this flag, you should not use the -J-Xverify:none flag (often specified in the IDE configuration file), so you may need to edit the .conf file to remove the -Xverify option before using the pre-resolve option.

More tips

For help on working with class paths, please see

http://bits.netbeans.org/dev/javadoc/org-openide-modules/org/openide/modules/doc-files/classpath.html

Applies to: NetBeans 6.x

Platforms: all

What is a module cluster?

Most of all, cluster is a compatibility unit. It is set of modules that is developed by the same group of people, built and released at once.

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

Applies to: NetBeans 6.8 and above

What is the difference between a suite and a cluster?

Suite

A suite is a container project used to group external module projects into a unit whose members can refer to one another as well as to a NB platform. If you only have one module project, you can treat it as "standalone" and you do not need a suite, but using a suite is advisable for serious projects since it offers you more options, such as adding library wrapper modules, or creating a complete application based on your module.

Since NetBeans 6.7 a suite can depend either on another suite, standalone module or even external binary cluster, see DevFaq How To Reuse Modules. If you use version earlier than 6.7 a suite S2 cannot directly depend on another suite S1. But if S1 uses NB platform P1, you could create a derived platform P2 by building S1 on top of P1, and then select P2 as the NB platform for S2. Then S2 can refer to all the modules in P1 as well as the modules built from S1.

The NB IDE build (from sources on hg.netbeans.org) does not use suites. It uses a historical build infrastructure which partially overlaps the external module/suite build harness introduced in 5.0, but which has different requirements (and is considerably more complex). Module projects physically inside the netbeans.org source tree cannot be "standalone" modules nor "suite component" modules - they are simply netbeans.org modules, and as such use a (slightly) different format for metadata, and have access to somewhat different facilities specific to netbeans.org practices.

Cluster

A cluster is simply a subdirectory of a NB-based-app's binary installation; every module in the installation falls into one cluster. The installation is divided into clusters for purposes of:

  1. Conceptual clarity.
  2. Possible mapping to native packaging systems such as RPM.

The NB team has a policy of treating inter-cluster module dependencies as more significant than intra-cluster module dependencies with respect to backward compatibility, with the aim of making it possible for product teams building on top of the NB IDE to select a subset of the IDE to use with cluster granularity rather than with module granularity, which may be simpler to grasp and integrate with native packaging. But there is nothing preventing you from reusing a subset with module granularity.

The NB launcher (nbexec) accepts a list of cluster directories to load modules from - basically a search path. There are no further semantics to clusters.

The suite project type has a standard build target to assemble a complete application. For simplicity, it simply places all modules built from suite sources into their own cluster named in accordance with the suite's name.

NBMs may specify a cluster. The netbeans/ subdirectory of the NBM (which is a ZIP file) has a file layout which matches the layout of files within a single cluster. Each cluster managed by Auto Update has an update_tracking/ subdirectory with one XML file per module, enumerating the files which that module contributes to the cluster.

Currently the "NB Platform" is just the platform* cluster from the IDE, though the choice of modules may not be exactly what you want for every "platform" application.

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

References:

Applies to: NetBeans 6.8 and above

How can I reuse my modules in several RCP applications?

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

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

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

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

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

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. In NetBeans 6.1 there was no alternative.

As of NetBeans 6.5, you can work on "orphan" modules from the netbeans.org source base. There are two issues to consider:

  1. Mercurial currently does not let you clone or check out just a subdirectory of a repository, so you will need to get module sources some other way (we are still considering some possibilities).
  2. Since "upstream" modules (that the module of interest depends on) are not available in source form, you need to have a recent development build of NetBeans available to compile against.

Issue 143236 describes the enhancement in NetBeans 6.5 that permits this development mode.

Quick usage guide
  1. Create an nb_all dir wherever you like. It must have at least the nbbuild dir from the netbeans.org source tree.
  2. Create nbbuild/user.build.properties and in it set the property netbeans.dest.dir to the full path to a NetBeans IDE installation you would like to both compile against and build into (you should not use your real development IDE, rather a copy).
  3. Run: ant -f nbbuild/build.xml bootstrap
  4. Add subdirs for any netbeans.org module projects you would like to work on. (The modules may be already present in the target platform. If they are not, you need to check out sources for any transitive dependencies not in the target platform too.)
  5. Using a 6.5+ IDE, open the desired projects and work normally.
What works

Source projects should open without error and without displaying error badges, assuming all dependencies are available in either source or binary form.

You can build the projects normally. The modules will be built into the target platform (overwriting any existing copy of the module).

You can use Run and Debug to start the target platform with a test userdir after building the modules, set breakpoints etc.

You can Test the source projects normally.

Code completion should work against APIs present in other modules. If those modules are available in source form, you will get popup Javadoc automatically, and can navigate to sources. If not, you can still add popup Javadoc capability for all published APIs:

  1. Download "NetBeans API Documentation" from AU.
  2. Open NetBeans Platform Manager.
  3. Select the "default" platform and note the location of NetBeansAPIDocs.zip in the Javadoc tab.
  4. Create a new platform; select the same dir as you specified for netbeans.dest.dir.
  5. In the new platform, add NetBeansAPIDocs.zip to the Javadoc tab.
Caveats

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 ide5/modules/org-openide-example.jar you make a JAR like ide5/modules/patches/org-openide-example/mypatch.jar. The mypatch part of your JAR file patch can be named anything you like. The JAR file should only contain those classes you want to patch. It does not need a manifest, though an empty manifest is harmless.

The patch must be in the same cluster as the original. (Issue 69794) If you want to create an NBM containing a patch, you must ensure it will be installed in the same cluster (use the nbm.target.cluster property), but note that you cannot test such a dummy module as part of a module suite (since this property is interpreted only by Plugin Manager). If you are distributing a complete application including a patch to the NB Platform, you will need to either manually preinstall the patch JAR in your copy of the Platform; or override your build-zip target to include the JAR in the final ZIP (in which case testing using Run Project will not have the patch active).

Applies to: NetBeans 6.x

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

Applies to: NetBeans 6.NetBeans Platform Manager

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 throug soft or weak references and make it easier to browse the dump.

Analyze the problem.

Once you have the dump of the heap in a file, it is possible to open it using the NetBeans profiler. This has a number of analysis features and is integrated with the IDE, e.g. to browse sources.

Alternately, you can use the JDK's tool jhat. It will start simple web server and you can use a web browser to see the data. There are many functions starting with lists of classes with numbers of objects and their size, navigation between references, finding of reference chains from GC root to certain objects. JavaScript can be used to express more complex queries.

Other tools

INSANE is a home-grown tool that is useful for analysis of memory content and also can be used in automated tests - so once you have fixed a memory leak, you can write a test that will fail if the memory leak is ever recreated. NbTestCase.assertGC is all you need to know.

DTrace can be used to monitor object allocation and garbage collection. Nice article about using DTrace with the HotSpot provider: Java and DTrace

Tips and tricks
Common leaking objects

There are some typical classes where it should be easily possible to tell what the appropriate number of their instances in memory should be, and if these are leaking there is a serious problem:

Leaks vs. retained memory

There are two different ways how memory can be wasted: leaks and improper retention of memory.

Leaks are cases when repeated invocation of certain activity creates new set of objects that cannot be reclaimed after activity is finished. The biggest problem is accumulation of these objects that leads to increased memory usage and after a long enough time leads to OutOfMemoryError. The nature of this error is that it leaves data structures of an application in undefined state so anything executed after this moment may lead to unexpected results.

Retained memory is memory occupied by objects that were created to serve some purpose but these objects are held longer than necessary. This may mean that some action has to be performed that flushes these objects or they will remain in memory until the end of the session. An example of the former is LRU caches (often holding last component in UI, files or projects). A common example of the latter is resources like parsed bundles or images statically referenced in classes that use them.

-J-Dnetbeans.debug.heap can make profiling easier as it more quickly releases references to collapsed nodes.

If you have the Timers module enabled (normally it is in dev builds), click its button in the Memory toolbar to get a summary of interesting live objects and statistics.

Applies to: NetBeans 6.5 and above

Platforms: All

What is a WeakListener?

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

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

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

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

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

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

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

When should I use a WeakListener?

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

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

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

How can I profile NetBeans?

There are many possibilities how to profile Java applications and that can be applied to NetBeans profiling. For different task it can be good to select different ways because each of them has its strengths and weaknesses.

See also: DevFaqMemoryLeaks

To be able to profile an application it is usually needed to start it with a modified command that typically adds some (JVMPI or JVMTI) libraries, some classes to (boot)classpath, specifies options for profiling and often initializes profiling support before the application starts to run its code.

NetBeans profiler

The NB module development support is integrated with the NB Profiler. Just select a module and click Profile to start.

Want to cover some typical activities like:

Analyzer

It is a sampling profiler working on Solaris and Linux (with limited functionality) that collects data during runtime. These data are later available for offline processing.

It provides some capabilities that are not available in other Java profilers namely timeline view. This view shows timeline for each thread visualizing if the thread actually executes some code or not.

Download and install Analyzer tool

Performance Analyzer that is part of Sun Studio tools and can be downloaded from the developers' site.

Run the Analyzer
export _NB_PROFILE_CMD='collect -p 1 -j on -S off -g NetBeans.erg  -y 38 -d /export/home/radim/analyzer

-p num stands for sampling period (on, hi, lo are also accepted), -j on turns on Java profiling, -y num determines the signal to trigger profiling on/off. -y num,r means that profiling will be resumed at the begining. Use man collect to get detailed explanation of all options.

Profiling hints

Startup: start with profiling enabled, send a signal when startup is completed. When sampling every 1ms it takes 70 seconds instead of 40.

Other tools

Quite simple way how to measure time spent in some code is to wrap the code with

long t0 = System.nanoTime();
try {
  ... measured code
} finally {
  long t1 = System.nanoTime();
  System.out.println("action took "+(t1-t0)/1000000+"ms");
}

JVMTI is powerful interface that allows to write custom libraries that will track behavior of application.

DTrace is a comprehensive dynamic tracing framework for the Solaris??? Operating Environment. It is one of the few tools that allows to track activities running deeply in the system and analyze the system. Because there are also probes provided by Java VM and function like jstack it is also possible to map observed actions to parts of Java code in running application.

Tips and trick

Node pop-ups: interesting starting point is o.o.awt.MouseUtils$PopupMouseAdapter.mousePressed()

How to measure performance/responsiveness?

See What is UI responsiveness for overview.

Older Performance web page contains few links to documentation of one possible approach how to measure and profile responsiveness. This is based on use of modified event queue and patches classes from JDK.

Recently we changed the support a bit to avoid modifications of core JDK's classes and and use small utility library available in Hg. This is used in current automated testing and can be used for manual checks too. To run such test:

  1. Build performance project.
  2. Copy the JAR file to netbeans/platform7/core
  3. Start the IDE with -J-Dnetbeans.mainclass=org.netbeans.performance.test.guitracker.Main -J-Dguitracker.mainclass=org.netbeans.core.startup.Main
  4. ... watch process output when you perform an action

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

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 two ways to do this, depending on what exactly you need:

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

Applies to: NetBeans 6.5 and above

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

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

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

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

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

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

Applies to: NetBeans 6.7 and above

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

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

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

You can also declare your action in your layer manually:

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

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

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

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

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

See also:

How do I add an action to the text-editor popup menu?

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

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

You can also declare your action in your layer manually:

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

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

See also:

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

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

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

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

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

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

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

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

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

and here is how to register it:

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

Applies to: NetBeans 5.0, 5.5, 6.x

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

    1. Implement the corresponding interface such as org.netbeans.spi.project.CopyOperationImplementation.
    2. Implement org.netbeans.spi.project.ActionProvider:
public final class AddActionActions implements ActionProvider {
    private final AddActionProject project; //suppose this is your project
    public AddActionActions(AddActionProject project) {
        this.project = project;
    }
    public String[] getSupportedActions() {
        return new String[] {
            ActionProvider.COMMAND_COPY
        };
    }
    public boolean isActionEnabled(String command, Lookup context) {
        if (command.equals(ActionProvider.COMMAND_COPY)) {
            return true;
        } else {
            throw new IllegalArgumentException(command);
        }
    }
    public void invokeAction(String command, Lookup context) {
        if (command.equalsIgnoreCase(ActionProvider.COMMAND_COPY)){
            DefaultProjectOperations.performDefaultCopyOperation(project);
        }
    }
}
   
    1. Add these implementations to your project's lookup:
lookup = Lookups.fixed(
    // ... as before
    new AddActionOperation(this),
    new AddActionActions(this),
);
   
    1. Register the actions into the project node's context menu:
public @Override Action[] getActions(boolean context) {   
    Action[[ | ]] nodeActions = new Action[2];
    nodeActions[0] = CommonProjectActions.copyProjectAction();
    nodeActions[1] = CommonProjectActions.closeProjectAction();
    return nodeActions;
}
   

See also: Common Project Actions

How do I add an action to a folder?

Add to your layer:

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

How do I add an action to my custom node?

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

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

See also:

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

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

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

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

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

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

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

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

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

Applies to: NetBeans IDE 6.5 and above Platforms: All

How do I add a dropdown menu to toolbar?

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

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

Example:

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

    List handledCharts;

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

    }

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

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

    protected boolean asynchronous() {
        return false;
    }

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

        toggleButton = new JToggleButton();

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

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

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

        buttonGroup = new ButtonGroup();

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

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

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

        return toggleButton;
    }

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

            AnalysisChartTopComponent analysisTc =
                AnalysisChartTopComponent.getSelected();

            if (analysisTc == null) {
                return;
            }

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

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

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

            AbstractHandledChart selectedHandledChart = null;

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

            if (selectedHandledChart == null) {
                return;
            }

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

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

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

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

                SwitchHideShowDrawingLineAction.updateToolbar(viewContainer);
            }

        }
    }

}

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

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

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

private final Lookup lookup;
public MyAction() {
  this (Utilities.actionsGlobalContext());
}

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

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

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

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

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

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

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

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

private LookupResult<? extends DataObject> res;

@Override
public synchronized void addPropertyChangeListener(PropertyChangeListener l) {
  boolean startListening = getPropertyChangeListeners().length == 0;
  super.addPropertyChangeListener(l);
  if (startListening) {
    res = lookup.lookupResult(MyType.class);
    res.addLookupListener(this);
  }
}

@Override
public synchronized void removePropertyChangeListener(PropertyChangeListener l) {
  super.removePropertyChangeListener(l);
  if (getPropertyChangeListeners().length == 0) {
    res.removeLookupListener(this);
    res = null;
  }
}

Now comes the actual implementation of LookupListener:

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

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

  private final Set<Action> popupMenuActions = new WeakSet<Action>();
  @Override
  public Component getToolbarPresenter() {
    JPopupMenu menu = new JPopupMenu();
    Action actionOne = new DemoMenuAction("One");
    Action actionTwo = new DemoMenuAction("Two");
    menu.add(new JMenuItem(actionOne));
    menu.add(new JMenuItem(actionTwo));
    popupMenuActions.add(actionOne);
    popupMenuActions.add(actionTwo);
    //add action listeners to the menu items to do what you want
    Icon icon = (Icon) getValue(SMALL_ICON);
    JButton result = DropDownButtonFactory.createDropDownButton(icon, menu);
    result.setAction(this);
    return result;
  }

  @Override
  public void setEnabled(boolean enabled) {
    super.setEnabled(enabled);
    for (Action a : popupMenuActions) {
      if (a != null) { //WeakSet iterator can return null
        a.setEnabled(enabled);
      }
    }
  }

  private class DemoMenuAction extends AbstractAction {
    DemoMenuAction(String name) {
      putValue(NAME, name);
      setEnabled (MyAction.this.isEnabled());
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      DataObject ob = res.allInstances().iterator().next();
      DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(
              ob.getName()));
    }
  }

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

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

How do I hide/show toolbar dynamically?

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

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

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

Developing.xml:

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

2. Register the configuration files in layer.xml:

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

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

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

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

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

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

containing definitions of overridden labels.

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

See also Technical details

Applies to: NetBeans 5.0, 5.5, 6.x

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

Can I hide or show a whole menu or toolbar?

To hide a menu or toolbar you have to edit your layer.xml and append _hidden to the name of the desired menu or toolbar. You may also hide *.instance files.

<folder name="Menu">
    <!-- Hide View menu -->
    <folder name="View_hidden"/>
    <folder name="SomeMenu">
        <!-- Hide a single menu item -->
        <file name="SomeAction.instance_hidden"/>
    </folder>
</folder>
<folder name="Toolbars">
    <!-- Hide Edit toolbar -->
    <folder name="Edit_hidden"/>
</folder>

It's generally much easier to do this from the NetBeans IDE, as described here.

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.

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

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

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

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

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

Another handy trick: in a built source tree, run

ant index-layer-paths

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

How can I add a JSeparator to the main toolbar?

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

You can do this by creating a class like:

package com.example.util.widgets;

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

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

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

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

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

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

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

Trick #1
 
<file name="org-nvarun-tat-separatorAfter.instance">
    <attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
    <attr name="position" intvalue="175"/>
</file>
<file name="org-nvarun-tat-separatorBefore.instance">
    <attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
    <attr name="position" intvalue="125"/>
</file>
Trick #2
<folder name="Toolbars">
    <folder name="Build">
        <file name="org-nvarun-tat-SayCheez.shadow">
            <attr name="originalFile"
                  stringvalue="Actions/Tools/org-nvarun-tat-SayCheez.instance"/>
            <attr name="position" intvalue="325"/>
        </file>
    </folder>
</folder>
Trick #3
<folder name="Menu">
    <folder name="Tools">
        <file name="org-nvarun-tat-SayCheez.shadow">
            <attr name="originalFile"
                  stringvalue="Actions/Tools/org-nvarun-tat-SayCheez.instance"/>
            <attr name="position" intvalue="150"/>
        </file>
        <file name="org-nvarun-tat-separatorAfter.instance">
            <attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
            <attr name="position" intvalue="175"/>
        </file>
        <file name="org-nvarun-tat-separatorBefore.instance">
            <attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
            <attr name="position" intvalue="125"/>
        </file>
    </folder>
</folder>

Note that these tricks apply to the module which declares the action. You cannot remove an action declared in another module, but you can hide it: DevFaqSwitchingMenusByContext

(Reposted from this entry on NetBeans Zone.)

How do I have only Shortcut Keys for an Action?

The New Action wizard allows you to uncheck both menu and toolbar placement for your action and only assign a keyboard shortcut. To learn how to do this manually, read on. Refer to TaT_HackingNetBeansXMLLayerPartOne for more details.

Trick #1
 
<folder name="Actions">
    <folder name="Tools">        
        <file name="org-nvarun-tat-SayCheez.instance"/>
    </folder>
</folder>
<folder name="Menu">
    <folder name="Tools">
        <file name="org-nvarun-tat-SayCheez.shadow">
            <attr name="originalFile"
                  stringvalue="Actions/Tools/org-nvarun-tat-SayCheez.instance"/>
            <attr name="position" intvalue="150"/>
        </file>
    </folder>
</folder>
<folder name="Toolbars">
    <folder name="Build">
        <file name="org-nvarun-tat-SayCheez.shadow">
            <attr name="originalFile"
                  stringvalue="Actions/Tools/org-nvarun-tat-SayCheez.instance"/>
            <attr name="position" intvalue="325"/>
        </file>
    </folder>
</folder>
<folder name="Shortcuts">
    <file name="O-F3.shadow">
        <attr name="originalFile"
              stringvalue="Actions/Tools/org-nvarun-tat-SayCheez.instance"/>
    </file>
</folder>
Trick #2
Tips to Remember
  1. Following are some keycode equivalents. See Javadoc for KeyEvent for the full list:
  • A to Z (as is), F1 to F12 (as is), 0 to 9 (as is)
  • / as SLASH, \ as BACK_SLASH
  • ; as SEMI_COLON
  • . as PERIOD
  • ??? as QUOTE

See also DevFaqKeybindings.

(Reposted from this entry on NetBeans Zone.)

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

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

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

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

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

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

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

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

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

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

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 as the lookupAll method is not present yet.

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

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

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

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

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 unless it can access the object's class, and it won't be able to access the object's class unless it declares a dependency on the API module that defines it. (A <T> Map<Class<T>,T> would do the same job as Lookup.)
  2. The class of values in a map can change without notice - so if you have (SomeIface) foo = (SomeIface) globalMap.get("foo"), some new version of the module that provides "foo" can change the return type, causing ClassCastException s; with Lookup, you cannot ever get an object that is not of the type you passed in the request - so Lookup's approach is more robust.
  3. Lookup supports listening to changes in the result.
  4. Lookup supports multiple instances for one key. (Sort of like <T> Map<Class<T>,List<T>> )

There are some other capabilities of Lookup (such as getting classes of results without instantiating them, and naming result items) but these are rarely used in practice.

Lookup is very powerful, yet simple and generic; people quickly learn to love it, once they realize what it can do.

How do I use Java generics with Lookup?

As of NetBeans 6, a number of convenience methods have been added to lookup, and support for Java generics has been added to Lookup. The following are differences:

NB 5.x Code NB 6 Code
Lookup.Result r = lkp.lookup(
|}

  new Lookup.Template(X.class))
|
Lookup.Result<? extends X> r = 
  lkp.lookupResult(X.class)
Collection c = r.allInstances()
{Collection<? extends X> c =
 r.allInstances()</pre>
Collection<? extends X> c = 
  lkp.lookupAll(X.class);

The new style also works well with for-loops and avoids casts:

for (SomeService s : Lookup.getDefault().lookupAll(SomeService.class)) {
    // ...
}
// ...
SomeSingleton s = Lookup.getDefault().lookup(SomeSingleton.class);
if (s != null) {
    // ...
}

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 lookup are instantiated lazily when first requested.

Here is the usual usage pattern:

1. A central "controller" module defines some interface, e.g.

package controller.pkg;
public interface MyService {
    void doSomething();
}

2. Each module which wants to implement that service depends on the controller module which defines the interface, and creates and registers an implementation:

@ServiceProvider(service=MyService.class)
public class MyImpl implements MyService {
    public void doSomething() {....}
}

It is also possible to declaratively mask other people's implementations and declaratively order implementations so some will take precedence.

3. The controller finds all implementations and uses them somehow:

for (MyService s : Lookup.getDefault().lookupAll(MyService.class)) {
    s.doSomething();
}
More About Lookup

Applies to: NetBeans 6.7 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 an class, such as TopComponent or Node which has a method getLookup(), and to need to add to or filter the original Lookup's contents. There are a number of convenience factories and classes which make it easy to do this:

If you need to customize a Node's lookup, read the FAQ item on how to do that.

If there is more than one of a type in a Lookup, which instance will I get?

As noted in the overview of Lookup, a Lookup can contain more than one instance of a given class; Lookup is often used for singletons, but not exclusively for singletons. For example, in the Projects API, there is a class called ProjectFactory that recognizes different types of user projects on disk; each module that provides a project type registers another factory in the system.

So the inevitable question is, if there are two instances of X in a Lookup, and I call lookup(X.class), which one do I get?

The answer is, it's undefined - don't do that. The next inevitable question is, but how can that be?

A Lookup makes no assumptions about what's in it, or what you might want to put in it, or how many of anything there should be. That contract is an agreement between whoever tells you that you should get an instance of X from some Lookup and you. If they document that there will only be one, use Lookup.lookup(Class); if they document that there can be more than one, use Lookup.lookup(Lookup.Template) and iterate the results.

In practice this is a non-problem - anything you are going to try to find in a Lookup is going to document whether it is supposed to be a singleton or not.

How can I find out what is in a Lookup

Do not do any of these things in production code!

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

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

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

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

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.

Token.java
public final class Token {
      
    private final long id;

    public Token(long id) {
        this.id = id;
    }

    public long getId() {
       return id;
    }
}
LazyLoadingDelegate.java
import org.openide.util.lookup.InstanceContent;

public class LazyLoadingDelegate implements InstanceContent.Convertor<Token, AnExpensiveClass> {

    @Override
    public AnExpensiveClass convert(Token token) {
        // this will be called when something actually requests an instance 
        // of AnExpensiveClass from the lookup.  We just need to create and
        // return an instance based on the supplied token (i.e. assume that 
        // the AnExpensiveClass constructor will load data from the database 
        // and populate the instance we're returning).
        return new AnExpensiveClass(token);
    }

    @Override
    public Class<? extends AnExpensiveClass> type(Token token) {
        return AnExpensiveClass.class;
    }

    @Override
    public String id(Token token) {
        return String.valueOf(token.getId());
    }

    @Override
    public String displayName(Token token) {
        return "my lazy loading delegate";
    }
}
Code that creates a Lookup and registers the InstanceContent:
    ic = new InstanceContent();
    al = new AbstractLookup(ic);
        
    Token token = new Token(12345);
    ic.add(token, new LazyLoadingDelegate());

And your context-sensitive action will look like normal; it does not need to know about the lazy loading (code not relevant to lazy loading has been removed for the sake of brevity):

public final class ExpensiveClassAction 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...
    }
}

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="Hidden">
            <file name="com-tomwheeler-example-this-name-is-Irrelevant.instance">
                <attr name="instanceClass"
                      stringvalue="com.tomwheeler.example.impl.SampleImplementation"/>
                <attr name="instanceOf"
                      stringvalue="com.tomwheeler.example.intf.SampleInterface"/>
            </file>
        </folder>
    </folder>
</filesystem>

The name of the file is arbitrary but must end with .instance. The value of the instanceClass attribute needs to define the implementation class being registered, while instanceOf defines the interface (or abstract class) being implemented.

If you want to create the implementation using a factory method rather than calling a zero-argument constructor, replace instanceClass with instanceCreate, e.g.:

<attr name="instanceCreate"
      methodvalue="com.tomwheeler.example.impl.SampleImplementations.make"/>

It is also possible to pass parameters to the factory method; see API documentation for details.

Client code is unaware of the registration mechanism, so the code used to look up a registered implementation of the interface would be the same as always; for example:

SampleInterface intf = Lookup.getDefault().lookup(SampleInterface.class);
// now do something with intf...

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 (File f)

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

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

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

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

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

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

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

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

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

Language Parsing Support (e.g., ANTLR, javaCC)

How can I add support for a new language via javaCC?

1) Overview

This tutorial aims to help NetBeans Platform developers implement support for a new language in their application, for example, in NetBeans IDE. It is focused on editor features such as syntax coloring, error highlighting, parsing, code folding, code completion, etc. Descriptions of how to implement a new project or to provide "run" or "debug" support are out of the scope of this document.

This tutorial contains links to detailed API descriptions for APIs used during language support implementation and provides links to modules you will need to depend on. It is based on NetBeans Platform 6.7 or above (e.g., 6.8 too). Previous versions of the NetBeans Platform do not contain all the APIs used here and there are several new ways of implementing the features relevant to this document.

We will use the "javaCC" parser generator in this tutorial (go here for ANTLR), so you will learn some basic info about lexers, grammars, error recovery and the javaCC parser generator. Creating a new language, and defining its grammar, is not an easy task. That is why we will use an existing Java 1.5 grammar file in this tutorial.

You are assumed to have some basic knowledge of lexical analysis, syntactical analysis, and a basic understanding of language grammars.

Note: If you do not have any/much experience with NetBeans module development, you are highly recommended to follow several tutorials on the NetBeans Platform Learning Trail BEFORE continuing with the steps that follow. In particular, the File Type Integration Tutorial should be very familiar to you.

The sources of the module that you build in this tutorial are found here on Kenai:

http://kenai.com/projects/org-simplejava

2) Establish your new project, generate MIME type recognizer and generate data loader.

Step 1: Create a new NetBeans module.

Choose New Project | NetBeans Modules | Module. Type "Simplejava" as the project name, choose an appropriate folder as the Project Location, check "Standalone Module", and click Next.

Type "org.simplejava" as the Code Name Base, "Simple Java" as the Module Display Name and check "Generate XML Layer".

The IDE will create the module on disk and display its project structure in the IDE.


Step 2: Generate DataObject and MIME type resolver for your language.

Select "Simple Java" project node, New > Other... > Module Development > File Type. Select "text/x-simplejava" as a MIME Type, "sj" as a Extension and "SJ" as a Class Name Prefix. IDE will generate "SJDataObject.java", "SJResolver.xml", "SJTemplate.sj" files, and add some registrations to your "layer.xml" file.

If you would like to know more about stuff generated by IDE to your module now, follow these links:

You can Compile your project and Run NetBeans with this new module (select "Simple Java" project root node and select "Run" from pop-up menu). NetBeans is able to recognize "sj" files and open them in text editor. Now we will focus on a basic syntax coloring.

3) Syntax Coloring.

Syntax Coloring is a basic feature of every programming language support. In order to implement Syntax Coloring you need some Lexer (Tokenizer, Lexical Analyser). See http://en.wikipedia.org/wiki/Lexical_analyser for more info about lexical analyses. There are several ways how to create Lexer for your language. You can implement lexer by yourself, or use some existing tool that generates lexer implementation from some formal descriprion of your language (JavaCC, ANTLR, Flex...). If you would like to implement your lexer directly, you should implement "org.netbeans.spi.lexer.LanguageHierarchy", "org.netbeans.api.lexer.TokenId" and "org.netbeans.spi.lexer.Lexer" classes form NetBeans "lexer" module. See "http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-lexer/overview-summary.html" for more info about Lexer APIs, and some real implementations: "java.lexer/src/org/netbeans/lib/java/lexer/JavaLexer.java", "languages.manifest/src/org/netbeans/modules/languages/manifest/MfLexer.java" or "cnd.lexer/src/org/netbeans/modules/cnd/lexer/ShLexer.java".

But we will use "JavaCC" to generate lexer in this tutorial. So download javacc-4.0.zip from "https://javacc.dev.java.net" and unpack it to some "/myjavacc40" folder. We will use grammar specified in "/myjavacc40/examples/JavaGrammars/1.5/Java1.5.jj" file. You can try to use some different version of JavaCC, but there can be some differences in generated files.

If you are using ANTLR to generate your lexer and parser you can read the ANTLR adaptation tutorial.

Step 3: Generate "Simple Java" lexer via JavaCC.

Create "org.simplejava.jcclexer" package in your "Simple Java" project, and copy "/myjavacc40/examples/JavaGrammars/1.5/Java1.5.jj" and "/myjavacc40/examples/JavaGrammars/1.5/Token.java" files there. Add "package org.simplejava.jcclexer;" line to "Java1.5.jj" file after "PARSER_BEGIN(JavaParser)" line:

PARSER_BEGIN(JavaParser)

package org.simplejava.jcclexer;

import java.io.*;
import java.util.*;

And add "package org.simplejava.jcclexer;" line to second line of "Token.java" file after "/* Generated By:JavaCC: Do not edit this line. Token.java Version 3.0 */":

/* Generated By:JavaCC: Do not edit this line. Token.java Version 3.0 */
package org.simplejava.jccparser;

"Java1.5.jj" file contains descriptions of tokens for Java parser. Thats nearly what we need for our Java lexer. But there are some differences. Lexer defined for parser hides some types of tokens - typically comments and whitespaces. But we need to see such tokens in NetBeans lexer, because we need to define special colors for comments. So we need to change that in our JavaCC file. We should change:

SKIP :
{
  " "
| "\t"
| "\n"
| "\r"
| "\f"
}

to:

TOKEN :
{
  < WHITESPACE:
  " "
| "\t"
| "\n"
| "\r"
| "\f">
}

and change all SPECIAL_TOKEN definitions:

SPECIAL_TOKEN :
{
  <SINGLE_LINE_COMMENT: "//" (~["\n","\r"])* ("\n" | "\r" | "\r\n")?>
}

<IN_FORMAL_COMMENT>
SPECIAL_TOKEN :
{
  <FORMAL_COMMENT: "*/" > : DEFAULT
}

<IN_MULTI_LINE_COMMENT>
SPECIAL_TOKEN :
{
  <MULTI_LINE_COMMENT: "*/" > : DEFAULT
}

to TOKEN definitions:

TOKEN :
{
  <SINGLE_LINE_COMMENT: "//" (~["\n","\r"])* ("\n" | "\r" | "\r\n")?>
}

<IN_FORMAL_COMMENT>
TOKEN :
{
  <FORMAL_COMMENT: "*/" > : DEFAULT
}

<IN_MULTI_LINE_COMMENT>
TOKEN :
{
  <MULTI_LINE_COMMENT: "*/" > : DEFAULT
}

As we will use our "org.simplejava.jcclexer.Java1.5.jj" grammar file for tokenizer only, we can simplify it. Set BUILD_PARSER property to false:

options {
  JAVA_UNICODE_ESCAPE = true;
  ERROR_REPORTING = false;
  STATIC = false;
  JDK_VERSION = "1.5";
  BUILD_PARSER = false;
}

Delete JavaParser class body:

PARSER_BEGIN(JavaParser)

package org.simplejava.jcclexer;

public class JavaParser {}

PARSER_END(JavaParser)

And delete:

/*****************************************
 * THE JAVA LANGUAGE GRAMMAR STARTS HERE *
 :::***************************************/
and rest of "Java1.5.jj" file.

"Java1.5.jj" file is ready now, and we can "compile" it from command line now:

cd /myprojects/simplejava/src/org/simplejava/jcclexer
/myjavacc40/bin/javacc Java1.5.jj

The JavaCC parser generator will generate the "JavaCharStream.java", "JavaParserConstants.java", "JavaParserTokenManager.java", "ParseException.java", and "TokenMgrError.java" files into your "org.simplejava.jcclexer" package. All the files should be compilable:

[image - see online version]

We've now completed the JavaCC part of the tutorial. The time has come to use the generated files to create our NetBeans Lexer plugin.

Step 4: Create NetBeans Lexer plugin.

We should define dependency on Lexer module first: select "Simple Java" project root node, select "Properties" item form popup menu, check "Show Non-API Modules", and select "Libraries", "Add...". Now you should search for "Lexer" (in "Filter" input line), and add it to libraries. Create "org.simplejava.lexer" package in your project now.

The first class we have to implement is TokenId. TokenId represents one type of token. It has three properties: name (unique name of this token type like "KEYWORD_IF"), id (unique number) and primaryCategory. primaryCategory can be used if you want to share the same tokens coloring color for more token types:

import org.netbeans.api.lexer.Language;
import org.netbeans.api.lexer.TokenId;

public class SJTokenId implements TokenId {

    private final String        name;
    private final String        primaryCategory;
    private final int           id;
    
    SJTokenId (
        String                  name,
        String                  primaryCategory,
        int                     id
    ) {
        this.name = name;
        this.primaryCategory = primaryCategory;
        this.id = id;
    }

    @Override
    public String primaryCategory () {
        return primaryCategory;
    }

    @Override
    public int ordinal () {
        return id;
    }

    @Override
    public String name () {
        return name;
    }
}

LanguageHierarchy contains list of token types for our language, and creates a new instances of our Lexer:

import java.util.*;
import org.netbeans.spi.lexer.*;

public class SJLanguageHierarchy extends LanguageHierarchy<SJTokenId> {

    private static List<SJTokenId>  tokens;
    private static Map<Integer,SJTokenId>
                                    idToToken;

    private static void init () {
        tokens = Arrays.<SJTokenId> asList (new SJTokenId[] {
            //[PENDING]
        });
        idToToken = new HashMap<Integer, SJTokenId> ();
        for (SJTokenId token : tokens)
            idToToken.put (token.ordinal (), token);
    }

    static synchronized SJTokenId getToken (int id) {
        if (idToToken == null)
            init ();
        return idToToken.get (id);
    }

    protected synchronized Collection<SJTokenId> createTokenIds () {
        if (tokens == null)
            init ();
        return tokens;
    }

    protected synchronized Lexer<SJTokenId> createLexer (LexerRestartInfo<SJTokenId> info) {
        return new SJLexer (info);
    }

    protected String mimeType () {
        return "text/x-simplejava";
    }
}

Lexer implementation reads input text and returns tokens for it. But our Lexer implementation delegates to lexer generated by JavaCC:

class SJLexer implements Lexer<SJTokenId> {

    private LexerRestartInfo<SJTokenId> info;
    private JavaParserTokenManager javaParserTokenManager;


    SJLexer (LexerRestartInfo<SJTokenId> info) {
        this.info = info;
        JavaCharStream stream = new JavaCharStream (info.input ());
        javaParserTokenManager = new JavaParserTokenManager (stream);
    }

    public org.netbeans.api.lexer.Token<SJTokenId> nextToken () {
        Token token = javaParserTokenManager.getNextToken ();
        if (info.input ().readLength () < 1) return null;
        return info.tokenFactory ().createToken (SJLanguageHierarchy.getToken (token.kind));
    }

    public Object state () {
        return null;
    }

    public void release () {
    }
}

We can register our plugin now. Add following code to your SJTokenId file:

    private static final Language<SJTokenId> language = new SJLanguageHierarchy ().language ();

    public static final Language<SJTokenId> getLanguage () {
        return language;
    }

and following registration to your layer.xml file:

    <folder name="Editors">
        <folder name="text">
            <folder name="x-simplejava">
                ... some current registrations ...
                <file name="language.instance">
                    <attr name="instanceCreate" methodvalue="org.simplejava.lexer.SJTokenId.getLanguage"/>
                    <attr name="instanceOf" stringvalue="org.netbeans.api.lexer.Language"/>
                </file>
            </folder>
        </folder>
    </folder>

See more information about Lexer APIs here.

Your source structure should now look as follows:

[image - see online version]

Both parts of our lexer job are done (NetBeans Lexer plugin and real implementation of lexer generated by JavaCC.) Now we need to connect them together.

Step 5: Connect your NetBeans Lexer plugin with lexer generated by JavaCC.

We should reimplement JavaCharStream first:

public class JavaCharStream {

    private LexerInput input;

    static boolean staticFlag;

    public JavaCharStream (LexerInput input) {
        this.input = input;
    }

    JavaCharStream (Reader stream, int i, int i0) {
        throw new UnsupportedOperationException ("Not yet implemented");
    }

    JavaCharStream (InputStream stream, String encoding, int i, int i0) throws UnsupportedEncodingException {
        throw new UnsupportedOperationException ("Not yet implemented");
    }

    char BeginToken () throws IOException {
        return (char) input.read ();
    }

    String GetImage () {
        return input.readText ().toString ();
    }
    
     public char[] GetSuffix (int len) {
        if (len > input.readLength ())
            throw new IllegalArgumentException ();
        return input.readText (input.readLength () - len, input.readLength ()).toString ().toCharArray ();
     }

    void ReInit (Reader stream, int i, int i0) {
        throw new UnsupportedOperationException ("Not yet implemented");
    }

    void ReInit (InputStream stream, String encoding, int i, int i0) throws UnsupportedEncodingException {
        throw new UnsupportedOperationException ("Not yet implemented");
    }

    void backup (int i) {
        input.backup (i);
    }

    int getBeginColumn () {
        return 0;
    }

    int getBeginLine () {
        return 0;
    }

    int getEndColumn () {
        return 0;
    }

    int getEndLine () {
        return 0;
    }

    char readChar () throws IOException {
        return (char) input.read ();
    }
}

This version of JavaCharStream reads input chars from LexerInput, in place of standard InputStream. And now we should introduce JavaCC token types to our Lexer plugin. Just rewrite token types defined in JavaParserConstants file generated by JavaCC:

public interface JavaParserConstants {
  int EOF = 0;
  int WHITESPACE = 1;
  int SINGLE_LINE_COMMENT = 4;
  int FORMAL_COMMENT = 5;
  int MULTI_LINE_COMMENT = 6;
  int ABSTRACT = 8;
  int ASSERT = 9;
  int BOOLEAN = 10;
  int BREAK = 11;
  int BYTE = 12;
  int CASE = 13;
  int CATCH = 14;
  int CHAR = 15;
  ...

to your SJLanguageHierarchy file:

import static org.simplejava.jcclexer.JavaParserConstants.*;

public class SJLanguageHierarchy extends LanguageHierarchy<SJTokenId> {

    private static List<SJTokenId>  tokens;
    private static Map<Integer,SJTokenId>
                                    idToToken;

    private static void init () {
        tokens = Arrays.<SJTokenId> asList (new SJTokenId[] {
            new SJTokenId ("EOF", "whitespace", EOF),
            new SJTokenId ("WHITESPACE", "whitespace", WHITESPACE),
            new SJTokenId ("SINGLE_LINE_COMMENT", "comment", SINGLE_LINE_COMMENT),
            new SJTokenId ("FORMAL_COMMENT", "comment", FORMAL_COMMENT),
            new SJTokenId ("MULTI_LINE_COMMENT", "comment", MULTI_LINE_COMMENT),
            new SJTokenId ("ABSTRACT", "keyword", ABSTRACT),
            new SJTokenId ("ASSERT", "keyword", ASSERT),
            new SJTokenId ("BOOLEAN", "keyword", BOOLEAN),
            new SJTokenId ("BREAK", "keyword", BREAK),
            new SJTokenId ("BYTE", "keyword", BYTE),
            new SJTokenId ("CASE", "keyword", CASE),
            new SJTokenId ("CATCH", "keyword", CATCH),
            new SJTokenId ("CHAR", "keyword", CHAR),
            ...

Token category should correspond to the color you want to see in the editor. Notice that we MUST keep token identifiers (numbers)!!!

Go here to access the completed file:

http://kenai.com/projects/org-simplejava

We have JavaCC generated lexer integrated to IDE. And we can define concrete colors for our tokens now.

Step 6: Define concrete colors for your token types.

Color for token types are defined declaratively in one xml file. Create FontAndColors.xml file in /myprojects/simplejava/src/org/simplejava folder:

<!DOCTYPE fontscolors PUBLIC 
    "-//NetBeans//DTD Editor Fonts and Colors settings 1.1//EN"  
    "http://www.netbeans.org/dtds/EditorFontsColors-1_1.dtd">
<fontscolors>
    <fontcolor name="character" default="char"/>
    <fontcolor name="errors" default="error"/>
    <fontcolor name="identifier" default="identifier"/>
    <fontcolor name="keyword" default="keyword" foreColor="red"/>
    <fontcolor name="literal" default="keyword" />
    <fontcolor name="comment" default="comment"/>
    <fontcolor name="number" default="number"/>
    <fontcolor name="operator" default="operator"/>
    <fontcolor name="string" default="string"/>
    <fontcolor name="separator" default="separator"/>
    <fontcolor name="whitespace" default="whitespace"/>
    <fontcolor name="method-declaration" default="method">
        <font style="bold" />
    </fontcolor>
</fontscolors>

This file defines how to visualize tokens produced by lexer.

"fontcolor" tag properties:

NetBeans main menu > Tools > Options > Fonts & Colors, if you select "Language: All Languages".

"fontcolor" tag can contain nested font tag. "font" tag has following properties:

See DTD for this file here.

List of all token colors are editable in NetBeans Options Dialog. We should provide some short example text written in our language. So create file "/myprojects/simplejava/src/org/simplejava/SimpleJavaExample.sj" with following content:

/**
 * SimpleJavadoc comment for <code>SimpleJavaExample</code> class.
 * @author Simple Joe Smith
 */
public class SimpleJavaExample {
    
    @Deprecated public String method (int param) {
        return "SimpleString " + '-' + 1.2;
    }// line comment
}


Do not forget to register your "FontAndColors.xml" and "SimpleJavaExample.sj" files in your "layer.xml":

    <folder name="Editors">
        <folder name="text">
            <folder name="x-simplejava">
                ... some current registrations ...
                <attr name="SystemFileSystem.localizingBundle" stringvalue="org.simplejava.Bundle"/>
                <folder name="FontsColors">
                    <folder name="NetBeans">
                        <folder name="Defaults">
                            <file name="FontAndColors.xml" url="FontAndColors.xml">
                                <attr name="SystemFileSystem.localizingBundle" stringvalue="org.simplejava.Bundle"/>
                            </file>
                        </folder>
                    </folder>
                </folder>
            </folder>
        </folder>
    </folder>
    <folder name="OptionsDialog">
        <folder name="PreviewExamples">
            <folder name="text">
                <file name="x-simplejava" url="SimpleJavaExample.sj"/>
            </folder>
        </folder>
    </folder>

Your "/myprojects/simplejava/src/org/Bundle.properties" file should contain localized names of your language, and token types:

text/x-simplejava=Simple Java
character=Character
errors=Error
identifier=Identifier
keyword=Keyword
literal=Literal
comment=Comment
number=Number
operator=Operator
string=String
separator=Separator
whitespace=Whitespace
method-declaration=Method Declaration

Syntax coloring is finished! You can rename some Foo.java file to Foo.sj and open it in the NetBeans editor. It should be colored, all keywords should be red:

[image - see online version]

Go to Tools > Options > Fonts & Colors. The Language drop-down list should contain a "Simple Java" entry, as you can see below. If you select it you will see a list of your token types and your "Simple Java" example text. You can change the colors for your tokens here too:

[image - see online version]

4) Parser integration

Step 7: Generate "Simple Java" parser by JavaCC.

Create "org.simplejava.jccparser" package and copy "/myjavacc40/examples/JavaGrammars/1.5/Java1.5.jj" and "/myjavacc40/examples/JavaGrammars/1.5/Token.java" files there. Add "package org.simplejava.jcclexer;" line to "Java1.5.jj" file after "PARSER_BEGIN(JavaParser)" line. And add "package org.simplejava.jcclexer;" line to second line of "Token.java" file after "/* Generated By:JavaCC: Do not edit this line. Token.java Version 3.0 */".

Compile "Java1.5.jj" file.

We have "Simple Java" parser now, and we can integrate it to NetBeans now.

Step 8: Integrate parser to NetBeans.

Implementation of Parser API is similair to other NetBeans APIs. You have to implement Parser class, ParserFactory and register ParserFactory in your layer.xml file.

So, create "org.simplejava.parser" package.

Add dependency on "Parsing API" (select root node of your module > Properties > Libraries > Add...).

Create "SJParserFactory" class in "parser" package:

public class SJParserFactory extends ParserFactory {

    @Override
    public Parser createParser (Collection<Snapshot> snapshots) {
        return new SJParser ();
    }
}

Create "SJParser" class:

public class SJParser extends Parser {

    private Snapshot snapshot;
    private JavaParser javaParser;

    @Override
    public void parse (Snapshot snapshot, Task task, SourceModificationEvent event) {
        this.snapshot = snapshot;
        Reader reader = new StringReader (snapshot.getText ().toString ());
        javaParser = new JavaParser (reader);
        try {
            javaParser.CompilationUnit ();
        } catch (org.simplejava.jccparser.ParseException ex) {
            Logger.getLogger (SJParser.class.getName()).log (Level.WARNING, null, ex);
        }
    }

    @Override
    public Result getResult (Task task) {
        return new SJParserResult (snapshot, javaParser);
    }

    @Override
    public void cancel () {
    }

    @Override
    public void addChangeListener (ChangeListener changeListener) {
    }

    @Override
    public void removeChangeListener (ChangeListener changeListener) {
    }

    
    public static class SJParserResult extends Result {

        private JavaParser javaParser;
        private boolean valid = true;

        SJParserResult (Snapshot snapshot, JavaParser javaParser) {
            super (snapshot);
            this.javaParser = javaParser;
        }

        public JavaParser getJavaParser () throws org.netbeans.modules.parsing.spi.ParseException {
            if (!valid) throw new org.netbeans.modules.parsing.spi.ParseException ();
            return javaParser;
        }

        @Override
        protected void invalidate () {
            valid = false;
        }
    }
}

And register ParserFactory in your layer:

    <folder name="Editors">
        <folder name="text">
            <folder name="x-simplejava">
                ... some current registrations ...
                <file name="org-simplejava-parser-SJParserFactory.instance"/>
            </folder>
        </folder>
    </folder>

Your parser generated by JavaCC is registerred in NetBeans now. You can compile and run "Simple Java" module. But your parser will never be called. There is simple reason. Nobody asks for parser results, there is no client of "Simple Java" parser. So, we should create some client for our parser.

Step 9: Adding some basic error recovery to our parser.

We will create a first client of SJParser now. This client (task) will show syntax errors in editor gutter. But we should do several modifications to our parser first. Our parser throws ParseException when it finds first error in source code. This is default behaviour of parsers genearted by JavaCC. But in the IDE we need to detect more than one syntax error. So we should try to add some simple error recovery to our parser:

1) Change "ERROR_REPORTING = false;" to "ERROR_REPORTING = true;".

2) Add "import java.util.*;" to your Java1.5.jj file.

3) Add following method to your JavaParser body:

   public List<ParseException> syntaxErrors = new ArrayList<ParseException> ();

   void recover (ParseException ex, int recoveryPoint) {
      syntaxErrors.add (ex);
      Token t;
      do {
          t = getNextToken ();
      } while (t.kind != recoveryPoint);
   }

4) Catch ParseExceptions in FieldDeclaration, MethodDeclaration and Statement :

void CompilationUnit():
{}
{
    try {
        [LOOKAHEAD((Annotation())*"package")PackageDeclaration() ]
        ( ImportDeclaration() )*
        ( TypeDeclaration() )*
        ( < "\u001a" > )?
        ( <STUFF_TO_IGNORE: ~[]> )?
        <EOF>
    } catch (ParseException ex) {
        recover (ex, SEMICOLON);
    }
}
...
void FieldDeclaration(int modifiers):
{}
{
    try {
      // Modifiers are already matched in the caller
      Type() VariableDeclarator() ( "," VariableDeclarator() )* ";"
    } catch (ParseException ex) {
        recover (ex, SEMICOLON);
    }
}
...
void MethodDeclaration(int modifiers):
{}
{
    try {
        // Modifiers already matched in the caller!
        [TypeParameters() ]
        ResultType()
        MethodDeclarator() ["throws"NameList() ]
        ( Block() | ";" )
    } catch (ParseException ex) {
        recover (ex, SEMICOLON);
    }

}
...
void Statement():
{}
{
    try {
          LOOKAHEAD(2)
          LabeledStatement()
        |
          AssertStatement()
        |
          Block()
        |
          EmptyStatement()
        |
          StatementExpression() ";"
        |
          SwitchStatement()
        |
          IfStatement()
        |
          WhileStatement()
        |
          DoStatement()
        |
          ForStatement()
        |
          BreakStatement()
        |
          ContinueStatement()
        |
          ReturnStatement()
        |
          ThrowStatement()
        |
          SynchronizedStatement()
        |
          TryStatement()
    } catch (ParseException ex) {
        recover (ex, SEMICOLON);
    }
}

Recompile Java1.5.jj now:

cd /myprojects/simplejava/src/org/simplejava/jcclexer
/myjavacc40/bin/javacc Java1.5.jj

We have added some very basic error recovery to our parser. So we can display syntax errors in editor now.

Step 10: Syntax errors reporting.

Now we are ready to implement our first ParserResultTask. This task consists from three usual steps: create some factory (TaskFactory), create task (ParserResultTask) and register factory in layer.xml file:

Create "SyntaxErrorsHighlightingTaskFactory" class in "org.simplejava.parser" package:

import org.netbeans.modules.parsing.api.Snapshot;
import org.netbeans.modules.parsing.spi.SchedulerTask;
import org.netbeans.modules.parsing.spi.TaskFactory;

public class SyntaxErrorsHighlightingTaskFactory extends TaskFactory {

    @Override
    public Collection<? extends SchedulerTask> create (Snapshot snapshot) {
        return Collections.singleton (new SyntaxErrorsHighlightingTask ());
    }
}

Create "SyntaxErrorsHighlightingTask" class:

class SyntaxErrorsHighlightingTask extends ParserResultTask {

    public SyntaxErrorsHighlightingTask () {
    }

    @Override
    public void run (Result result, SchedulerEvent event) {
        try {
            SJParserResult sjResult = (SJParserResult) result;
            List<ParseException> syntaxErrors = sjResult.getJavaParser ().syntaxErrors;
            Document document = result.getSnapshot ().getSource ().getDocument (false);
            List<ErrorDescription> errors = new ArrayList<ErrorDescription> ();
            for (ParseException syntaxError : syntaxErrors) {
                Token token = syntaxError.currentToken;
                int start = NbDocument.findLineOffset ((StyledDocument) document, token.beginLine - 1) + token.beginColumn - 1;
                int end = NbDocument.findLineOffset ((StyledDocument) document, token.endLine - 1) + token.endColumn;
                ErrorDescription errorDescription = ErrorDescriptionFactory.createErrorDescription (
                    Severity.ERROR,
                    syntaxError.getMessage (),
                    document,
                    document.createPosition (start),
                    document.createPosition (end)
                );
                errors.add (errorDescription);
            }
            HintsController.setErrors (document, "simple-java", errors);
        } catch (BadLocationException ex1) {
            Exceptions.printStackTrace (ex1);
        } catch (org.netbeans.modules.parsing.spi.ParseException ex1) {
            Exceptions.printStackTrace (ex1);
        }
    }

    @Override
    public int getPriority () {
        return 100;
    }

    @Override
    public Class<? extends Scheduler> getSchedulerClass () {
        return Scheduler.EDITOR_SENSITIVE_TASK_SCHEDULER;
    }

    @Override
    public void cancel () {
    }
}

And register TaskFactory in your layer:

    <folder name="Editors">
        <folder name="text">
            <folder name="x-simplejava">
                ... some current registrations ...
                <file name="org-simplejava-parser-SyntaxErrorsHighlightingTaskFactory.instance"/>
            </folder>
        </folder>
    </folder>

Check that your source structure is now as follows:

[image - see online version]

When you install the module again, you should see syntax errors marked as follows:

[image - see online version]

Our simplejava parser is now integrated into the NetBeans Platform, and we can continue coding new features based on it, as done above for syntax error checking.

Apendix A: List of APIs referenced from this tutorial
Name of API Description Name of module
File Systems and MIME Type Resolvers Manipulate files and their MIME types. openide.filesystems
Data Systems Define icon, actions, and more for your files. openide.loaders
Lexer API Define tokens of your language and way how to visualise them. lexer
Parsing API Integrate a parser with the rest of the IDE. parsing.api

How can I add support for a new language via ANTLR?

This will serve as the index page that links to everything we know about how to integrate ANTLR into a NetBeans Platform application (go here for javaCC).

Notes on the above.

Other useful links:

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?

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 customize the content of my Node'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.

I need to write some code that tracks the global selection. What should I do?

If you are writing an action, consider using one of the context sensitive action classes in the apis such as NodeAction or CookieAction.

For other types of code (or for actions sensitive to something that does not implement Node.Cookie in the active TopComponent's or Node's Lookup , consider using Utilities.actionsGlobalContext().

Utilities.actionsGlobalContext() returns a Lookup which proxies the Lookup of the active (focused) TopComponent's Lookup (which, if it is an explorer view, is proxying the Lookup(s) of whatever Node(s) are selected). You can do something like this:

Lookup.Template tpl = new Lookup.Template (SomeApiClass.class);
Lookup.Result res = Utilities.actionsGlobalContext().lookup (tpl);
res.addLookupListener (new LookupListener() {
   public void resultChanged (LookupEvent evt) {
     Collection c = ((Lookup.Result) evt.getSource()).allInstances();
     //do something with the collection of 0 or more instances - the collection has changed
   }
});

The nice thing about this approach is that, unless your code specifically cares about Nodes, you don't need to depend on the Nodes API.

The idea behind this is that every "logical window" in NetBeans has its own Lookup, whose contents represent the "selection" in that window (or whatever services it wants to expose). Utilities.actionsGlobalContext() is a single point of entry - you don't have to track which window currently has focus - it is a Lookup which proxies the Lookup of whatever window does have focus. When the focused window changes, the Lookup returned by Utilities.actionsGlobalContext() will fire the appropriate changes. So, for example, an Action can be written to be sensitive to a particular object type; it does not need any code that relates to tracking window focus or similar.

Please note: Generally, keep a hard reference on the Lookup.Result (or make a closure on it with some final keyword and a reference from the anonymous listener). Because if you don't -- the garbage collector might kick in quite soon and your listener won't be called. Source: Lookup.Result garbage collection trick

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

    private final FileFilter fileFilter;
   
    static class FileFilteredChildren extends FilterNode.Children {
        private final FileFilter fileFilter;
   
        public FileFilteredChildren (Node owner, FileFilter fileFilter) {
            super(owner);
            this.fileFilter = fileFilter;
          }

        @Override
        protected Node copyNode (Node original) {
            return new FileFilteredNode(original, fileFilter);
          }

        @Override
        protected Node[] createNodes (Object object) {
            List<Node> result = new ArrayList<Node>();

            for (Node node : super.createNodes(object)) {
                DataObject dataObject = (DataObject)node.getLookup().lookup(DataObject.class);

                if (dataObject != null) {
                    FileObject fileObject = dataObject.getPrimaryFile();
                    File file = FileUtil.toFile(fileObject);

                    if (fileFilter.accept(file)) {
                        result.add(node);
                      }
                  }
              }

            return result.toArray(new Node[0]);
          }
      }

    public FileFilteredNode (Node original, FileFilter fileFilter) {
        super(original, new FileFilteredChildren(original, fileFilter));
        this.fileFilter = fileFilter;
      }
  }

Note that if you're showing the filtered nodes in a tree view according to the code above, you might find expansion handles on leaf nodes. This thread from the dev@openide list discusses some solutions to this problem.

How do I preserve the column attributes of a TreeTableView?

Assuming you are embedding a TreeTableView (TTV) inside a TopComponent, you can override the readExternal(ObjectInput) and writeExternal(ObjectOutput) methods for preserving the attributes of the columns in your TTV (e.g. the column ordering, sorted-ness, sorting order, visibility, and width).

Start by keeping a reference to the Node.Property array used to define the columns of the TTV, since there is no way to get those properties from the TTV (i.e. there is no getProperties() method). The examples below will refer to this Node.Property array as "columns".

In order to get and set the column widths of the tree-table, we need to subclass TreeTableView and provide a getTable() method that returns the treeTable protected field of the TreeTableView class. In the examples below, this reference will be referred to as treeTable for brevity.

First let us save the column attributes to the serialized TopComponent via the writeExternal() method.

    public void writeExternal(ObjectOutput out) throws IOException {
        super.writeExternal(out);
        out.writeInt(columns.length);
        for (int ii = 0; ii < columns.length; ii++) {
            Boolean b = (Boolean) columns[Ii].getValue("InvisibleInTreeTableView");
            if (b == null) {
                b = Boolean.FALSE;
            }
            out.writeBoolean(b.booleanValue());
            Integer i = (Integer) columns[Ii].getValue("OrderNumberTTV");
            if (i == null) {
                i = new Integer(ii);
            }
            out.writeInt(i.intValue());
            b = (Boolean) columns[Ii].getValue("SortingColumnTTV");
            if (b == null) {
                b = Boolean.FALSE;
            }
            out.writeBoolean(b.booleanValue());
            b = (Boolean) columns[Ii].getValue("DescendingOrderTTV");
            if (b == null) {
                b = Boolean.FALSE;
            }
            out.writeBoolean(b.booleanValue());
        }
        try {
            TableColumnModel tcm = treeTable.getColumnModel();
            int count = tcm.getColumnCount();
            for (int index = 0; index < count; index++) {
                TableColumn tc = tcm.getColumn(index);
                out.writeInt(tc.getWidth());
            }
        } catch (IOException ioe) {
            ErrorManager.getDefault().notify(ErrorManager.WARNING, ioe);
        }
    }

Next, we see how to deserialize the column attributes.

    public void readExternal(ObjectInput in)
            throws IOException, ClassNotFoundException {
        super.readExternal(in);
        try {
            int count = in.readInt();
            for (int ii = 0; ii < count; ii++) {
                boolean b = in.readBoolean();
                columns[Ii].setValue("InvisibleInTreeTableView", Boolean.valueOf(b));
                int i = in.readInt();
                columns[Ii].setValue("OrderNumberTTV", Integer.valueOf(i));
                b = in.readBoolean();
                columns[Ii].setValue("SortingColumnTTV", Boolean.valueOf(b));
                b = in.readBoolean();
                columns[Ii].setValue("DescendingOrderTTV", Boolean.valueOf(b));
            }
        } catch (Exception e) {
            // Could be reading an old instance which is missing data.
            // In any case, ignore this as there is no use in reporting it.
        }
        nodeView.setProperties(columns);

        // Read the column widths from the stream immediately and save them
        // to a final array for the Runnable below to access them.
        TableColumnModel tcm = treeTable.getColumnModel();
        int count = tcm.getColumnCount();
        final int[[ | ]] widths = new int[Count];
        try {
            for (int index = 0; index < count; index++) {
                widths[Index] = in.readInt();
            }
        } catch (IOException ioe) {
            // Could be reading an old instance which is missing data.
            // In any case, ignore this as there is no use in reporting it
            // (and return immediately so as not to invoke the runnable).
            return;
        }

        // Changing Swing widgets must be done on the AWT event thread.
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                // TreeTableView prohibits moving the tree
                // column, so it is always offset zero.
                setTreePreferredWidth(widths[0]);
                for (int index = 1; index < widths.length; index++) {
                    setTableColumnPreferredWidth(index - 1, widths[Index]);
                }
            }
        });
    }

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

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

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

How can I make sortable columns in a TreeTableView?

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

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

How can I add a "View" capability for data my node represents?

Let's say that you've added support for a new file type in your application. You want to be able to provide an action by which users can "view" the file, which might open it up in the source editor (for text-based files) or a custom editor you've created in Swing. How can you add this view action?

It turns out that there are a few ways:

  1. Create a ViewCookie for your node and in display the contents in the cookie's view() method.
  2. Create a subclass of NodeAction and displays the node's contents in its performAction() method.
  3. Create a subclass of Node.Cookie that my node should return in its lookup and then create a CookieAction that acts upon this.

The first approach (ViewCookie) is the simplest of the three, though it can really only operate on a single node. If you just need something quick and easy, then it is probably your best bet.

The second approach (NodeAction) will work but is discouraged since someone creating a FilterNode on your node might inadvertently disable your action.

The third approach (Node.Cookie/CookieAction) is the most difficult of the three but also the most versatile. Your CookieAction can be enabled for multiple classes and can also operate on several nodes at once.

See also:

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

Applications which manage sets of data items often offer to users the capability of selecting and deselecting all the items currently on the screen with a single menu (or key shortcut). In some cases even a "Invert selection" option could be useful which selects all unselected nodes an vice versa.

Implementing such a feature with the OpenIDE API is quite a simple task. We first define a subclass of SystemAction which listens for changes in the selection of the current TopComponent and tracks the currently active ExplorerManager:

public abstract class ExplorerManagerAction extends SystemAction
  {
    private ExplorerManager activeExplorerManager;

    public ExplorerManagerAction()
      {
        TopComponent.getRegistry().addPropertyChangeListener(new PropertyChangeListener()
          {
            public void propertyChange (PropertyChangeEvent event)
              {
                if (TopComponent.Registry.PROP_ACTIVATED.equals(event.getPropertyName()))
                  {
                    Object value = event.getNewValue();

                    if (value instanceof ExplorerManager.Provider)
                      {
                        activeExplorerManager = ((ExplorerManager.Provider)value).getExplorerManager();
                        setEnabled(true);
                      }

                    else
                      {
                        activeExplorerManager = null;
                        setEnabled(false);
                      }
                  }
              }
          });
      }

    final public void actionPerformed (ActionEvent actionEvent)
      {
        if (activeExplorerManager != null)
          {
            try
              {
                performAction(activeExplorerManager);
              }
            catch (PropertyVetoException e)
              {
                // ...
              }
          }
      }

    abstract protected void performAction (ExplorerManager explorerManager)
      throws PropertyVetoException;

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

    protected void initialize()
      {
        super.initialize();
        putValue("noIconInMenu", Boolean.TRUE);
      }

    protected boolean asynchronous()
      {
        return false;
      }
  }

Now in order to implement the specific node selection actions we just have to subclass and provide a concrete implementation of the performAction() method which takes an ExplorerManager as parameter.

For the "Select All" action we have:

public final class SelectAllAction extends ExplorerManagerAction
  {
    protected void performAction (ExplorerManager explorerManager)
      throws PropertyVetoException
      {
        explorerManager.setSelectedNodes(explorerManager.getRootContext().getChildren().getNodes());
      }
    public String getName()
      {
        return NbBundle.getMessage(SelectAllAction.class, "CTL_SelectAllAction");
      }
  }

For the "Deselect all" action we have:

public final class DeselectAllAction extends ExplorerManagerAction
  {
    protected void performAction (ExplorerManager explorerManager)
      throws PropertyVetoException
      {
        explorerManager.setSelectedNodes(new Node[0]);
      }
    public String getName()
      {
        return NbBundle.getMessage(DeselectAllAction.class, "CTL_DeselectAllAction");
      }

At last for the "Invert selection" action we have:

public final class InvertSelectionAction  extends ExplorerManagerAction
  {
    protected void performAction (ExplorerManager explorerManager)
      throws PropertyVetoException
      {
        List nodes = new ArrayList(Arrays.asList(explorerManager.getRootContext().getChildren().getNodes()));
        nodes.removeAll(Arrays.asList(explorerManager.getSelectedNodes()));
        explorerManager.setSelectedNodes((Node[[ | ]])nodes.toArray(new Node[0]));
      }
    public String getName()
      {
        return NbBundle.getMessage(InvertSelectionAction.class, "CTL_InvertSelectionAction");
      }
  }

The above code for "Select All" and "Invert selection" only works for "flat" node structures with a root and a single level of children. For more complex structures we just need to replace explorerManager.getRootContext().getChildren().getNodes() with a piece of code that recursively explores the node tree contents.

To complete our work, this is the XML code to put in the layer.xml in order to add actions in the menu, the toolbar and to define the proper key bindings:

<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd">
<filesystem>
    <!-- Declares the relevant actions. -->
    <folder name="Actions">
        <folder name="Select">
            <file name="my-package-action-SelectAllAction.instance"/>
            <file name="my-package-action-DeselectAllAction.instance"/>
            <file name="my-package-action-InvertSelectionAction.instance"/>
        </folder>
    </folder>
    <!-- Adds the actions to the Select main menu. -->
    <folder name="Menu">
        <folder name="Select">
            <file name="my-package-action-SelectAllAction.shadow">
                <attr name="originalFile" stringvalue="Actions/Select/my-package-action-SelectAllAction.instance"/>
            </file>
            <attr name="my-package-action-SelectAllAction.shadow/my-package-action-DeselectAllAction.shadow" boolvalue="true"/>
            <file name="my-package-action-DeselectAllAction.shadow">
                <attr name="originalFile" stringvalue="Actions/Select/my-package-action-DeselectAllAction.instance"/>
            </file>
            <attr name="my-package-action-DeselectAllAction.shadow/my-package-action-InvertSelectionAction.shadow" boolvalue="true"/>
            <file name="my-package-action-InvertSelectionAction.shadow">
                <attr name="originalFile" stringvalue="Actions/Select/my-package-action-InvertSelectionAction.instance"/>
            </file>
            <attr name="my-package-action-InvertSelectionAction.instance/it-tidalwave-bluemarine-catalog-tagstamper-action-separatorBefore.instance" boolvalue="true"/>
        </folder>
    </folder>
    <!-- Declares the shortcuts. D- maps to "command" on Mac OS X and to "ctrl" on Linux and Windows. -->
    <folder name="Shortcuts">
        <file name="D-A.shadow">
            <attr name="originalFile" stringvalue="Actions/Select/my-package-action-SelectAllAction.instance"/>
        </file>
        <file name="D-D.shadow">
            <attr name="originalFile" stringvalue="Actions/Select/my-package-action-DeselectAllAction.instance"/>
        </file>
        <file name="D-I.shadow">
            <attr name="originalFile" stringvalue="Actions/Select/my-package-action-InvertSelectionAction.instance"/>
        </file>
    </folder>
    <!-- Adds the actions to the Select toolbar -->
    <folder name="Toolbars">
        <folder name="Select">
            <file name="my-package-action-InvertSelectionAction.shadow">
                <attr name="originalFile" stringvalue="Actions/Select/my-package-action-InvertSelectionAction.instance"/>
            </file>
            <attr name="my-package-action-InvertSelectionAction.shadow/my-package-action-DeselectAllAction.shadow" boolvalue="true"/>
            <file name="my-package-action-DeselectAllAction.shadow">
                <attr name="originalFile" stringvalue="Actions/Select/my-package-action-DeselectAllAction.instance"/>
            </file>
            <attr name="my-package-action-DeselectAllAction.shadow/my-package-action-SelectAllAction.shadow" boolvalue="true"/>
            <file name="my-package-action-SelectAllAction.shadow">
                <attr name="originalFile" stringvalue="Actions/Select/my-package-action-SelectAllAction.instance"/>
            </file>
        </folder>
    </folder>
</filesystem>

-- Main.fabriziogiudici - 06 Jul 2006

PENDING: Review/cleanup

Why do my nodes in the Explorer always have an expand-box by them, even though they have no children?

Nodes are not asked for their child nodes until the user tries to expand them - to do otherwise would be very bad for performance. If your Node is not supposed to have child nodes, use Children.LEAF as the children object passed to the constructor. That will eliminate the expand handle.

How can I prevent (or override) the node deletion dialog?

By default, you will be prompted to confirm your intention whenever you try to delete a node from within an explorer manager view (for example, the projects tab). You can prevent this dialog from being shown, which is handy if the node is not important enough to warrant confirmation or if you want to instead show your own confirmation.

To do this, call setValue("customDelete", Boolean.TRUE) on the node on which you want to suppress confirmation. This can be done at any time before the destroy() method is invoked.

The above will suffice if you just want to suppress the aforementioned dialog which is sufficient for most customization cases. But if you need total control over node deletion, you can implement the ExtendedDelete interface.

How can I change my node's appearance?

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

    private Movie movie;

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

    @Override
    public String getHtmlDisplayName() {
        return "<b>" + this.getDisplayName() + "</b>";
    }
    
}
The javadoc for the HtmlRenderer class explains what subset of HTML is supported. You can also change the icon's node by overriding various methods such as
getIcon(int type)
or {getOpenedIcon()}. It's also possible, but far more difficult, to control other aspects of the node's appearance; for example, drawing a box around the node or changing its background color. To do this you must create or modify the explorer view in which the node is rendered. Fabrizio Giudici posted code that illustrates this on the
dev@openide
list.

How do I handle cut, copy and paste?

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

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

How can I graphically create a ChoiceView?

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

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


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

Finally switch to the "Source" view and fix the import errors. --Tboudreau 02:40, 24 January 2010 (UTC)

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

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

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

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

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


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

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

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

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

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

Threading

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

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

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

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

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

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

I need to run some code on a background thread. Can the platform help me?

First, ask yourself why you need to do this and if it is really necessary. Generally there is only one reason: You are doing something takes some time (file I/O, computing something large and complicated, talking to a network socket) that will block the UI.

NetBeans contains a thread pool org.openide.util.RequestProcessor. (You can use the thread pools that exist today in java.util.concurrent but it is more typical to use RequestProcessor.) There is a general purpose built-in thread pool - RequestProcessor.getDefault(). You can use that for things that only happen once in a while; otherwise you are probably better off creating your own instance of RequestProcessor. There is a FAQ item about how to know when to do which. In its most simple usage, RequestProcessor.post() is called with a Runnable. The call returns a RequestProcessor.Task which you can use to monitor the status of the task and listen to task finish among other.

Note that if you are doing something in the background, you may want to use the Progress API to show a progress indicator in the status-bar (or use it to put up a modal progress dialog if the UI really needs to be blocked - use with care, only when really necessary).

Remember that if you are running more threads than you have processors (or cores) - and your OS is probably using some as well - then when you ask to multi-thread, you are asking your CPU to divide the time of the CPUs you have between more virtual threads. And switching the context a CPU is working in - sending it off to some other memory space and set of instructions, and then another - takes time. So heavy use of multi-threading, especially on single CPU machines, can slow things down rather than speed them up. If you can make your code run faster, do that first.

When should I use RequestProcessor.getDefault() and when should I create my own RequestProcessor?

RequestProcessor.getDefault() is tempting to use, but it is also dangerous. This FAQ item will tell you when not to use it.

RequestProcessor has a constructor argument for its throughput. That says how many threads this RequestProcessor is allowed to use at the same time. When you call new RequestProcessor("Useful name for thread dump", 3) you are creating a thread pool that can have 3 threads available to run things on simultaneously.

The throughput of RequestProcessor.getDefault() is Integer.MAX_VALUE. Think about what that means: it can potentially create thousands of threads; but your OS cannot necessarily handle thousands of threads, and you probably don't have thousands of CPUs. Which means the OS does extra work time-slicing between the threads and things get slower, not faster.

RequestProcessor.getDefault() is useful for one-off operations - you have some situation that happens once in a great while, and, say, while constructing some object, you need to do some work in the background; that work will probably never need to be done again for the life of the Java VM. That's a perfect case for RequestProcessor.getDefault().

Now here is the anti-example: You are creating a Node that represents a file. It needs to mark itself with an error badge and color its text in red if the file contains errors. You can't read the file when you create the Node - that takes to long. So when the node is created, it runs a background task to check its status, and updates its icon and display name after it has read the file. Now imagine you did this with RequestProcessor.getDefault(). What happens when the user expands a folder that contains 1000 of your files? 1000 threads get created, and the whole application gets very, very slow. For that, you are much better off creating one new RequestProcessor and using it for all your nodes. The FAQ entry about RequestProcessor.Task shows how to do this correctly.

If you create your own RequestProcessor, please always use a name. If you get a deadlock it makes debugging much easier.

What APIs come with built-in background thread handling

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

Specifically they are

How can I run an operation occasionally on a background thread, but reschedule it if something happens to delay it?

There are a lot of reasons you might want to reschedule a background operation. For example, you want to re-parse a file 3 seconds after the user stops typing, so you can show errors. But at 2 seconds she starts typing again. You don't want that task to run a second from now anymore. You can either cancel the task, or even simpler, call task.schedule(3000) every time a key is pressed. If it was already scheduled, it will be rescheduled for 3 seconds from now again.

Or imagine you have the situation described in the FAQ about RequestProcessor.getDefault() - a node for a file needs to read the file after it is created to mark itself if the file has errors. RequestProcessor.Task makes this sort of thing easy.

public class FooDataNode extends DataNode implements PropertyChangeListener, Runnable {
  private boolean error;
  private static final RequestProcessor THREAD_POOL = new RequestProcessor("FooDataNode processor", 1);
  private final RequestProcessor.Task task = THREAD_POOL.create(this);

  FooDataNode(FooDataObject obj) {
    super(obj, Children.LEAF);
    obj.addPropertyChangeListener(WeakListeners.propertyChange(this, obj));
    task.schedule(100);
  }

  public void propertyChange(PropertyChangeEvent evt) {
    DataObject obj = (DataObject) evt.getSource();
    if (DataObject.PROP_MODIFIED.equals(evt.getPropertyName()) && !obj.isModified()) { //file was saved
      task.schedule(100);
    }
  }

  @Override
  public String getHtmlDisplayName() {
    return error ? "<font color=\"!nb.errorForeground\">" + getDisplayName() : null;
  }

  public void run() {
    boolean old = error;
    error = doesTheFileHaveErrors();
    if (old != error) {
      fireDisplayNameChange(null, null);
    }
  }

  private boolean doesTheFileHaveErrors() {
    assert !EventQueue.isDispatchThread();
    //parse the file here
    return true; //whatever the value should be
  }
}

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 to install their components is the declarative XML Window System API, 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.

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

How can I change the executable's icon?

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

'Application Icon' Images

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

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

Windows Icons

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

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

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

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

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

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

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

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

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

Mac Icons

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

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

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

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

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

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

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

The "New Window Component" wizard in the NetBeans IDE generates a singleton TopComponent. That's fine for some uses, but often you will want to create multiple instances of your TopComponent.

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

In your TopComponent's .java source file:

Next, open the settings file that the wizard generated for your TopComponent. This is typically named something like FooTopComponentSettings.xml. Locate the instance XML element (NOT one of the instanceof elements and remove method="getDefault" from the end of that line.

Finally, you will need to change any code, such as from the action which opens the TopComponent, which called the getDefault() method. It should now simply create a new instance of your TopComponent instead.

NOTE: These instructions should apply to NetBeans 5.0 through 6.5. You may need to adapt them slightly for newer versions.

Netbeans 6.8

This modified recipe seems to work in 6.8:

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

<math>Insert formula here</math>

Wizards and Templates

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

For example, say you want to make a template which will appear in File | New File which will prompt the user for a name and location but then actually create several related files.

Just use an arbitrary empty file as the template, and declare it to have an instantiatingWizardURL attribute with an instance of WizardDescriptor.InstantiatingIterator. The wizard iterator can specify any sequence of Swing panels you like to ask the user whatever questions you like, and at the end it can do whatever you like to create the new files. Return the created files in instantiate().

Here is an example of a wizard that creates a number of files. This is the layer file that declares it (look at emptyLibraryDescriptor).

You may wish to reuse a standard GUI panel for picking a folder and name, as in Templates.createSimpleTargetChooser.

The NetBeans 5.0 module development support has a (meta-)wizard New Wizard. Choose New File for Registration Type and follow the wizard steps.


Applies to: NetBeans 5.0, 5.5, 6.X

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

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

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

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

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

How do I show that a user has filled an invalid input into my wizard?

A: Set the WizardPanel_errorMessage property in the WizardPanel instance that is related to the displayed panel.

Example:

wizardDescriptor.putProperty("WizardPanel_errorMessage", NbBundle.getMessage(MyPanel1.class, "key"));

Note: Since WizardDescritor, spec.version 7.8 (i.e.since NetBeans 6.5 Platform)

You can obtain the instance of WizardDescriptor in the WizardDescriptor.Panel.readSettings as settings parameter method.

Update in NetBeans 6.8

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

Output Window

How do I create my own tab in the output window and write to it?

NetBeans contains classes that make writing to the output window very simple - you don't have to worry about components, you just get an instance of a thing called InputOutput, which has methods getOut() and getErr() that return OutputStreams. There is a utility class, IOProvider that can supply InputOutput objects - you pass it a string name that should be shown on the output tab, and a boolean (whether or not it should reuse an existing tab with the same name if there is one). So, hello world code for the output window looks like this:

InputOutput io = IOProvider.getDefault().getIO ("Hello", true);
io.getOut().println ("Hello from standard out");
io.getErr().println ("Hello from standard err");  //this text should appear in red
io.getOut().close();
io.getErr().close();

It is important to close the output streams when you are done with them - output is written to a memory mapped file, which cannot be deleted if the stream is still open - and the tab title will remain boldfaced until the streams are closed, which helps indicate to the user that the process has finished.

-- Main.timboudreau - 10 Jun 2006

Note: For platform based applications to correctly use InputOutput and IOProvider an Output Window implementation must be available and enabled. Follow the below steps to be sure you include everything to allow the output window and tabs to be used and shown.

  1. Open your module projects properties. (Right click the project and select properties).
  2. Select libraries
  3. Check to see if 'I/O APIs' is in the dependency list.
  4. If it is not it needs to be added.

To add 'I/O APIs'

  1. Choose 'Add' from 'Module Dependencies'
  2. Select 'I/O APIs' from the list
  3. Press OK

To force 'Output Window' (the implementation of the tabbed output window) to be enabled,

  1. Choose 'Add' from 'Required Tokens'
  2. Pick =org.openide.windows.IOProvider=
  3. Press OK

Note: this shall not be necessary in the current 6.0 trunk version..

Relevent to 6.0: If the dependencies do not show up in the selection list check the 'Module Suite' to make sure they have not been excluded from the platform.

  1. Right click on the module suite
  2. Click Properties
  3. Go to Libraries
  4. Locate the platform 'Clusters and Modules'
  5. Make sure I/O API is checked
  6. Make sure Output Window is checked
  7. Click OK

Hint: It is sometimes helpful to call InputOutput.select() to make sure the tab is made visible in the output window.

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

How to implement custom IOProvider?

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

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

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

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

    public OutputWriter getStdOut() {
        // implement
    }

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

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

    @Override
    public String getName() {
        return NAME;
    }
}

Add "OpenIDE-Module-Provides: org.openide.windows.IOProvider" to your module manifest (manifest.mf file) to inform that your module provides IOProvider service. Then instance of your provider could be obtained by IOProvider.get("My IO provider")

Applies to: NetBeans 6.7 or higher

How do I embed output window tab to another component?

You have to create IOContainer which provides access (for IOProvider) to your component where you want to embed OW tab (IO tab). Then you need to pass IOContainer instance to IOProvider.getIO(String name, Action[[ | ]] actions, IOContainer ioContainer). IOContainer is created by IOContainer.create(IOContainer.Provider). The following code demonstrates how to add OW to custom TopComponent.:

    IOContainer ioc = IOContainer.create(new IOC());
    InputOutput io = IOProvider.getDefault().getIO("test", new Action[0], ioc);
    io.getOut().println("Hi there");
    io.select();

    // implement IOContainer.Provider in TopComponent where OW tab will be added
    class IOC extends TopComponent implements IOContainer.Provider {
        JComponent ioComp;
        CallBacks ioCb;

        public IOC() {
            setLayout(new BorderLayout());
            setDisplayName("Test");
        }

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

        public void add(JComponent comp, CallBacks cb) {
            if (ioComp != null) {
                remove(ioComp);
                if (ioCb != null) {
                    ioCb.closed();
                }
            }
            ioComp = comp;
            ioCb = cb;
            add(comp);
            validate();
        }

        public JComponent getSelected() {
            return ioComp;
        }

        boolean activated;
        public boolean isActivated() {
            return activated;
        }

        @Override
        protected void componentActivated() {
            super.componentActivated();
            activated = true;
            if (ioCb != null) {
                ioCb.activated();
            }
        }

        @Override
        protected void componentDeactivated() {
            super.componentDeactivated();
            activated = false;
            if (ioCb != null) {
                ioCb.deactivated();
            }
        }

        public boolean isCloseable(JComponent comp) {
            return false;
        }

        public void remove(JComponent comp) {
            if (comp == ioComp) {
                ioComp = null;
                ioCb = null;
            }
        }

        public void select(JComponent comp) {
        }

        public void setIcon(JComponent comp, Icon icon) {
        }

        public void setTitle(JComponent comp, String name) {
        }

        public void setToolTipText(JComponent comp, String text) {
        }

        public void setToolbarActions(JComponent comp, Action[] toolbarActions) {
        }
    }

Applies to: NetBeans 6.7

How to use color text in Output Window?

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

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

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

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


public class L implements OutputListener {
...
}

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

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

Writing tests

Using NbModuleSuite & friends

Right API for starting the test inside NetBeans Runtime Container is provided in from 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.

TODO


NOTES

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

NetBeans Developer Test FAQ

Abstract

Contains info how to develop tests for NetBeans plugin.

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

Useful test classes in modules

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

Testing things that use FileObjects

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

See UsingFileSystemsMasterfs for more info on how to fix this.

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

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

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

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

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

Writing Tests for DataObjects and DataLoaders

Quite easy. At least in NetBeans 6.5 and newer. Everything shall work as declarative MIME resolvers are loaded automatically from unit tests and loaders are available from unit tests automatically.

Example code is below:

    private static final String BAD_MANIFEST_CONTENT =
            "Manifest-Version: 1.0\n" +
            "junk junk junk\n" +
            "some more junk\n";
    private static final String GOOD_MANIFEST_CONTENT =
            "Manifest-Version: 1.0\n" +
            "Java-Bean: true\n" +
            "OpenIDE-Module-Name: com.foo.bar\n\n";

    @Test public void checkContent() throws Exception {
        FileSystem fs = FileUtil.createMemoryFileSystem();
        FileObject good = fs.getRoot().createData("good.mf");
        writeFile(GOOD_MANIFEST_CONTENT, good);
        DataObject goodDob = DataObject.find(good);

        FileObject bad = fs.getRoot().createData("bad.mf");
        writeFile(BAD_MANIFEST_CONTENT, bad);
        DataObject badDob = DataObject.find(bad);

        YourInterface y = goodDob.getLookup().lookup(YourInterface.class);
        y.doYourTest();
    }

    private void writeFile(String content, FileObject file) throws Exception {
        OutputStream os = file.getOutputStream();
        os.write(content.getBytes("UTF-8"));
        os.close();
    }

In the somewhat unusual case in which your unit test resides in a different module from that which contains your file support code (DataLoader, DataObject, etc.), you will need to add a <test /> dependency on the module which contains the file support code. Currently this can only be done by editing the project.xml file for the module containing your unit tests. See the build harness' README for more information; you can find the relevant section by searching for test-dependencies in that file.


Older versions than 6.5

If you are writing a test for a DataObject, you need to set up enough of the DataLoader infrastructure that DataObject.find() will locate your DataLoader and call it to create your DataObject subtype.

First, use the setup code described in Testing Things That Use File Objects. Add to the test's setUp() method a call to FileUtil.setMIMEType() to manually assign the file extension to the MIME type of your DataLoader.

FileUtil.setMIMEType("mf", "text/x-manifest");

(setMIMEType() is deprecated with respect to usage from inside a module, but it is fine to use it in a unit test).

(For XML file subtypes, FileUtil.setMIMEType() on *.xml is not likely to work. You can instead register a MIMEResolver in default lookup which does whatever you need.)


Second, you need to make sure your DataLoader is registered in the default Lookup so that DataObject.find() will find it. In 6.0, the New File Type template will set this up automatically by creating the correct file in test/unit/META-INF/services. (Or you can get better control by using org.openide.util.test.MockLookup.)

How do I test something which uses the System Filesystem?

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

In case you see difference from expected behavior:

Authentication and Authorization in Platform Apps

Other strategies for authentication and authorization

There are cases in which you want to exercise great control over who is allowed to use your application. You might, for example, be required to check the user's network credentials, validate client-side certificate or check a license server before the platform application is even launched.

A platform application is typically started from an executable launcher (Windows) or shell script (Unix). This invokes the org.netbeans.core.startup.Main.main method. However, as described in the Module System documentation, you can use the netbeans.mainclass system property to specify a different class to run at startup.

This main class must be present in the startup classpath (you can put it alongside core.jar in platform8/core or similar) and must have a main method. The main method can then invoke whatever authorization logic you like. If it fails, you'll probably want to show a dialog to the user and call System.exit. If it passes, you can then simply invoke org.netbeans.core.startup.Main.main yourself to continue the normal NetBeans startup procedure.

If you simply want to enable a single module based on some criteria (for example, the existence of a license file), you can use ModuleInstall.validate().

Custom Project Types

Why don't previously opened editors return when I re-open my project?

If you edit a file within some type of project offered by the NetBeans IDE, such as a Java project, you will find that closing and then re-opening the project will restore the editor windows that previously had been open. However, if this sequence does not hold true for a custom project type you've implemented, you should verify that your project's Lookup contains an AuxiliaryConfiguration instance.

The org.netbeans.spi.project.AuxiliaryConfiguration interface defines just a few methods, but you might look at Mevenide M2AuxilaryConfigImpl for an idea of how you could implement it.

Deploying Changes through AutoUpdate and using Autoupdate API

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

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

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

1. Deciding where you will host it.

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

2. Creating your NBM files and autoupdate XML descriptor.

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

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

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

4. Making sure your application knows about it.

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

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

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

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

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

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

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

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

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

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

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

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

To customize appearance of balloon-like tooltip (since NB6.5)

The balloon-like tooltip notifies user when available updates of IDE's installed plugins. If you would like to suppress it, just run IDE with a option -J-Dplugin.manager.allow.showing.balloon=false. Otherwise, if you would like to force showing balloon in every case then run IDE with the option -J-Dplugin.manager.allow.showing.balloon=true

To customize amount time of showing the balloon (since NB6.5)

As was written above, the balloon-like tooltip notifies user when available updates. Once Plugin Manager invokes the balloon, it's showing for 30 seconds as default.If you would like to make the timeout smaller use a option -J-Dplugin.manager.showing.balloon.timeout to specify the timeout in milliseconds. Have in mind a particular value 0 to make the timeout unlimited.


Applies to: NetBeans 6.0 or newer

Platforms: All

Do not hesitate to contact me on jrechtacek@netbeans.org if you have any question. [image - see online version]

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

To customize appearance of balloon-like tooltip (since NB6.5)

The balloon-like tooltip notifies user when available updates of IDE's installed plugins. If you would like to suppress it, just run IDE with a option -J-Dplugin.manager.allow.showing.balloon=false. Otherwise, if you would like to force showing balloon in every case then run IDE with the option -J-Dplugin.manager.allow.showing.balloon=true

To customize amount time of showing the balloon (since NB6.5)

As was written above, the balloon-like tooltip notifies user when available updates. Once Plugin Manager invokes the balloon, it's showing for 30 seconds as default.If you would like to make the timeout smaller use a option -J-Dplugin.manager.showing.balloon.timeout to specify the timeout in milliseconds. Have in mind a particular value 0 to make the timeout unlimited.


Applies to: NetBeans 6.0 or newer

Platforms: All

Do not hesitate to contact me on jrechtacek@netbeans.org if you have any question. [image - see online version]

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
 %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 to install components using its custom installers?

As you know Autoupdate Services primary handles NetBeans plugins based on NBM packaging. In addition, Autoupdate Services offers a possibility to install/uninstall components which are not usually in NBM format. This possibility has been designed to support such use-cases to allow install Application Serves like GlassFish into NetBeans IDE. This way should enable to use native installers for handling such components.

To enable such possibility, Autoupdate Services API are bringing:

How to setup a Update Provider providing custom components?

Use interface UpdateProvider and make a provider for such components. 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 matching these components. It has to return a 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. Look on them in detail, both are using SPI UpdateItem.create(Installed)NativeComponent

Ad UpdateItem matching available component firstly - the provider has to describe name, display name, download size and so on. But the most important things are CustomInstaller and CustomUninstaller vice versa. It could look like:

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

For installed component

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

How could look a custom installer like? It it quite simple, look on

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

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

Using META-INF/services. More info in Geertjan's blog: http://blogs.sun.com/geertjan/entry/meta_inf_services_vs_layer

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

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

A sample project having this UpdateProvider
Important Note

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



Applies to: NetBeans 6.5 or newer

Platforms: All

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

When things go wrong: Troubleshooting

I've got a class not found error/exception. How can I fix it?

The most likely explanation is that you have a problem in your dependencies. In order for a class in one module to reference a class/interface defined in another module, the following must be true:

  1. The class/interface being referenced must be visible to the code using it, according to the normal Java visibility rules. This typically means that the class must be public, since package-private access across modules is impossible.
  2. The package containing the class/interface must be exported (marked as providing an API visible to other modules). To "export" package, right click project, select Properties -> API Versioning and choose either public or friend export type.
  3. The module containing the code which uses this class/interface must declare a dependency on the module which provides it.

These rules are pretty straightforward and it is easy in most cases to verify that dependencies are set up correctly. If you receive a ClassNotFoundException or NoClassDefFoundError at runtime, the stack trace will generally lead you to the problem.

However, there are some cases where you will receive a ClassNotFoundException or NoClassDefFoundError at runtime, but finding which modules need to declare dependencies on one another is more difficult because the stacktrace does not directly identify the code involved. This occurs most frequently when you have library modules (composed of JAR files which were compiled outside of the platform). Although the dependencies were satisfied (by setting the classpath as needed) when the libraries were compiled, the developer may not have correctly set these dependencies in the platform application which uses them.

In this case, you can often locate the problem by rebuilding the suite and paying close attention to the output generated by the verify-class-linkage task. For example:

verify-class-linkage: Warning: a.SomeImplementation cannot access b.publicapi.SomeInterface

This tells us that the module which provides SomeImplementation needs to declare a dependency on the module which provides SomeInterface.

For more background, see Issue 145503.

I find files missing from the source ZIP file

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

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

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

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

External FAQ Entries

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