How to use certain NetBeans APIs

This page contains extracted usecases for some of the NetBeans modules that offer an API.

How to use Ant?

The Ant integration module recognizes Ant build scripts, facilitates editing them as text or structurally, lets the user run targets or create shortcuts to them, etc.

The principal use cases for the API are covered in the overall API architecture.


How to use Common Annotations?

Provides common annotations serving as a documentation element and for static code analysis.

CheckReturnValue annotated method

When the method return value is important value to check (or the only effect the method has) the method can be annotated with CheckReturnValue. Annotation servers as documentation as well as a hint for static code analysis.

CheckForNull annotated method

Method annotated with CheckForNull may return null value. Annotation servers as documentation as well as a hint for static code analysis.

NonNull annotated element

When the field, parameter, local variable or return value of the method must not be null the NonNull annotation can be used to clearly express this. It servers as documentation as well as a hint for static code analysis.

NullAllowed annotated element

Field, parameter or local variable annotated with NullAllowed can contain null value so null check should occur before any dereference. Annotation servers as documentation as well as a hint for static code analysis.

NullUnknown annotated element

Annotation NullUnknown complementing other nullness annotations servers for cases where the element may or may not be null under certain defined circumstances (usage).

SuppressWarnings annotated element

When the analysis tool report false warning it is possible to use SuppressWarning annotation to suppress the warning.


How to use Debugger Core API?

The debuggercore/api module (Debugger Core API) allows to install different debugger implementation to one IDE. It allows to share some common UI components.

UseCase I. - Install and use CPP debugger plug-in to NetBeans + Java Debugger.

CPP debugger plug-in installs support for debugging of some new language to the NetBeans IDE, and some new debugging engine. This implementation of debugger should share UI components (actions, Debugger Views, ...) with default NB Java Debugger. It should share basic debugger model too - notion of current context, current session, thread, call stack line, ...

CPP debugger plug-in installs:

UseCase II. - Install and use JSP debugger plug-in to NetBeans + Java Debugger.

JSP debugger plug-in installs support for debugging of some new language to the NetBeans Java Debugger. It does not contain a new debugger engine, but it delegates to standard NB Java debugger. So it does not depends on Debugger Core API only, but it depends on JavaDebugger API too.

JSP debugger plug-in installs:

UseCase III. - Install and use J2EE debugger plug-in to NetBeans + Java Debugger.

J2EE debugger plug-in installs some enhancements to the standard Java Debugger. It does not contain a new debugger engine or language support. So it does not depends on Debugger Core API only, but it depends on JavaDebugger API too.

J2EE debugger plug-in installs:

UseCase IV. - Install and use DBX debugger plug-in to NetBeans.

DBX debugger plug-in installs support for debugging of some new language (CPP) to the NetBeans IDE, and some new debugging engine. But it contains debugger engine for Java debugging too. DBX debugger engine has its own session management (or will have in the next versions). One debugger engine can manage more than one sessions. One engine supports debugging in more than one language.

UseCase V. - Implement Debugger Core UI module on top of Debugger Core API / SPI.

Debugger Core UI needs:


How to use JPDA Debugger API?

The debuggerjpda/api (Debugger JPDA API) defines API for NetBeans Java Debugger.

UseCase I. - Install and use CPP debugger plug-in to NetBeans + Java Debugger.

CPP debugger plug-in installs support for debugging of some new language to the NetBeans IDE, and some new debugging engine. This implementation of debugger should share UI components (actions, Debugger Views, ...) with default NB Java Debugger. It should share basic debugger model too - notion of current context, current session, thread, call stack line, ...

CPP debugger plug-in installs:

UseCase II. - Install and use JSP debugger plug-in to NetBeans + Java Debugger.

JSP debugger plug-in installs support for debugging of some new language to the NetBeans Java Debugger. It does not contain a new debugger engine, but it delegates to standard NB Java debugger. So it does not depends on Debugger Core API only, but it depends on JavaDebugger API too.

JSP debugger plug-in installs:

UseCase III. - Install and use J2EE debugger plug-in to NetBeans + Java Debugger.

J2EE debugger plug-in installs some enhancements to the standard Java Debugger. It does not contain a new debugger engine or language support. So it does not depends on Debugger Core API only, but it depends on JavaDebugger API too.

J2EE debugger plug-in installs:

UseCase IV. - Install and use DBX debugger plug-in to NetBeans.

DBX debugger plug-in installs support for debugging of some new language (CPP) to the NetBeans IDE, and some new debugging engine. But it contains debugger engine for Java debugging too. DBX debugger engine has its own session management (or will have in the next versions). One debugger engine can manage more than one sessions. One engine supports debugging in more than one language.


How to use HTML UI API?

NetBeans Platform specific bindings over standard HTML for Java API.

Primary purpose of this API is to allow smooth use of HTML based UI in NetBeans Platform. To achieve that it provides specific annotatations like @OpenHTMLRegistration, but otherwise it builds on the same usecases as the HTML for Java API.

Portable HTML based Window

Want to open a live HTML page as a NetBeans window component? Do you want to use Java to control enabled/disabled state of various HTML elements? Then have a look at @OpenHTMLRegistration annotation.

Portable HTML based Dialog

Want to open a modal dialog filled with an HTML page and block until user makes his choice? Then have a look at @HTMLDialog annotation.

Embedding an HTML UI Component

Are you satisfied with your HTML UI as used in windows and dialogs, but you'd like to use it at a different part of the overall NetBeans UI? Then check @HTMLComponent annotation.

How to use Java Support APIs?

Provides java specific queries (javadc, source level) used by other modules like java language infrastructure. More information in the Javadoc.

The API is widely used by all sorts of IDE modules which need to work with Java sources. They can find Javadoc, unit tests, source level, etc. The SPI is intended mainly for Java platform and library providers, and project type providers, to declare all of this information.


How to use Classpath APIs?

Models basic aspects of the metadata surrounding list of source roots, such as the classpath. More information in the Javadoc.

The API is widely used by all sorts of IDE modules which need to work with sources. The SPI is intended mainly for (java) platforms and library providers, and project type providers, to declare all of this information.


How to use Maven API?

XXX no answer for arch-what

Start exploring use-cases related to Maven archetypes at the ArchetypeWizards class.


How to use Progress API?

The progress API is good for tracking progress of long lasting tasks in the IDE.

Basic usage

There are 3 types of progress indication:

The default location of the progress indication is the status bar which aggregates all tasks running in the IDE that show progress. However it's possible to exclude the task from the default location and show the progress in one's custom dialog component. In such a case the same task should not appear in the status line component as well.

It's possible to request cancelling the task from status line progress aggregator if the task allows cancelling.

Progress tasks that get started as a result of explicit user action takes precedence in the status line docked component over tasks that are triggered by the system. (say filesystem refresh for example)

The most common usecase of the API looks like this:

ProgressHandle handle = ProgressHandleFactory.creatHandle("My custom task");
...
// we have 100 workunits
// at this point the task appears in status bar.
handle.start(100);
...
handle.progress(10);
...
handle.progress("half way through", 50);
...
handle.progress(99);
// at this point the task is finished and removed from status bar
// it's not realy necessary to count all the way to the limit, finish can be called earlier.
// however it has to be called at the end of the processing.
handle.finish();

Advanced Usage

In case your usage of the API

then you should consider using the aggregating version of APIs which is similar to the simple APIs but has distinctive differences and additions that allow for more complex scenarios.

It allows to compose the progress bar from 1+ independent sources, all sharing proportional piece of the progress bar. Additionally you can monitor the task's overall progress from one central place and possibly add more contributing sources of the progress during processing.

        // let's have a factory for client code that performs some part of the job to be done..
        Lookup.Result res = Lookup.getDefault().lookup(new LookupTemplate(MyWorkerFactory.class));
        Iterator it = res.allInstances().iterator();
        ProgressContributor[] contribs = new ProgressContributor[res.allInstances().size()];
        int i = 0;
        while (it.hasNext()) {
            MyWorkerFactory prov = (MyWorkerFactory)it.next();
            contribs[i] = AggregateProgressFactory.createProgressContributor("Module X contribution");
            MyWorker worker = prov.createWorker(contribs[i]);
            //... snip ... do something with the worker..
            i = i + 1;
        }
        AggregateProgressHandle handle = AggregateProgressFactory.createHandle("My Task", contribs, null, null);
        // non-cancellable and with out output link.
        
        // calling start() at the time when the actual long running task starts processing
        handle.start("here we go");
        // ...snip...
        // now the individual MyWorker instances log their progress.
        // possibly in other threads too..
        // ... snip...
        // 
        if (myConditionThatSpawnsAnotherContributor()) {
            ProgressContributor cont = AggregateProgressFactory.createProgressContributor("Additional exceptional contribution");
            handle.addContributor(cont);
            // ... snip ...
        }
        
        // the task is finished when all the ProgressContributors finish..

How to use Search API?

This project is good for implementators of nodes to define how files under this node should be searched. For example, if you implement a custom project type, you can define which folders should be searched when the project is in the current search scope. It is also good for people who want to add a custom tab into the "Search in projects" dialog. For example, implementators of platform applications can add form with criteria for searching in a database.

Search History

SearchHistory is synchronising history content through netbeans modules and it saves history to preferences.

There are two separate histories. One for search and another for replace. When you add your propertyListener to SearchHistory - you can listen for changes in histories.

SearchHistory has methods for adding new entries and getting whole history list.

SearchInfo API & SPI

This use-case was formerly covered by module org.openidex.search.

The SearchInfo API+SPI allows other modules to specify whether and how should nodes they define be searched.

The definition is represented by objects extending class SearchInfoDefinition . To customize searching on a custom node, a SearchInfoDefinition object must be added to the node's lookup. In most cases, there is no need to define own class extending the class - one can use factory methods of class SearchInfoDefinitionFactory .

In some cases implementators may need to apply the same set of SearchFilterDefinitions in the whole subtree of a node. If so, it is not needed to put SearchInfoDefinition to all nodes' lookups, but only one instance of SubTreeSearchOptions have to be put into the lookup of the root node.

Defines abstract classes SearchInfoDefinition, SearchFilterDefinition, SubTreeSearchOptions and a factory class SearchInfoDefinitionFactory

Enhance IDE searching features

People that want to enhance IDE searching features (with custom search criteria or specialized algorithms) can add a new tab to the "Search in Projects" dialog.

They need to implement several classes:

Defines abstract classes that need to be implemented when creating custom providers: SearchProvider, SearchProvider.Presenter, SearchResultsDisplayer, SearchComposition and relative classes. Classes usually used by search providers. Contains class SearchInfo, that defines which files should be searched (it can be retrieved from methods in SearchInfoUtils, or UI component controller ScopeController), SearchListener that you should inform about events that happen during searching, and helper classes SearchInfoUtils (getting SearchInfo objects for nodes) and FileNameMatcher (filtering files by file name). Several UI components that can be used in presenters of search providers, and factory method for creating them.

Search in Projects API

This API enables other modules to open Find in Projects dialog with some pre-defined criteria and to start searching programatically.

Contains classes for controlling search, passing search criteria, and some helper classes.

How to use Visual Library API?

The Visual Library 2.0 is the next generation of the original Graph Library 1.0. It is designed for a general visualization with a support for graph-oriented modeling. Its focus is to become a part of the NetBeans platform and unify the visualization (UI and API) used in NetBeans-Platform-based applications. See http://graph.netbeans.org/ web-site for details. See documentation for complete set of use-cases and code-snippets.

See documentation for complete set of use-cases.


How to use Web APIs?

There are multiple IDE modules that need access to definition of web module. On one side there are modules that provide wizards, edititing, debugging etc. for JSPs, web.xml, servlets, and similar. On the other side there are also multiple project types that can contain web modules in them. This API/SPI exists for communication between these two types of modules.

Retrieving the propertis of a web module

The WebModule class, which encapsulates a web module, has methods for retrieving the module's properties:

   FileObject myServlet = ...;
   WebModule wm1 = WebModule.getWebModule (myServlet);
   String version = wm1.getJ2eePlatformVersion ();
   System.out.println ("Servlet is in version:" + version + " web module");
  

Implementing a web module

Most often the web module is implemented inside a project:

   public class MyProjectType implements Project {
     Lookup getLookup () {
       return Lookups.fixed(new Object[] {
         new MyProvider (),
         ...
       }
     }
     private class MyProvider implements WebModuleProvider {
       WebModule findWebModule(FileObject file) {
         if (isMyFile (file)) {
           WebModule wm;
           synchronized (this) {
             wm = cachedWebModule (file);
             if (wm == null) {
               wm = WebModuleFactory.createWebModule (new WebModuleImpl ());
               cache (file, wm);
             }
           }
           return wm;
         }
       }
       boolean isMyFile (FileObject file) {...}
       WebModule cachedWebModule (FileObject file) {...}
       cache (FileObject file, WebModule wm) {...}
     }
     
     private class WebModuleImpl implements WebModuleImplementation {
       ...
     }
   }
  

It is also possible to implement web modules backed by other means than a project by implementing a WebModuleProvider and registering it in the default lookup.

Implementing support for a web framework

Support for web frameworks, such as Struts and JSF, can extend a WebModule with framework-specific features, such as configuration files. An implementor wanting to provide such support implements WebFrameworkProvider and registers it in the j2ee/webtier/framework in the default file system.


How to use Bootstrap?

The NetBeans launcher starts the application. Different launchers are provided for different supported platforms - Unix/Linux, Windows, and others. There are also a handful of classes in the org.netbeans and org.netbeans.core packages which directly support early startup features, such as command-line options.

Invalidating Caches

NetBeans Module system is optimized to eliminate useless I/O operations on start (as a result the embedded OSGi container is fastest on the planet -- with respect to application start up time). This is achieved by caching information known to have been needed in previous starts and using it rather than obtaining it again from the module JAR files.

There are various caches (like all-layers.dat, all-manifests.dat, all-resources.dat, netigso-bundles, etc. ) provided by the module system or by other subsystems of the application. Together, working in orchestration, they eliminate the need to touch the disk (which is very slow operation especially during morning launch). Btw. there is a test which verifies the caching system really works -- it is recommended for each product built on top of NetBeans Platform to copy and adjust it to verify the caches are really used.

Of course, the caches may get out of date, for example when an external tool modifies the installation layout. How can the system detect whether the caches are valid and still be usable? The only way to verify the caches are 100% correct is to regenerate them and compare whether the cached bits are the same. However that would be terribly slow and defeat the whole purpose of using caches.

As such we have the lastModified API. Every cluster (as enumerated by netbeans.dirs and netbeans.home properties) is supposed to contain such file. Whenever an external tool changes something inside some cluster, it is supposed to touch the file and change its timestamp. That will tell the system that caches are invalid (as their timestamps will become older than newest .lastModified file).

Generating Shared Cache

The caches (as introduced in invalidating caches section) are optimized to reflect the state of previous start. However that means, the very first start runs without them. This may not be a problem (if the start follows immediately after installation), however in multi user environment (when the installation is done by administrator), the first start may be slow.

To mitigate that the system offers support for shared caches. As part of installation, one can also copy certain cache files into the shared location. Those files will then be used on a first start of the system (when the user directory is empty).

To generate the shared cache files start NetBeans with an empty, temporary user directory and then copy the desired files into first cluster directory:

$ netbeans --userdir /tmp/nb -J-Dnetbeans.close=true -J-Dorg.netbeans.core.WindowSystem.show=false
$ cd /tmp/nb
$ zip -r $INSTALL/$first_netbeans_dirs_dir/var/cache/populate.zip var/cache/netigso
$ cp var/cache/* $INSTALL/$first_netbeans_dirs_dir/var/cache
$ rm -r /tmp/nb/
         

The meaning of populate.zip and list of known cache files is described here. Additional modules and subsystems may add new files however. The ultimate knowledge is available only to those who understand overall product installation structure.

Patch classes

In case one wants to modify other classes before they get loaded into the VM, one can register its own Agent-Class and then be called whenever another class is defined. The behavior matches as closely as possible the one provided by JDK instrument package. To patch bytecode of other classes register your class in manifest and in its static agentmain method add your own ClassFileTransformer which will then be consulted whenever new classes are loaded.

# following line should be in manifest of your module
Agent-Class: your.pkg.Transformer             

// this should be your class
package your.pkg;
public class Transformer implements ClassFileTransformer {
    public static void agentmain(String args, Instrumentation i) {
        i.addTransformer(new Transformer());
    }
             
    public byte[] transform(
        ClassLoader loader, String className, Class classBeingRedefined, 
        ProtectionDomain protectionDomain, byte[] classfileBuffer
    ) {
        // do your transformation
    }
}

The implementation tries to be as complient as possible with the original JDK's specification, but some differences are inevitable. For example the classBeingRedefined parameter in the previous example is always null as NetBeans runtime container does not have access to the class instance that is being defined yet.

Module Fragments

This is a specific case of Patch Classes use-case. To maintain binary compatibility when removing methods from API classes, the "removed" implementation is actually moved to a special class, which becomes a superclass of the original API class. Such special classes should be separated into a 'compat' module, which is only loaded in presence of old clients.

The compat module should declare it is a fragment of the original API module in its MANIFEST.MF

OpenIDE-Module-Fragment-Host: orignal.module.codename
            

which ensures contents of the compat module will be loaded using classloader of the 'fragment host' module. The compat module will not get its own classloader. The special class itself should be marked using PatchPublic annotation, which causes it will be patched as superclass and inserted into the inheritance chain.


How to use Core?

XXX no answer for arch-what

No special APIs exported beyond few friend contracts:

How to use Core - IDE?

core.ide

Register Node in Services tab

Use ServicesTabNodeRegistration to register your nodes into Services in the IDE.


How to use Multi-tabs?

Allow easy customization of editor tabs.

Tab Decorator

To customize the rendering of (some) editor tabs one needs subclass TabDecorator class and register it in the global Lookup.

The example below shows a decorator that removes file extension from Java source files to have shorter tabs to show more file names without the need for scrolling.

ServiceProvider(service = TabDecorator.class, position = 1000)
public class MyTabDecorator extends TabDecorator {

    public String getText( TabData tab ) {
        String res = tab.getText();
        if( null != res )
            res = res.replace( ".java", "");
        return res;
    }
}
              

Custom Tab Displayer

If one needs a custom editor tab displayer for example to have special tab layout or special layout of scrolling buttons etc it is necessary to subclass TabDisplayer class and register an instance of TabDisplayerFactory in the global Lookup.


public class MyTabDisplayer extends TabDisplayer {

    public MyTabDisplayer( TabDataModel model ) {
        super( model );
    }

    ServiceProvider(service = TabDisplayerFactory.class)
    public static class MyTabDisplayerFactory extends TabDisplayerFactory {
        public TabDisplayer createTabDisplayer( TabDataModel tabModel, int orientation ) {
            return new MyTabDisplayer( tabModel );
        }
    }

    //implement all abstract methods here
}
          


How to use MultiView Windows?

Multi views are general mechanism for displaying several perspectives, or views of data, which will be used consistently across whole IDE window system. Using multi views will enable modules to visually represent data document or object in unified manner at one specific place in the system, yet still allowing for different perspectives of data viewing.

There is an introduction to MultiView and its usage in its javadoc. It covers the major part of available usecases. Here is just a list of frequently asked or interesting questions slowly expanding as people ask them:

MultiView faq:

How does serialization work?

Q: How does serialization of multiviews work and what needs to be serializable?

First of all, you don't need to worry about serialization if all your MultiViewDescription instances contained in the multiview state to be non serializable. Meaning they all return TopComponent.PERSISTENCE_NEVER in MultiViewDescription.getPersistenceType().

If at least one of the views requires serialization, you have no choice but to make all MultiViewDescription implementors serializable. You also can persist the MultiViewElement instances that the multiview contains. The algorithm here is a bit complicated for performance reasons. Only those Elements are stored that were created during the session and which are Serializable. So if the user never switches to the 4rd tab, and it's corresponding element and visual component never get created, then it won't be stored. (We would have to create it just for the sake of persistance). So if your visual component needs some inital context for creation, you should store it in the description instance, and if the visual component wants to store it's state (location of cursor, selected field, something else that makes sense for the opened component) you should store it in the MultiViewElement. So basically if you are always able create the Element from Description without any persisted data, you don't need to persist anything.

If you define your own CloseOperationHandler implementation for the multiview component, then you also ought to define it Serializable. Otherwise it will be silently replaced by the default handler on restoration of the multiview component.

How to set the display name?

Q: How do I set the display name for the multiview component?

Each MultiViewDescription defines display name and icon. While the icon is meant for the whole document/view tab, the display name is just for the inner switching button. So how does one set the name for the whole MultiView component? It can be done when creating the component.

    TopComponent mvtc = MultiViewFactory.createMultiView(myDescriptions);
    mvtc.setDisplayName("My static mvtc displayName");

Later in the lifecycle of the component, it can be also influenced from within the individual multiview visual elements using the MultiViewElementCallback.updateTitle() method.


How to use NetBeans OSGi Integration?

XXX no answer for arch-what

Share NetBeans Resource Cache

The only supported usecase right now is to allow any framework to obtain access to internal cache and load classes from it. See NetigsoArchive.


How to use Startup?

XXX no answer for arch-what

XXX no answer for arch-usecases


How to use UI Handler Library?

XXX no answer for arch-what

XXX no answer for arch-usecases


How to use Git Library API?

The library provides a Java implementation of git client allowing you to work with and get information about Git repositories and run Git commands.

Get Git client

Before you can run preferred Git commands, you must get an instance of GitClient bound to a specific repository.
Instances of GitClient are provided by GitRepository. GitRepository represents a concrete local Git repository and is always bound to a specific folder.

The correct way to achieve this is to call GitRepository.getInstance(repositoryRoot).createClient().

Run Git commands

To run a Git command simply call a method mapped to the command on an instance of GitClient.

Control Git command's workflow

You are able to control a Git command's work and listen for warning and error messages and informative messages indicating start and finish of the command via ProgressMonitor. Every method of GitClient mapped to a Git command accepts an instance of ProgressMonitor as a parameter. Through an instance of this class you can cancel a command, an implementation of such a command periodically calls isCanceled and interrupts its work if the method returns true.
Its basic implementation at ProgressMonitor.DefaultProgressMonitor supports canceling commands while implementing other methods as no-op.

Recieve notifications

Some Git commands may take a noticeable amount of time to finish and waiting that long for the full result returned by the command may not be sufficient. Git API provides a way to follow the process of building the result of such commands.
Let's say you want to get all revisions from the Git history. The log command is expensive especially on large repositories and you do not want to wait for it to finish but want to be notified when a single revision from the history is fetched and added to the result. This way you can incrementally present the result in the UI without the need for waiting indefinitely for the command to finish.

Package org.netbeans.libs.git.progress offers a set of listeners extending the NotificationListener interface which you can attach to an instance of GitClient via addNotificationListener() and through which you can closely monitor building of the result.


How to use Auto Update Services?

org.netbeans.api.autoupdate org.netbeans.spi.autoupdate

Browse all available units

Give overview of IDE installation to users, it involve overview of installed modules (grouped together as feature), overview of available updates, overview of available new features. The API can return list of UpdateUnit which describes all instances of unit, e.g. installation in IDE, all its available updates, optionlly its backup instance. UpdateUnit can represent either a feature (e.g. group of modules), a single module or a localization.

Proposed usage of API: Call List<UpdateUnit> UpdateManager.getDefault().getUpdateUnits()

Browse all units by chosen style (e.g. modules, features, localization)

Sometimes there can be a need to get overview of units by chosen style, e.g. feature, module or localization.

Proposed usage of API: Call List<UpdateUnit> UpdateManager.getDefault().getUpdateUnits(UpdateStyle style)

Browse installed modules

When an API client needs to get overview of installed modules.

Proposed usage of API: Call List<UpdateUnit> UpdateManager.getDefault().getUpdateUnits(UpdateStyle style) and filter units which haven't been installed yet.

Search for new functionality

Someone is searching for some functionality which can be installed into IDE. It needs a set of available UpdateUnits which are applicable to active IDE. UpdateManager will search all available UpdateUnit given attribute.

Install new functionality

An client needs to install new functionality into the IDE installation. She knows what unit and what version wants to install. Needs to identify if the functionality is ready to install, resolve its dependencies, identify possible problems and locate other unit what have to be installed together with asked functionality.

Proposed usage of API:

Update of installed unit

A client needs to update some unit of functionality which is already installed. She knows what unit and what update element (by version) wants to install. Needs to identify possible problems with update install, resolve its dependencies, identify possible problems and locate other unit what have to be installed together with asked functionality.

Proposed usage of API: See above Install new functionality

Uninstall functionality

An client needs to uninstall some functionality from IDE installation. She knows what unit wants to uninstall. Needs to identify if the functionality is ready to uninstall, resolve its dependencies, identify possible problems and locate other unit what will be disabled together.

Proposed usage of API:

Switch off functionality

An client needs to switch off (disable) some functionality in IDE installation. Needs to resolve its dependencies, identify possible problems and locate other unit what will be disabled together.

Proposed usage of API:

Switch on functionality

Like Switch off functionality An client needs to switch on (enable) some functionality in IDE installation.

Rollback of previous update

Sometimes an client needs to rollback of installed update of unit to previous version. Needs to resolve its dependencies, identify possible problems and locate other unit what are affected by rollback.

Proposed usage of API: Like above Switch off functionality

Resolve problems what accrued while processing operation

OperationContainer and OperationInfo identifies some problems, i.e. broken dependencies, needs to install more units, the operation causes disable some other modules and so on. The client can use this information to consult these with end-user.

Make IDE up-to-date

Sometimes need to make whole IDE installation up-to-date. Find all available updates of installed units and install the latest available version. It is covered by previous use-cases.

Get all subscriptions to Update Center

Show me all registered subscriptions to Update Center, e.g. get me list of UpdateUnitProvider. Proposed usage of API: Call UpdateUnitProviderFactory.getUpdateUnitProviders()

Subscribe new Update Center

If there is a new Update Center which is not already subscribed into IDE user wants to subscribe new one Update Center which will be connected from that time in periodically checks. There should be a factory where subscribe new one Update Center, known types of Update Center have own factory method. Proposed usage of API: Simply call UpdateUnitProviderFactory.create() which creates and registered new one subscription in the system and will be used from that time in the future.

Customization of Update Center subscription

An user wants to enable or disable of Update Center subscription. Proposed usage of API: Simply call UpdateUnitProviderFactory.setEnable(UpdateUnitProvider, boolean).

Unsubscribe of some Update Center

Simple unsubscribe a chosen Update Center from the system. Need to know of chosen Update Provider Id. This Update Center won't be checked anymore. Proposed usage of API: Simply call UpdateUnitProviderFactory.remove(Id).

Refresh content of subscribed Update Center

The content of Update Provider is cached and the system works across there caches. There is a cache per each Update Center subscription. The caches are refreshed periodically by the system. But, sometime an user wants to call refresh manually. Proposed usage of API: Simply call UpdateUnitProvider.refresh().

Specify the cluster where to install

TBD

Get all installed files of given unit

TBD


How to use Auto Update UI?

AutoUpdateUI

Download and Install

Primary purpose of the API is to share classical UI for downloading and installing additional modules. Read about PluginManager.openInstallWizard.

How to use Issue Tracking?

The module allows to integrate Bugtracking systems into the IDE workflow.

The main Bugtracking SPI and API Use Cases are based on:
- the Bugtracking UI spec.
- the Issue Management Use Cases. For additional information see also Tasks Dashboard UI spec

Registration and setup

The Bugtracking SPI provides a way to register bugtracking plugins and to setup remote Repository configurations of one kind.

Accessing Issues

All registered plugins provide the capability to access Issues from a Repository via:
- their ID
- based on a simple text criteria
- the capability to create, edit and execute more complex Queries

Issue management

For the needs of Issue Management all registered plugins provide: - the capability to create and edit Issues
- basic Issue information like id, summary, priority, scheduling ...

Automated Issue Operations

All registered plugins provide bugtracking functionality (if available) to other IDE workflows via the Bugtracking API. - e.g. attaching files, closing Issues, etc.

See also the more detailed API/SPI requirements.


How to use Classfile Reader?

The ClassFile API is designed as a fast, low memory-cost way to access classfile information. It is useful for tools and modules that directly read classfiles, such as the clazz and javacore modules.

The normal usecase is for a client wanting to inspect a classfile. A ClassFile instance is created with either a String path, File or InputStream instance. All attributes of the classfile are available as properties, such as getSourceFileName or getMethods.


How to use Static Analysis Core?

XXX no answer for arch-what

XXX no answer for arch-usecases


How to use Database Explorer?

This project provides access to objects defined in the Database Explorer. Documentation is available in the Javadoc.

Registering JDBC ../db.drivers

An external module can register JDBC drivers. A typical example is a module which provides integration with a database server. In this case the module contains the JDBC driver for that database server and uses the Database Explorer API to add it do the Database Explorer.

Another client of this API could be a module providing integration with a J2EE application server. Sometimes a J2EE application server bundles a database server for improving the out-of-the-box experience. When the server is registered in the IDE the JDBC drivers for the bundled database server are added to the Database Explorer.

The drivers are registered by making calls on JDBCDriverManager or by registering an XML file which describes the driver in the module layer. The XML file is described by the JDBC Driver DTD. An example of a registration file describing the JDBC driver for PostgreSQL follows:

    <?xml version='1.0'?>
    <!DOCTYPE driver PUBLIC '-//NetBeans//DTD JDBC Driver 1.0//EN' 'http://www.netbeans.org/dtds/jdbc-driver-1_0.dtd'>
    <driver>
      <name value='postgresql-7'/>
      <display-name value='PostgreSQL (v7.0 and later)'/>
      <class value='org.postgresql.Driver'/>
      <urls>
        <url value='file:/folder1/folder2/drivers/pg74.1jdbc3.jar'/>
      </urls>
    </driver>
   

This file should be registered in the Databases/JDBCDrivers folder of the module layer. To addres a bundled JAR inside the IDE the nbinst protocol can be used in the URLs: nbinst:/modules/ext/bundled-driver.jar.

Get the underlying JDBC Driver instance for a JDBCDriver

You can use the JDBCDriver.getDriver() method to obtain a reference to the underlying JDBC Driver instance. This is useful if you want to use the registered drivers but create your own JDBC connections independent of the Database Explorer.

Retrieving the list of JDBC ../db.drivers

When creating a new connection the JDBC driver which it should use can be specified. A list of all the registered JDBC drivers can be retrieved using JDBCDriverManager.getDrivers().

Registering database runtimes

An external module can register new database runtimes. A database runtime is an abstraction of a database server instance (usually bundled with the IDE, an integration module or with a J2EE server). It allows a database server instance to be started and stopped when a connection to this instance is made in the IDE. Database runtimes are represented by the DatabaseRuntime SPI interface and are registered in the Databases/Runtimes of the module layer.

Creating database connections

A module can create new database connections (for example to a bundled database). New connections can be added by calling DatabaseConnection.create() to create a new DatabaseConnection instance and then ConnectionManager.addConnection() to add the connection to the Database Explorer.

New connections can also be added by registering them in the module layer. The format of the registration file is described by the Database Connection DTD. An example of a registration file describing a connection to a PostgreSQL database follows:

    <?xml version='1.0'?>
    <!DOCTYPE connection PUBLIC '-//NetBeans//DTD Database Connection 1.1//EN' 'http://www.netbeans.org/dtds/connection-1_1.dtd'>
    <connection>
      <driver-class value='org.postgresql.Driver'/>
      <driver-name value='postgres-7'/>
      <database-url value='jdbc:postgresql:test'/>
      <schema value='public'/>
      <user value='test'/>
      <password value='cGFzc3dvcmQ='/>
    </connection>
   

This file should be registered in the Databases/Connections folder of the module layer.

The password element is optional, but if it is included, its value must be the Base64 encoding of the UTF-8 representation of the password. Note that the UTF-8 representation of passwords composed entirely of ASCII characters is the same as their ASCII representation, so for such passwords all that needs to be done is to convert them to Base64.

Base64 encoding serves as a simple scrambling to prevent accidental revelation of the password. It is not indended to offer any real security. You can protect the password by assigning appropriate file protections to the connection XML file.

Retrieving and displaying the list of database connections

Sometimes the list of connections needs to be displayed somewhere else in the IDE than the Runtime tab. A typical example is the SQL Editor, which allows the user to select the database connection which the SQL statement will be executed against in a combo box in the editor toolbar. The list of connections can be obtained by calling ConnectionManager.getConnections(), which returns an array of DatabaseConnection instances.

The client usually needs to show the display name of the connection. The display name can be retrieved using the DatabaseConnection.getDisplayName() method.

Retrieving the properties of database connections

Sometimes a client needs to retrieve the connection properties, such as the driver class. An example could be a module for a J2EE server creating a connection pool. The properties can be retrieved using the getDriverClass(), getDatabaseURL(), getSchema(), getUser() and getPassword() methods of the DatabaseConnection class.

Showing the New Database Connection dialog

Usually when displaying a list of connections (usually in a combo box), the last item is "New Connection", which displays the standard New Database Connection dialog of the Database Explorer. This can be achieved by calling one of the ConnectionManager.showAddConnectionDialog() methods.

Remove a database connection

A user of this API may want to remove a connection from the list of connections registered by the Database Explorer. This is done using ConnectionManager.removeConnection()

Connecting to a database

A component which provides database functionality (such as the SQL Editor) will need to connect to a database. This can be achieved using the DatabaseConnection.showConnectionDialog() method and the java.sql.Connection instance can be retrieved using the getJDBCConnection() method.

If you want to connect to the database without showing a dialog or any kind of UI, you can use the DatabaseConnection.connect() method.

Test a database connection for validity

You may want to test to make sure the underlying physical JDBC connection obtained from a DatabaseConnection is either valid or null. This is done using the DatabaseConnection.getJDBCConnection(boolean test) method, which validates the underlying connection before returning it. If the connection is invalid, it marks the DatabaseConnection as disconnected and returns null.

Displaying the database connections in the UI

A component which provides database functionality (such as the SQL Editor or a module providing support for data sources) will need to let the user select the a database connection, usually through a combo box. This can be achieved using the DatabaseExplorerUIs.connect() method. The JComboBox passed to the method will be filled with the list of connections as returned by ConnectionManager.getConnections(), followed by a separator and a New Database Connection item which will display the dialog for adding a new database connection when selected.

Drag and drop support for database objects

A component might need to allow database tables from the Database Explorer to be dragged to a visual editor. An API is provided in DatabaseMetaDataTransfer containing DataFlavors for database objects and nested classes encapsulating those database objects during a drag and drop transfer.

Get support for working with SQL identifiers

A component might need support for working with SQL identifiers. In particular, it's important to know when to quote a SQL identifier. The SQLIdentifiers.Quoter class is provided for this.


How to use Diff?

The diff module provides the ability to visualize differences between source files. It also has a graphical conflicts resolver tool and built-in patch algorithm. List of the main features: Simple APIs, that provide access to registered diff and merge engines and visualizers. Built in and external diff engines defined. Graphical diff vizualizer and conflicts resolver. Extensible with additional diff and merge engines and vizualizers. Patch algorithm implemented for UNIX-style, unidiff and contextual diff formats.

Show a diff from action

From an action or wherever you like you can call this:

public void diff(final StreamSource local, final StreamSource remote){
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            try {
                DiffView view = Diff.getDefault().createDiff(local, remote);
                showDiff(view);
            } catch (IOException ex) {
                Logger.getLogger(ThisClass.class.getName()).throwing(ex);
            }
        }
    });
}
public void showDiff(final DiffView view){
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            //create our panel with our view
            //right now I am just going to use the diff component 
            // instead of a panel
            //create a topcomponent with our panel
            DiffTopComponent tc = new DiffTopComponent(view);
            tc.setName("MY_DIFF");
            tc.setDisplayName("Some display name");
            tc.open();
            tc.requestActive();
        }
    });
}

Embeded into TopComponent

Here is a top component to display it:

public class DiffTopComponent extends TopComponent {
    /** Creates a new instance of DiffTopComponent */
    public DiffTopComponent(Component diffPanel) {
        setLayout(new BorderLayout());
        add(diffPanel, BorderLayout.CENTER);
        getAccessibleContext().setAccessibleName(
            NbBundle.getMessage(DiffTopComponent.class, 
            "ACSN_Diff_Top_Component")); // NOI18N
        
        getAccessibleContext().setAccessibleDescription(
            NbBundle.getMessage(DiffTopComponent.class, 
            "ACSD_Diff_Top_Component")); // NOI18N
    }
   
    public DiffTopComponent(DiffView view) {
        this(view.getComponent());
    }
    public int getPersistenceType(){
        return TopComponent.PERSISTENCE_NEVER;
    }
    protected String preferredID(){
        return "DiffTopComponent";    //NOI18N
    }
    public HelpCtx getHelpCtx() {
        return new HelpCtx(getClass());
    }
}

How to use Editor Module?

The editor module provides a full-featured source text editor that is integrated with the Form Editor, Explorer, compiler, and debugger. List of the main features: Syntax highlighting of java, HTML, XML and other languages. Code Completion enables to type a few characters and then display a list of suggestions appropriate in the given context that can be then used to automatically complete the expression. Word Matching enables enables to type the beginning characters of a word used elsewhere in the code and then have the editor generate the rest of the word. Abbreviations allow to expand typed text from a few predefined characters into a full word or phrase. Goto Class enables to open a Java file in the Source Editor by typing only the class name. The IDE helps to identify the correct package name for the class. The Fast Import feature enables to quickly add import statements for Java classes in the source file. Goto Declaration feature allows to quickly jump to a declaration of a variable under the cursor. Goto Source allows to open source file containing definition of a type that the variable under the cursor is of. Code folding allows to collapse sections of the code that are unimportant to the user at the given time. For example in java source the collapsable sections include imports section, inner classes, methods and javadocs.

No answer

How to use Editor Braces Matching?

The Braces Matching SPI allows modules providing editor support for documents to create their own BracesMatchers that are tailored for the type of documents they support. The module itself provides an infrastructure for highlighting matching areas identified by a matcher and navigating between them.

Although the SPI can generally by used for highlighting areas in a document that have something in common, the usecases below are demonstrated on a simple braces matching example. This example is used for its simplicity and clarity, but it could be substituted by more complex examples.

The usecases listed here were heavily inspired by comments in issues 95126 and 66037.

Usecase 1. - Highlighting results

Probably the main reason why this SPI exists is to allow Netbeans editor to highlight matching braces in a document. The highlighting itself is done by the infrastructure and is not of a concern for BracesMatcher implementors. It should be possible to highlight independently (ie. in a different color) both the original brace and the matching brace. It should also be possible to highlight the original brace in a special color when its matching brace can't be found. The colors obviously have to be customizable by users.

Usecase 2. - Navigating between results

If the original brace is detected and its matching brace is found Netbeans editor needs to allow an easy navigation between those two positions (ie. jumping from the original brace to the matching one and back).

In general if there is more than one matching area users should be allowed to cycle through all of them. Since there is only one editor action (shortcut) for navigating between matching areas the cycling is only done in one direction (backward). In order for cycling to work properly the BracesMatcher implementation has to report matching areas in a consistent way. That is the matching areas should always be sorted by their position in a document, starting with the one at the lowest offset.

Usecase 3. - Different search scenarios

The users are likely to have different preferences for the way how braces matching works therefore its behavior should be customizable. We have listed below several possible scenarios that can be used simply by setting different values for the search parameters described before. They all differ in the way how the original area is detected.

The shortcuts for the parameters have the following meaning - MBL ... max backward lookahead, MFL ... max forward lookahead, SD ... search direction, CB ... caret bias. The values are B ... backward or backward preferred and F ... forward or forward preferred. The question mark ? means that the value of this parameter has no effect for the search.

Usecase 4. - Auto-switching the search scenario

The editor in Netbeans can operate in two modes - normal and overwrite. They both use different shape of a caret and thus need a different caret bias. The braces matching infrastructure should detect what mode the editor is in and change the parameters used for searching for the original area accordingly. The caret bias is the most important parameter, but other parameters may need to be changed too.

This feature should of course be only active for text components where the parameters have not been overwritten by some other module.

By default the two search scenarios used for the normal and overwrite modes in Netbeans editor are the scenario B for the normal mode and scenario A for the overwrite mode. In general scenarios from both editor modes should be customizable by users.


How to use Editor Code Templates?

Code Templates allow to paste various code snippets by using parametrized text. The parameters of the same name will share the same default value and if that value gets changed by user's typing the new value gets replicated into all the parameter's occurrences. Code Templates replace the original abbreviations functionality. Code template's example for (Iterator ${iterator} = ${collection instanceof="java.util.Collection"}.iterator(); ${iterator}.hasNext();) { ${cursor}${iterator}.next();" } Each parameter can have additional hints of what values can be assigned to it. The hint has a form ${param hint=value} or just ${param hint} which translates to ${param hint="true"} If necessary the value of the hint can be enclosed in quotes to allow to write whitespace or { or } into the value. The quote can be written by using \". Reserved parameter names ${cursor} defines position where the caret will be located after the editing of the code template default values will finish. Reserved hint names ${param editable=false} can be used to make the parameter to be skipped from user's editing. This may be useful e.g. with using java-specific type hint (described below). Java: ${ind index} defines that the default value of the parameter should be an unused variable in the given context named i. If i is already used then j is attempted or then k etc. until z. Then i0, i1 etc. are attempted. ${param type="java.util.Collection"} defines java type that the parameter must be instance of. Besides class names there can be array e.g. String[] or generics java.util.List<String> ${param array} defines parameter of array type (including arrays of primitive data types). ${param type="java.util.Iterator"} defines that the parameter has the given java type. The template processing infrastructure will use short name Iterator and import java.util.Iterator.

Code Template Parameters

One of the main benefits of the code templates is their parametrization which allows to substitute the default values for the parameters before the final insertion and it also allows the user to modify these default values explicitly after the code template gets inserted into the document.
The parameters are marked in the code template's text by ${...}.
Parameters of the same name benefit from automatic replication. Once the template gets pasted into the document all the parameter's occurrences get replaced by parameter's default value.
The first parameter's occurrence gets selected.
The user can now replace the default value. If the user does so the new value gets replicated to all the other occurrences of this parameter automatically.

Mime-type specific operation

Each code template needs to find the default values for its parameters before it gets inserted into the text.
Sometimes it's enough to just specify the default value in the template's text but usually the default value gets determined from the context of insertion.
There is an intent to create a mime-type specific code template processor that would be registered per mime-type. There could be even more than one such processors processing the template in a specific order.

Parameter hints

Besides parameter's name the template processors may need additional hints of how to find a default value for the parameter.
For example java code template's parameter may be an index parameter which means that the infrastructure should fill in a fresh index variable e.g. i.
Or the parameter can only be of a certain java type such as in the case of iterating through a collection the type must be subtype of java.util.Collection.
These requirements could be specified as additional hints to the parameters e.g. ${i index} or ${c instanceof=java.util.Collection}.
The hints allow string literals to support arbitrary explicit default values specifications e.g. ${x default="Hello world"}.
The '{' and '}' have no special meaning inside the string literal.
The '"' char is allowed to be used by escaping ${x default="\"quoted string\""}.

Temporary Code Templates

The Code Completion functionality allows to build temporary Code Templates functionality if it could build a temporary template for completing of the method parameters. The parameters could be completed one by one by tabbing and the Code Templates framework would fill in proper default values just like it does for regular templates.
    JTextComponent pane = ...
    String tempCodeTemplateText = ...
    CodeTemplate ct = CodeTemplateManager.get(pane.getDocument()).createTemporary(tempCodeTemplateText);
    ct.insert(pane);

Insert Text Building and Updating

The parametrized text of the code template first gets parsed and the parameters get their default values which by default are the names of the parameters. The code template processor are then called to update this default value.
The new java infrastructure being developed would benefit from the possibility to obtain the full string containing the skeleton of the code template (without parameters) with the present default values. It can take that string and locally parse it to find out types of local variables used in the particular template and fill in dependent variable types.

Parameter Editability

Certain part of the code template may change text but it should not be edited by the user. For example when iterating over collection given as a parameter the collection may be generics-ed by additional type. The iterator's variable type then also needs to generics-ed with the same type.
The iterator's type parameter should not be editable because this operation may be done automatically by the java code template processor.
There should be a hint editable having true/false.

How to use Editor Code Completion?

Code Completion provides users with a list of suggested completions for partially typed texts in the editor and various dialog input fields. The Code Completion module was created to replace the original legacy editor code completion which lacked several key requirements: Support for multiple independent code completion content providers. Implied requirement for ordering and prioritization of the completion items. Direct support for asynchronous completion result computation. Missing separation to the API and SPI and implementation parts.

API

Show or hide completion window

The API is small and it only allows to explicitly show or hide the completion window.
It's being used by code templates that need to explicitly show the code completion window when tabbing to a particular parameter.
There may be certain actions that want to ensure that the code completion is hidden at the time when they are invoked. For example the actions pasting the content of the completion item into the document.

SPI

Provide completion content by independent providers

Completion infrastructure needs to obtain the results that are then displayed in the completion window.
There are three types of displayed results related to the current caret offset:

For the purpose of obtaining these completion results CompletionProvider exists.
There may be an arbitrary number of independent completion providers for a single completion popup window.
The completion providers are registered through the xml layer into Editors/<mime-type>/CompletionProviders. Once the document with the particular mime-type gets loaded the corresponding completion providers will get instantiated and used.

Threading:
The code completion's infrastructure invokes the requests for the completion results in the AWT thread.
Therefore all the methods of the completion providers are invoked in AWT thread but they may reschedule their processing into other threads.

Provide completion results computed asynchronously

The completion provider creates a task that computes the resulting data that will then be displayed by the code completion infrastructure.
The task creation and computation are called synchronously from the AWT event dispatch thread.
However there can be potentially long-running tasks (e.g. working with MDR) that are not desirable to be run in AWT thread.
Therefore the completion infrastructure provides a listener to which the completion task notifies the results.
The support class AsyncCompletionTask allows to post the task computation into RequestProcessor.

Provide list of completion items fulfilling various requirements

The completion task computes a collection of completion items which are then collected by the completion infrastructure and displayed.
Displaying. Each completion item must be able to display itself in a JList.
Sorting. The completion items may come from different completion providers and they must be sorted before displaying. The sort order should not only be alphabetical but it should also allow a prioritization of the items according to their importance in the given context.
Actions. The interaction of the user with the completion item is done by interacting with item's input map and action map.
Documentation. The item may want to display additional detailed information in a documentation popup window.


How to use Editor Error Stripe?

The Error Stripe shows an overview of important information of an edited source code. It shows this information for the whole source code (regardless of its size).

Augment Annotations to be shown in the Error Stripe

Use the OpenIDE Text API.

Provide Up-to-date Status for the Error Stripe

A module in the IDE has information whether data shown in the Error Stripe is up-to-date or not. The Error Stripe may change the appearance according to this knowledge.

Implement the UpToDateStatusProvider that provides up-to-date status. Be sure that it fires PropertyChangeEvent when this status is changed.

Implement the UpToDateStatusProviderFactory that creates an instance of your UpToDateStatusProvider for a given JTextComponent and install it as described here.


How to use Editor Code Folding?

The Code Folding is part of the editor module functionality and it's responsible for hiding of the portions of the code that are less important for the user at the given time.

API Use Cases

Exploring of the Folds

The code folding structure (fold hierarchy) relates to javax.swing.JTextComponent instance in one-to-one relationship.
To find the code folding hierarchy instance for the given non-null text component the following code snippet can be used:

    JTextComponent editorComponent = ...
    FoldHierarchy hierarchy = FoldHierarchy.get(editorComponent);

Explore the Folds Hierarchy

The tree-based hierarchy has one non-removable and non-collapsable root fold that covers the whole document. It can be obtained by

    FoldHierarchy foldHierarchy = ...
    Fold rootFold = hierarchy.getRootFold();

The children folds of the root fold (or children folds) can be obtained by

    // the hierarchy must be locked prior exploration or manipulation
    hierarchy.lock();
    try {
        Fold rootFold = ...
        int foldCount = rootFold.getFoldCount();
        for (int i = 0; i < foldCount; i++) {
            Fold childFold = rootFold.getFold(i);
        }
    } finally {
        hierarchy.unlock();
    }

Index of the child in its parent can be found by

    hierarchy.lock();
    try {
        Fold rootFold = ...
        int foldIndex = rootFold.getFoldIndex(childFold);
    } finally {
        hierarchy.unlock();
    }

Collapse Nearest Fold

In the given fold hierarchy find the nearest fold right at or after the given offset and collapse it.

    hierarchy.lock();
    try {
        Fold fold = FoldUtilities.findNearestFold(hierarchy, offset);
        hierarchy.collapse(fold);
    } finally {
        hierarchy.unlock();
    }

Expand All Folds

In the given fold hierarchy expand all folds that are currently collapsed.

    FoldUtilities.expand(hierarchy, null);

Collapse All Folds of Certain Type

In the given fold hierarchy collapse all e.g. javadoc folds that are currently collapsed.
The example can be generalized to any fold type.

    FoldUtilities.collapse(hierarchy, JAVADOC_FOLD_TYPE);

Start Listening on Fold Hierarchy Changes

In the given fold hierarchy start to listen on all changes done in the hierarchy.
This is actually used e.g. in the Editor's View Hierarchy that needs to refresh views based on the fold changes.

    hierarchy.addFoldHierarchyListener(new FoldHierarchyListener() {
        public void foldHierarchyChanged(FoldHierarchyEvent evt) {
            // Hierarchy does not need to be locked here
            //
            // evt.getAffectedStartOffset() and getAffectedEndOffset()
            // give text area affected by the fold changes in the event
        }
    });

Inspect Collapsed Folds in Affected Area

Listen on the hierarchy changes and refresh the views in the text area affected by the fold change.
Inspect the collapsed folds in the affected area because special views need to be created for the collapsed folds.
The actual code in the View Hierarchy is somewhat different but the one given here is more descriptive.

    hierarchy.addFoldHierarchyListener(new FoldHierarchyListener() {
        public void foldHierarchyChanged(FoldHierarchyEvent evt) {
            for (Iterator collapsedFoldIterator
                = FoldUtilities.collapsedFoldIterator(hierarchy,
                    evt.getAffectedStartOffset(),
                    evt.getAffectedEndOffset()
                );
                it.hasNext();
            ) {
                Fold collapsedFold = (Fold)it.next();
                // Create special view for the collapsedFold
            }
        }
    });

SPI Use Cases

Create a New Fold Manager

Manipulation of the folds is designed to be done by fold managers.
Those classes implement FoldManager interface in the SPI.
At initialization time they are given instance of FoldOperation through which they can create, add or remove the fold instances.

To create and use a new FoldManager instance it's necessary to

Create a New Fold by Fold Manager

Create a new fold and add it to the hierarchy. The operation is performed by the fold manager either at initialization phase (in the initFolds() which gets called automatically by the infrastructure) or at any other time when the fold manager's operation gets invoked (usually by a listener that the fold manager attaches to be notified about changes that can cause the folds structure to be changed - e.g. a parsing listener for java folds).

Operations that manipulate the hierarchy are done in terms of a valid transaction over the fold hierarchy.
Transactions allow to fire the collected changes as a single FoldHierarchyEvent at the time when they are committed.

    // In the FoldManager's context
    FoldOperation operation = getOperation();
    FoldHierarchyTransaction transaction = operation.openTransaction();
    try {
        Fold fold = operation.createFold(...);
        operation.addFoldToHierarchy(fold, transaction);
    } finally {
        transaction.commit();
    }

Remove Fold from Hierarchy by Fold Manager

Remove the existing fold from the hierarchy

    // In the FoldManager's context
    FoldOperation operation = getOperation();
    FoldHierarchyTransaction transaction = operation.openTransaction();
    try {
        Fold fold = ...
        operation.removeFoldFromHierarchy(fold, transaction);
    } finally {
        transaction.commit();
    }

Updating Fold hierarchy

In the preceding cases, maintaining Folds was the FoldManager's responsibility. The FoldManager typically held a copy of the Folds added to the hierarchy, and during the refresh, it compared them to the new data and decided what folds to remove. For simple cases, which only create/remove folds based on text positions, part of the work can be offloaded to the FoldOperation:
    // create new fold positional information for all folds.
    Collection<FoldInfo> newInfos = ...;
    
    // create FoldInfo for each of the fold
    newInfos.add(
        FoldInfo.range(start, end, type).
            withTemplate(customTemplate).
            withDescription(veryCustomDescription).
            collapse(true)
    );
    
    // the hierarchy must be locked prior to update
    
    doc.readLock();
    hierarchy.lock();
    try {
        operation.update(newInfos, null, null);
    } finally {
    }
The update() operation performs a diff, creates new folds, discards old ones, and updates the folds, which prevailed.

Accessing folds

Instead of keeping a copy of created folds, the FoldManager may call operation.foldIterator. The iterator will enumerate all folds, including (recursively) blocked ones.

How to use Editor Guarded Sections?

Guarded Sections protects user from modifying document content. The main goal is to simplify work with such a content to module writers and preserve created sections.

Add new section

In order to add a new section after the existing section, which seems to be most frequent, use:
        String sectionName = ...;
        StyledDocument doc = ...;
        GuardedSectionManager guards = GuardedSectionManager.getInstance(doc);
        GuardedSection g = guards.findSimpleSection(sectionName);
        guards.createSimpleSection("new_name", doc.createPosition(g.getEndPosition().getOffset() + 1));
       

Delete existing section

        StyledDocument doc = ...;
        GuardedSectionManager guards = GuardedSectionManager.getInstance(doc);
        GuardedSection g = guards.findSimpleSection("sectionName");
        g.deleteSection();
       

Plug guarded sections stuff into the editor

In case you want your CloneableEditorSupport to provide guarded sections you should implement the GuardedEditorSupport interface.
        private final class MyGuardedEditor implements GuardedEditorSupport {
           ...
        }
       
Further implement reading and writing of existing sections.
        protected void loadFromStreamToKit(StyledDocument doc, InputStream stream, EditorKit kit) throws IOException, BadLocationException {
            if (guardedEditor == null) {
                guardedEditor = new MyGuardedEditor();
                // remember the provider
                String mimeType = ((CloneableEditorSupport.Env) this.env).getMimeType();
                guardedProvider = GuardedSectionsFactory.find(mimeType).create(guardedEditor);
            }

            // load content to kit
            if (guardedProvider != null) {
                guardedEditor.setDocument(doc);
                Charset cs = FileEncodingQuery.getEncoding(this.getDataObject().getPrimaryFile());
                Reader reader = guardedProvider.createGuardedReader(stream, cs);
                try {
                    kit.read(reader, doc, 0);
                } finally {
                    reader.close();
                }
            } else {
                kit.read(stream, doc, 0);
            }
        }

        protected void saveFromKitToStream(StyledDocument doc, EditorKit kit, OutputStream stream) throws IOException, BadLocationException {
            if (guardedProvider != null) {
                Charset cs = FileEncodingQuery.getEncoding(this.getDataObject().getPrimaryFile());
                Writer writer = guardedProvider.createGuardedWriter(stream, cs);
                try {
                    kit.write(writer, doc, 0, doc.getLength());
                } finally {
                    writer.close();
                }
            } else {
                kit.write(stream, doc, 0, doc.getLength());
            }
        }
       
Your module should also require a proper implementation. In case of java content add to your module manifest file:
        OpenIDE-Module-Requires: org.netbeans.api.editor.guards.Java
       


How to use Editor Indentation?

Editor indentation performs reindentation and code beautification of Swing document.

API Usecases

Fix indentation of a single or multiple lines of a document.

Altghough there are formatting actions already there may be clients wishing to explicitly fix indentation of e.g. a newly inserted code into a Swing document.

The same code is used after inserting a newline into a document.

The Indent is an entry point for performing reindentation. The following code should be used by clients:
Indent indent = Indent.get(doc);
indent.lock();
try {
    doc.atomicLock();
    try {
        indent.reindent(startOffset, endOffset);
    } finally {
        doc.atomicUnlock();
    }
} finally {
    indent.unlock();
}

Code beautification of a selected area of a document.

Code beautification should not only fix line indentation but it may also perform extra changes to code according to formatting rules. For example add newlines or additional whitespace or add/remove extra braces etc.

The Reformat class should be used:
Reformat reformat = Reformat.get(doc);
reformat.lock();
try {
    doc.atomicLock();
    try {
        reformat.reformat(startOffset, endOffset);
    } finally {
        doc.atomicUnlock();
    }
} finally {
    reformat.unlock();
}

How to use Editor Library?

The editor library module provides subset of editor functionality independent on the NetBeans IDE (except few specific standalone classes). List of the main features: Syntax highlighting of java, HTML, XML and other languages. Code Completion enables to type a few characters and then display a list of suggestions appropriate in the given context that can be then used to automatically complete the expression. Word Matching enables enables to type the beginning characters of a word used elsewhere in the code and then have the editor generate the rest of the word. Abbreviations allow to expand typed text from a few predefined characters into a full word or phrase. Goto Class enables to open a Java file in the Source Editor by typing only the class name. The IDE helps to identify the correct package name for the class. The Fast Import feature enables to quickly add import statements for Java classes in the source file. Goto Declaration feature allows to quickly jump to a declaration of a variable under the cursor. Goto Source allows to open source file containing definition of a type that the variable under the cursor is of. Code folding allows to collapse sections of the code that are unimportant to the user at the given time. For example in java source the collapsable sections include imports section, inner classes, methods and javadocs.

No answer

How to use Editor Library 2?

The Editor Library 2 module is a set of official APIs and SPIs, designed to replaces the original Editor Library with legacy APIs that are not properly structured and do not conform to the rules implied on the current NB APIs. The APIs currently offered in Editor Library 2 module include: editor-code-generator editor-highlighting editor-typing-hooks

At the moment the Editor Library 2 module contains three distinct SPIs. Each SPI lives in its own package and the usecases can be found in the packages overview.

How to use MIME Lookup API?

Each editor provides an EditorKit which controls the policy of specific MIME content type. The policy of content type should be easily registered and found via some lookup mechanism, that will provide convenient way of using it either for kit provider or base editor infrastructure. In addition to this, the policy can be inherited, (e.g. in case of embeded kits like JSP) and the content types need to be merged in this case. MIME Lookup API should provide all mentioned requierements via easy lookup query, so content type policy user need not to solve this searching and merging on its own side.

Per mime-type operation

Operation of the editor module must be parametrized by the type of the file being edited. In the past the operation was parametrized by the class of the editor kit but that did not show up as being useful enough.
It is more practical to use a string-based parametrization concretely the mime-type. Anyone can then easily register an additional functionality for the editor because it's just enough to know the right mime-type and the type of the functionality class to be implemented and the xml layer folder where the class should be registered.

Provide list of instances as lookup result

On the modules' implementation side the registered functionality must be retrieved somehow. It's necessary to instantiate the registered objects and react to module enabling/disabling which can affect validity of the registered objects.
As the most convenient solution appears to use org.openide.util.Lookup allowing to provide the registered instances as a Lookup.Result allowing to listen for changes (e.g. caused by the module enabling/disabling).
This resulted into creation of class MimeLookup extends Lookup containing static MimeLookup getMimeLookup(String mimeType).

Nested mime-types

On the lexical level the document can contain nested languages.
For example JSP document can contain pieces of java code which can further contain javadoc comment tokens with nested javadoc language.
The nested languages should allow for special settings such as fonts and colors of nested syntax coloring but even things like actions that would be active in the nested document section.
This resulted into creation of static Lookup getLookup(MimePath mimePath) method in MimeLookup.

Known clients summary

Fold Manager Factories
The editor/fold module expects to find the registered fold manager factories (org.netbeans.spi.editor.fold.FoldManagerFactory classes).

Completion Providers
The editor/completion module expects to find the registered completion providers (org.netbeans.spi.editor.completion.CompletionProvider classes).

Editor Context Menu Actions
The editor module expects to find the registered popup menu actions (javax.swing.Action classes or names of actions (i.e. value of Action.NAME attribute) present in editor kit e.g. "goto-source").

Side Bars
The editor/lib module expects to find factories for components to be placed on the sides of the editor component (org.netbeans.editor.SideBarFactory classes).

Hyperlink Providers
The editor/lib module expects to find hyperlink providers that allow connecting an open document with some other documents (org.netbeans.lib.editor.hyperlink.spi.HyperlinkProvider classes).

Code Template Processors
The editor/codetemplates module expects to find factories for code template processors (org.netbeans.lib.editor.codetemplates.spi.CodeTemplateProcessorFactory classes).

Hints Providers
The editor/hints module expects to find editor hints providers (org.netbeans.modules.editor.hints.spi.HintsProvider classes).


API Use Cases

Find class instances for the given mime-type

An API method

MimeLookup lookup = MimeLookup.getMimeLookup("text/x-java");

can be used for getting the mime specific lookup. Having this we can lookup class or template:

Object obj = lookup.lookup(LookedUpClass.class);

or

Lookup.Result result = lookup.lookup(new Lookup.Template(LookedUpClass.class));

Getting embeded mime-type specific Lookup

As an example a jsp scriptlet is used. Scriptlet in fact consists of parent "text/x-jsp" mime-type and embeded "text/x-java" mime-type. To obtain a scriptlet lookup firstly we need to get a MimePath and then get appropriate lookup:

    MimePath scriptletPath = MimePath.parse("text/x-jsp/text/x-java");
    Lookup lookup = MimeLookup.getLookup(scriptletPath);

SPI Use Cases

Providing implemented MimeLookupInitializer

It is the general way of adding mime specific object into the MimeLookup. Implementation of MimeLookupInitializer should be created and registered to default lookup via META-INF/services registration. For details, please look at the simplified TestMimeLookupInitializer in mimelookup/test/unit or LayerMimeLookupInitializer. Usage of MimeLookupInitializer is deprecated, please use MimeDataProvider instead in similar way

How to use Editor Settings?

The legacy settings system in the editor module is complicated, error prone and hard to use. It'd been created spontaneously over the years to support immediate needs at that time without paying enough attention to extensibility and interoperability. Historically any module providing editor settings needed to depend on the whole editor module. The main purpose of this project is to define API for editor settings, that is lightweight and easily extensible. The API relies on MimeLookup to provide a way of registering and looking up settings. The aim is NOT to provide an implementation of a storage for editor settings, but to define an interface between this storage and clients like <mime-type> editors, externaleditor, etc.

Accessing settings

All editor settings are mime type specific and therefore should be retrieved using MimeLookup. The following example shows how to retrieve the FontColorSettings for java files and how to get AttributeSet with coloring attributes for a particular coloring (i.e. in this case the colors used for highlighting selected text)

    MimePath mimePath = MimePath.parse("text/x-java");
    FontColorSettings fcs  = (FontColorSettings) MimeLookup.getLookup(mimePath).lookup(FontColorSettings.class);
    AttributeSet coloring = fcs.getFontColors(FontColorNames.SELECTION_COLORING);

Listening on changes

If clients need to react on changes in editor settings they can attach LookupListener to the LookupResult they got for their particular settings class from MimeLookup. The following example shows how to do it.

    MimePath mimePath = MimePath.parse("text/x-java");
    Lookup lookup = MimeLookup.getLookup(mimePath);
    LookupResult result = lookup.lookup(new Lookup.Template(FontColorSettings.class));
    
    result.addLookupListener(new LookupListener() {
        public void resultChanged(LookupEvent ev) {
            //... the client's response to the settings change
        }
    });

The FontColorSettings class implementor is responsible and will create a new instance of FontColorSettings whenever some coloring will change. This new instance will be placed in MimeLookup replacing the old one.


How to use Editor Settings Storage?

The module is an implementation of the org.netbeans.modules.editor.settings providing a settings storage on the default filesystem.

New Options Dialog

The friend API provided by this module is used only by the new options dialog. It is not expected to have any other clients or users. The API gives the options dialog a read/write access to the editor settings storage allowing it to implement UI for maintaining the settings.

Defining a coloring

Various modules need to provide predefined font a colors for text tokens from languages they support. An example of such a module is java/editor which defines colorings for tokens in java files. Defining colorings is as simple as writing an XML file with the appropriate information. The example below shows how to do that.

<?xml version="1.0"  encoding="UTF-8"?>
<!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="mylang-keyword" foreColor="0000CC" default="keyword">
        <font style="bold" />
    </fontcolor>
</fontscolors>

Please see the http://www.netbeans.org/dtds/EditorFontsColors-1_1.dtd for more details.

Defining a key binding

As well as providing predefined colorings modules need to provide predefined key bindings. This can be accomplished by writing another simple XML file.

<?xml version="1.0"  encoding="UTF-8"?>
<!DOCTYPE bindings PUBLIC "-//NetBeans//DTD Editor KeyBindings settings 1.1//EN" "http://www.netbeans.org/dtds/EditorKeyBindings-1_1.dtd">

<bindings>
    <bind actionName="goto-source" key="O-O"/>
</bindings>

Please see the http://www.netbeans.org/dtds/EditorKeyBindings-1_1.dtd for more details.


How to use Editor Utilities?

Editor Utilities module contains useful utility classes and methods used by other editor related modules.

GapList

The GapList class is a java.util.List implementation similar to java.util.ArrayList but containing a gap in its underlying array. After a first modification at a particular index the subsequent modifications around that index are cheap.
The class is suitable for storage of any elements related to editing such as positions, elements, views etc.

PriorityMutex

The PriorityMutex is a simple mutex implementation allowing to find out that a priority thread (by default Event Dispatch Thread) is waiting to enter the mutex.
It's used e.g. in editor's view hierarchy or in editor fold hierarchy.

GapBranchElement

GapList-based element implementation suitable for line elements and any other branch element types.


How to use External Execution API?

Provides common APIs to execute external process in the IDE to handle its streams and present the output to the user. Input/line processing can be used as separate part.

Execution of an external process

Client needs to execute an external process and handle process streams and display the output in the output tab.

In order to achieve this client creates the ExecutionDescriptor. Via this object client configures all the UI behaviour of the subsequent execution. As a next step client creates the ExecutionService itself and calls run to execute the job. Run can be called multiple times. The output and input streams are presented in output tab. Additional processing and printing conversion can be configured in descriptor through interfaces described in following usecases.

The creation of the external process is supported by ExternalProcessBuilder to make things easier.

Processing the input

Client needs to process character data coming from stream, file or other source. This usecase should be solved by External Execution Base API.

To abstract the source of the data client must implement InputReader. To abstract the data processing client must implement InputProcessor or LineProcessor. For all three interfaces there are prepared common implementations (and bridge from character based to line based processing) at these three factory classes:

To configure additional functionality specific to org.openide.windows.OutputWriter see the next usecase.

Once the data source and processing objects are prepared client creates InputReaderTask. Factory methods of the InputReaderTask can create either common task exiting on interruption or cancellation or draining task which is trying to drain out all available data before exiting.

Printing the input

Client intends to process input lines and print them to org.openide.windows.OutputWriter. In addition printed lines should be transformed (converted) somehow and enriched by line listeners.

The both default printing processors provide factory method accepting LineConvertor. Namely InputProcessors.printing(org.openide.windows.OutputWriter out, LineConvertor convertor, boolean resetEnabled) and LineProcessors.printing(org.openide.windows.OutputWriter out, LineConvertor convertor, boolean resetEnabled). Convertor is then used to convert received lines to printed ones. Common convertors (file, http) are provided in factory class LineConvertors.

Custom process builder

Third party wants to implement custom process builder to provide additional functionality, such as remote execution. This usecase should be solved by External Execution Base API.

In order to do so it will implement ProcessBuilderImplementation and pass ProcessBuilder to its clients. The API instances are created with help of ProcessBuilderFactory.

Destroying a process

Client wants to destroy the process, trying to kill whole process tree. This usecase should be solved by External Execution Base API. Method ExternalProcessSupport.destroy(java.lang.Process process, Map<String,String> env) is designed for that. It will use a ProcessDestroyPerformer registered in default lookup to do so.

Extending startup environment

The third party plugin may want to be able provide additional arguments for the process startup in a standardized way. In order to do so it will register a implementation of StartupExtenderImplementation to the layer folder StartupExtender. The annotation StartupExtenderImplementation.Registration can be used for that.

The clients (for exmaple project or server) may query the extenders via the API class StartupExtender and use the additional arguments for the process.

Making certain open actions pluggable

Some default LineConvertors returned by LineConvertor needs to open file or URL. A bit special case is also options dialog opening required by ExecutionService to open options dialog specified by ExecutionDescriptor. To cover this three usecases in a pluggable way while keeping dependencies minimal there are three corresponding SPI classes one may implement. So there is FileOpenHandler to handle file opening, HttpOpenHandler to deal with HTTP URLs and OptionOpenHandler to open proper options dialog.


How to use J2EE DD API?

The project is based on the requirement to access all J2ee deployment descriptor files for other Netbeans modules in a simple and J2EE spec.-independant way. This module replaces the Web DD API (web/ddapi) module form the Web area.

J2EE Application

J2EE Aplications often need to explore the included modules. Ejb modules are usually used as components of a J2EE application. Web modules are usually used as clients or front-end components of J2EE application.
There is a requirement to be able to identify the sub-elements of web modules that are included to J2EE Application. For example, the J2EE Application need to be able to create a web module (WEB client), with the default web.xml file, then create a display-name and add a servlet element to deployment descriptor. Similarly, the J2EE Application need to be able to create an ejb module, with the default ejb-jar.xml file, then create a display-name and add an ejb element to deployment descriptor.

Web Services Based on Servlet

JAX-RPC Web Services based on servlet need to include specific elemens to deployment descriptor and map the service to a URL that specifies where the WSDL file can be found.
See the example (JWSDP1.2) :


<listener>
  <listener-class>com.sun.xml.rpc.server.http.JAXRPCContextListener</listener-class>
</listener>
<servlet>
  <servlet-name>Hello</servlet-name>
  <display-name>Hello</display-name>
  <description>JAX-RPC endpoint - Hello</description>
  <servlet-class>com.sun.xml.rpc.server.http.JAXRPCServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>Hello</servlet-name>
  <url-pattern>/hello</url-pattern>
</servlet-mapping>


Web Application Wizards

There are several wizards that need to insert elements to DD regarding the type of the wizard.
Examples :

DD Editor

DD Editor significantly improves DD editing in the way that user doesn't need to know the syntax of deployment descriptor file. It is desirable for DD Editor module to work with DD API interfaces instead of working with s2b beans directly (generated specifically for the particular version of DD). This method was used in previous versions of IDE.

Other modules that need to modify the deployment descriptor

This is the list of other possible clients of DD API : An example of this is adding EJB reference to allow the module to call an EJB in another EJB module.


How to use Java EE Metadata?

The project provides a generic framework for accessing Java EE metadata models.

Accessing metadata models

A module wishing to access Java EE metadata obtains a metadata model, which is encapsulated by the MetadataModel class. The client then implements a model action, represented by the MetadataModelAction class, and executes this action in the model context by calling the model's runReadAction() method:

    MetadataModel<SomeMetadata> model = // ...
    String result = model.runReadAction(new MetadataModelAction<SomeMetadata, String>() {
        public String run(SomeMetadata metadata) {
            // ... do something with metadata, e.g.
            // compute a String value
            return value;
        }
    }
   

The way to obtain the model itself, as well as the kinds of metadata encapsulated by MetadataModel is metadata and metadata provider-specific and is not addressed by this API.

Providing metadata models

A metadata provider first defines a root class describing the metadata, e.g., SomeMetadata. Then the provider implements the MetadataModelImplementation interface and creates a MetadataModel using MetadataModelFactory. Then the provider defines a way to return the model to its clients:

    private SomeMetadataModelImplementation modelImpl = new SomeMetadataModelImplementation();
    private MetadataModel<SomeMetadata> model = MetadataModelFactory.createMetadataModel(modelImpl);

    /**
     * Call this to retrieve the model of some metadata.
     */
    public MetadataModel<SomeMetadata> getSomeMetadataModel() {
        return model;
    }

    // ... 

    private class SomeMetadataModelImplementation implements MetadataModelImplementation<SomeMetadata> {

        // ...

    }
   

Providing multiple metadata models

A metadata provider might need to provide several kinds of metadata models at once. Furthermore, since there can be many models available or for backward compatibility reasons it might be impractical to provide a method for each of the models. In this case the provider may define a method like:

    public MetadataModel<T> getMetadataModel(Class<T> clazz) {
        // ...
    }
   

The types of Class which may be passed to the method is a part of the contract between the provider and its clients.


How to use Java EE Server Registry?

J2EE Server Module provides support for development of J2EE modules and framework for J2EE server management and for J2EE deployment in IDE.

Deployment API Compliant Server Plugin

A server that supports Deployment API can be integrated in IDE so that J2EE modules could be deployed to it from IDE. It will not support incremental deployment, start/stop server or JSP compilation.

In order to do this the plugin needs to add the server classes that implement Deployment API to classpath and to provide a layer file that will register the server in IDE (specifying URL, user name and password) and register a factory class from Deployment API. Beside that server plugin must also implement some other mandatory APIs.

Plugin for Server that does not support Deployment API

If a J2EE server does not support Deployment API still needs to be possible to implement a server plugin for it.

In this case the plugin needs to implement the Deployment API interfaces ( DeploymentFactory, DeploymentManager) and delegate to whetever interface the specific J2EE server provides. An example of this is the Tomcat5 plugin implemented in tomcatint/tomcat5 module, although it only supports deployment of web modules and it also supports some optional interfaces defined by J2EE Server Module in addition to the Deployment API.

Server Plugin mandatory APIs

Each server plugin is required to provide J2EE platform which devmodules may use beside else for obtaining compilation classpath.

Plugins must implement J2eePlatformImpl interface and register it via J2eePlatformFactory whose instance must be registered in the module layer file. Devmodules then may access the J2eePlatform interface via the Deployment utility class.

Server Plugin that implements optional APIs

In practice plugins will likely want to provide tighter integration with IDE that is specified in Deployment API. They can choose to provide any or all of the optional parts of plugin API: incremental deployment, JSP compilation, start/stop/debug server support and/or customized UI for server management.

In order to do this plugin needs to implement the additional interfaces and register their instances in module layer file and in netbeans-deployment.xml file (an additional config file with specified DTD).

Registration of various optional functionality is done via OptionalDeploymentManagerFactory.

The classes and/or interfaces related to each optional functionality are:

Devmodule integration

Implemetors of J2EE module support (web module, EJB module, J2EE Application, etc.) need to be able to provide UI to deploy or debug their modules on any J2EE server that has a corresponding plugin and supports given type of J2EE module. The deployment needs to work both for Deployment API based (full) deployment and incremental deployment (this needs to be transparent for the devmodules). Devmodules also need to provide UI for editing server specific configuration files existing in their sources. In addition to that, J2EE Application devmodule needs to communicate with devmodules representing J2EE module that constitute the application.

This is achieved by devmodules implementing the devmodules API. Typically this will be done by subclassing a support class in devmodules SPI but direct implementation of devmodules API should also be possible. The mechanism of discovery of devmodule implementation is highly dependent on how devmodules are represented in IDE (e.g. as projects or DataObjects) so this part of API is the least stable.

The API package provides abstractions of J2eeModule and a J2EEModuleContainer (a module that contains other modules, such as J2EE application). Two utility classes provide direct access to Deployment and to a JSPServletFinder. The SPI package contains utility classes for implementation of J2eeModule and J2eeModuleContainer.

Customization of Server Registry UI

Some products (JSC) requested to make it possible to replace the whole server registry UI.

Not supported in current version.

Retrieve data sources

Data sources created in the module and deployed on the server are accessed using J2eeModuleProvider methods. Some of the module's data source may be already also deployed on the server, in that case the client is responsible for the duplicity handling.

Retrieval from a server is done by a server plugin. Core part of the functionality is done by DatasourceManager implementation which is exposed from a server plugin through OptionalDeploymentManagerFactory.

Retrieval from a module is done with help of ConfigSupport and ConfigurationSupport implementations.

Create data source

Data sources are created in a module if they does not exist yet on a server or in a module itself. Data sources are stored in the server-specific format, only some common subset of attributes (e.g. JNDI name, username, url, ...) is provided by a creator.

Data source creation is done with help of ConfigSupport and ConfigurationSupport implementations. In case of conflict with existing data source, the first conflicting data source is passed to the thrown DatasourceAlreadyExistsException.

Deploy data source

Data sources stored in a module are deployed (registered) on a module's target server at the beginning of a module deployment.

Data sources stored in a module are retrived and passed to a DatasourceManager instance for deploying (registering) on the server.
All module data sources having a conflict with some existing server data source are passed to the thrown DatasourceAlreadyExistsException.


How to use Java Hints Test API?

XXX no answer for arch-what

XXX no answer for arch-usecases


How to use Java SE Projects?

Provides a project type for plain Java projects. J2SE projects can be created from scratch, or you can import existing Java source trees. Creates an Ant script letting you build the project (and subprojects), run it, debug it, run JUnit-format tests, and build Javadoc. GUI customizer permits easy customization of the most commonly needed project parameters. Provides code completion and other services for editing Java sources. Classpaths can include other projects, raw JARs, or configured libraries. Specific J2SE platforms may be configured.

Covered by UI specification and design document.


How to use Java Platform?

Many Java-based project types need to be able to configure the version and location of Java to be used when building and running the project. This API/SPI permits these platforms to be registered and queried, and any customizations made in an appropriate GUI and persisted to disk.

The API can be used by any code wishing to know the list of installed platforms and information about each one; typically this would be used by project type providers to implement a customizer dialog. The SPI is intended to be implemented by a few modules supply support for locating and introspecting installed platforms, for example a JDK setup wizard.


How to use Java Project Support?

Provides support infrastructure for projects working with the Java language.

Project type providers wishing to show Java packages in their logical views can use this SPI. Templates which are Java-centric can use it. Projects which wish to implement queries from the Java Support APIs can place implementations in their lookup and these will be delegated to automatically.


How to use Java Source?

XXX no answer for arch-what

XXX no answer for arch-usecases


How to use Java Source UI?

java.sourceui

XXX no answer for arch-usecases


How to use JUnit Tests?

The module makes creating, running and navigation between tests easier. (Actual test running is typically performed directly by a project type provider using Ant.)

The SPI allows to plug a project-type-specific implementation of JUnit support into NetBeans. The current NetBeans implementation only supports JUnit on J2SE project types. The SPI describes services provided by the custom JUnit support plugin.

The functionality to be plugged in comprises:

For navigation, the plugin defines mapping between source classes and the corresponding test classes (both directions). Thus it provides an additional information to the information provides by UnitTestForSourceQuery

For generation of test skeletons, the plugin actually defines the whole test skeleton generator - it generates one or more test files for a given source file.


How to use Keyring API?

XXX no answer for arch-what

XXX no answer for arch-usecases


How to use Lexer?

Lexer module provides token lists for various text inputs. Token lists can either be flat or they can form tree token hierarchies if any language embedding is present. Tokens

API Usecases

Obtaining of token hierarchy for various inputs.

The TokenHierarchy is an entry point into Lexer API and it represents the given input in terms of tokens.
    String text = "public void m() { }";
    TokenHierarchy hi = TokenHierarchy.create(text, JavaLanguage.description());

Token hierarchy for swing documents must be operated under read/write document's lock.
    document.readLock();
    try {
        TokenHierarchy hi = TokenHierarchy.get(document);
        ... // explore tokens etc.
    } finally {
        document.readUnlock();
    }

Obtaining and iterating token sequence over particular swing document from the given offset.

The tokens cover the whole document and it's possible to iterate either forward or backward.
Each token can contain language embedding that can also be explored by the token sequence. The language embedding covers the whole text of the token (there can be few characters skipped at the begining an end of the branch token).
    document.readLock();
    try {
        TokenHierarchy hi = TokenHierarchy.get(document);
        TokenSequence ts = hi.tokenSequence();
        // If necessary move ts to the requested offset
        ts.move(offset);
        while (ts.moveNext()) {
            Token t = ts.token();
            if (t.id() == ...) { ... }
            if (TokenUtilities.equals(t.text(), "mytext")) { ... }
            if (ts.offset() == ...) { ... }

            // Possibly retrieve embedded token sequence
            TokenSequence embedded = ts.embedded();
            if (embedded != null) { // Token has a valid language embedding
                ...
            }
        }
    } finally {
        document.readUnlock();
    }

Typical clients:

Using language path of the token sequence

For the given token sequence the client may check whether it's a top level token sequence in the token hierarchy or whether it's embedded at which level it's embedded and what are the parent languages.
Each token can contain language embedding that can also be explored by the token sequence. The language embedding covers the whole text of the token (there can be few characters skipped at the begining an end of the branch token).
    TokenSequence ts = ...
    LanguagePath lp = ts.languagePath();
    if (lp.size() > 1) { ... } // This is embedded token sequence
    if (lp.topLanguage() == JavaLanguage.description()) { ... } // top-level language of the token hierarchy
    String mimePath = lp.mimePath();
    Object setting-value = some-settings.getSetting(mimePath, setting-name);

Extra information about the input

The InputAttributes class may carry extra information about the text input on which the token hierarchy is being created. For example there can be information about the version of the language that the input represents and the lexer may be written to recognize multiple versions of the language. It should suffice to do the versioning through a simple integer:
public class MyLexer implements Lexer<MyTokenId> {
    
    private final int version;
    
    ...
    
    public MyLexer(LexerInput input, TokenFactory<MyTokenId> tokenFactory, Object state,
    LanguagePath languagePath, InputAttributes inputAttributes) {
        ...
        
        Integer ver = (inputAttributes != null)
                ? (Integer)inputAttributes.getValue(languagePath, "version")
                : null;
        this.version = (ver != null) ? ver.intValue() : 1; // Use version 1 if not specified explicitly
    }
    
    public Token<MyTokenId> nextToken() {
        ...
        if (recognized-assert-keyword) {
            return (version >= 4) { // "assert" recognized as keyword since version 4
                ? keyword(MyTokenId.ASSERT)
                : identifier();
        }
        ...
    }
    ...
}
The client will then use the following code:
    InputAttributes attrs = new InputAttributes();
    // The "true" means global value i.e. for any occurrence of the MyLanguage including embeddings
    attrs.setValue(MyLanguage.description(), "version", Integer.valueOf(3), true);
    TokenHierarchy hi = TokenHierarchy.create(text, false, SimpleLanguage.description(), null, attrs);
    ...

Filtering out unnecessary tokens

Filtering is only possible for immutable inputs (e.g. String or Reader).
    Set<MyTokenId> skipIds = EnumSet.of(MyTokenId.COMMENT, MyTokenId.WHITESPACE);
    TokenHierarchy tokenHierarchy = TokenHierarchy.create(inputText, false,
        MyLanguage.description(), skipIds, null);
    ...

Typical clients:

SPI Usecases

Providing language description and lexer.

Token ids should be defined as enums. For example org.netbeans.lib.lexer.test.simple.SimpleTokenId can be copied or the following example from org.netbeans.modules.lexer.editorbridge.calc.lang.CalcTokenId.
The static language() method returns the language describing the token ids.
public enum CalcTokenId implements TokenId {

    WHITESPACE(null, "whitespace"),
    SL_COMMENT(null, "comment"),
    ML_COMMENT(null, "comment"),
    E("e", "keyword"),
    PI("pi", "keyword"),
    IDENTIFIER(null, null),
    INT_LITERAL(null, "number"),
    FLOAT_LITERAL(null, "number"),
    PLUS("+", "operator"),
    MINUS("-", "operator"),
    STAR("*", "operator"),
    SLASH("/", "operator"),
    LPAREN("(", "separator"),
    RPAREN(")", "separator"),
    ERROR(null, "error"),
    ML_COMMENT_INCOMPLETE(null, "comment");


    private final String fixedText;

    private final String primaryCategory;

    private CalcTokenId(String fixedText, String primaryCategory) {
        this.fixedText = fixedText;
        this.primaryCategory = primaryCategory;
    }
    
    public String fixedText() {
        return fixedText;
    }

    public String primaryCategory() {
        return primaryCategory;
    }

    private static final Language<CalcTokenId> language = new LanguageHierarchy<CalcTokenId>() {
        @Override
        protected Collection<CalcTokenId> createTokenIds() {
            return EnumSet.allOf(CalcTokenId.class);
        }
        
        @Override
        protected Map<String,Collection<CalcTokenId>> createTokenCategories() {
            Map<String,Collection<CalcTokenId>> cats = new HashMap<String,Collection<CalcTokenId>>();

            // Incomplete literals 
            cats.put("incomplete", EnumSet.of(CalcTokenId.ML_COMMENT_INCOMPLETE));
            // Additional literals being a lexical error
            cats.put("error", EnumSet.of(CalcTokenId.ML_COMMENT_INCOMPLETE));
            
            return cats;
        }

        @Override
        protected Lexer<CalcTokenId> createLexer(LexerRestartInfo<CalcTokenId> info) {
            return new CalcLexer(info);
        }

        @Override
        protected String mimeType() {
            return "text/x-calc";
        }
        
    }.language();

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

}
Note that it is not needed to publish the underlying LanguageHierarchy extension.
Lexer example:
public final class CalcLexer implements Lexer<CalcTokenId> {

    private static final int EOF = LexerInput.EOF;

    private static final Map<String,CalcTokenId> keywords = new HashMap<String,CalcTokenId>();
    static {
        keywords.put(CalcTokenId.E.fixedText(), CalcTokenId.E);
        keywords.put(CalcTokenId.PI.fixedText(), CalcTokenId.PI);
    }
    
    private LexerInput input;
    
    private TokenFactory<CalcTokenId> tokenFactory;

    CalcLexer(LexerRestartInfo<CalcTokenId> info) {
        this.input = info.input();
        this.tokenFactory = info.tokenFactory();
        assert (info.state() == null); // passed argument always null
    }
    
    public Token<CalcTokenId> nextToken() {
        while (true) {
            int ch = input.read();
            switch (ch) {
                case '+':
                    return token(CalcTokenId.PLUS);

                case '-':
                    return token(CalcTokenId.MINUS);

                case '*':
                    return token(CalcTokenId.STAR);

                case '/':
                    switch (input.read()) {
                        case '/': // in single-line comment
                            while (true)
                                switch (input.read()) {
                                    case '\r': input.consumeNewline();
                                    case '\n':
                                    case EOF:
                                        return token(CalcTokenId.SL_COMMENT);
                                }
                        case '*': // in multi-line comment
                            while (true) {
                                ch = input.read();
                                while (ch == '*') {
                                    ch = input.read();
                                    if (ch == '/')
                                        return token(CalcTokenId.ML_COMMENT);
                                    else if (ch == EOF)
                                        return token(CalcTokenId.ML_COMMENT_INCOMPLETE);
                                }
                                if (ch == EOF)
                                    return token(CalcTokenId.ML_COMMENT_INCOMPLETE);
                            }
                    }
                    input.backup(1);
                    return token(CalcTokenId.SLASH);

                case '(':
                    return token(CalcTokenId.LPAREN);

                case ')':
                    return token(CalcTokenId.RPAREN);

                case '0': case '1': case '2': case '3': case '4':
                case '5': case '6': case '7': case '8': case '9':
                case '.':
                    return finishIntOrFloatLiteral(ch);

                case EOF:
                    return null;

                default:
                    if (Character.isWhitespace((char)ch)) {
                        ch = input.read();
                        while (ch != EOF && Character.isWhitespace((char)ch)) {
                            ch = input.read();
                        }
                        input.backup(1);
                        return token(CalcTokenId.WHITESPACE);
                    }

                    if (Character.isLetter((char)ch)) { // identifier or keyword
                        while (true) {
                            if (ch == EOF || !Character.isLetter((char)ch)) {
                                input.backup(1); // backup the extra char (or EOF)
                                // Check for keywords
                                CalcTokenId id = keywords.get(input.readText());
                                if (id == null) {
                                    id = CalcTokenId.IDENTIFIER;
                                }
                                return token(id);
                            }
                            ch = input.read(); // read next char
                        }
                    }

                    return token(CalcTokenId.ERROR);
            }
        }
    }

    public Object state() {
        return null;
    }

    private Token<CalcTokenId> finishIntOrFloatLiteral(int ch) {
        boolean floatLiteral = false;
        boolean inExponent = false;
        while (true) {
            switch (ch) {
                case '.':
                    if (floatLiteral) {
                        return token(CalcTokenId.FLOAT_LITERAL);
                    } else {
                        floatLiteral = true;
                    }
                    break;
                case '0': case '1': case '2': case '3': case '4':
                case '5': case '6': case '7': case '8': case '9':
                    break;
                case 'e': case 'E': // exponent part
                    if (inExponent) {
                        return token(CalcTokenId.FLOAT_LITERAL);
                    } else {
                        floatLiteral = true;
                        inExponent = true;
                    }
                    break;
                default:
                    input.backup(1);
                    return token(floatLiteral ? CalcTokenId.FLOAT_LITERAL
                            : CalcTokenId.INT_LITERAL);
            }
            ch = input.read();
        }
    }
    
    private Token<CalcTokenId> token(CalcTokenId id) {
        return (id.fixedText() != null)
            ? tokenFactory.getFlyweightToken(id, id.fixedText())
            : tokenFactory.createToken(id);
    }

}

The classes containing token ids and the language description should be part of an API. The lexer should only be part of the implementation.

Providing language embedding.

The embedding may be provided statically in the LanguageHierarchy.embedding() see e.g. org.netbeans.lib.lexer.test.simple.SimpleLanguage.

Or it may be provided dynamically through the xml layer by using a file in "Editors/language-mime-type/languagesEmbeddingMap" folder named by the token-id's name containing target mime-type and initial and ending skip lengths:

    <folder name="Editors">
        <folder name="text">
            <folder name="x-outer-language">
                <folder name="languagesEmbeddingMap">
                    <file name="WORD"><![CDATA[text/x-inner-language,1,2]]>
                    </file>
                </folder>
            </folder>
        </folder>
    </folder>

How to use Master Filesystem?

MasterFileSystems is just implementation of FileSystem provided in standalone module including implementation of URLMapper that resolves file protocol and is responsible for conversion from URL into FileObject and vice versa. Implementation just delegates to the other FileSystem implementations (LocalFileSystem, VCSFileSystem, ...) and playes the role of arbiter that controls instantiation and life cycle of provided FileObjects. MasterFileSystemAPI

MasterFileSystem is just implementation of FileSystem. There are no special use cases. FileObjects erlier returned from URLMapper or FileUtil.fromFile provided by LocalFileSystem or CvsFileSystem will be now provided by MasterFileSystem. There will be guaranteed that there won't be more instances of FileObject addressing one java.ioFile.

How to use NB JUnit?

Module contains NetBeans extension to JUnit.

Tests typically extends NbTestCase.


How to use Options Dialog and SPI?

This module contains implementation of Options Panel and simple SPI.

Register top level Options Panel

Client can install new panel to Options Dialog - see JavaDoc for OptionsCategory class.

Register panel to Advanced Options Panel

Client can install new panel to Advanced Options Panel - see JavaDoc for AdvancedOption class.


How to use Parsing API?

See Parsing API homepage for project requirements, motivation.

  1. Parsing API Client can always ask for parser result. This direct call has top level priority (stops all other requests). Its designed to support direct user to IDE interaction (like request for code completion) that have to be as fast as possible. Such type of task is called UserTask. This approach is used not only for parsing of file currently edited in Editor, but it supports Refactoring too.
  2. Parsing API Implementation listens on various changes in IDE (typing in the current document, cursor movements, switching of editor tabs, changes of classpath). These changes affects parse tree of the current document, and various visualisation features based on parser results (text coloring, hints, error stripe). Parsing API Client can register some tasks that should run when such change is done (Task). Implemementation of Parsing API than calls all such registerred tasks. These calls has lower priority than UserTasks, and they should not block user interaction with IDE (typing in editor).
  3. Parsing API defines how to recognize embedded languages. It should be possible to create snapshot of some file, call some recognizers that finds blocks of embedded languages and run different parsers for embedded blocks. It should be able to use the same parser for top level language and any embedded block of code written in the same language. Embedding recognizer can add some virtual code (code that does not exists in top level source) to the embedded block. There should be some support for translation of offsets between top level source and virtual source generated for embedded piece of code.

How to use Print?

Provides print functionality in NetBeans.

The typical client of Print module can be any tool to print custom data.

The simple way to enable printing for a custom data is:

If the data is a Swing component which extends javax.swing.JComponent and shown in a org.openide.windows.TopComponent, the key "print.printable" (PrintManager.PRINT_PRINTABLE) with value "Boolean.TRUE" in the component must be set as a client property. See example:

      public class MyComponent extends javax.swing.JComponent {
        public MyComponent() {
          ...
          putClientProperty("print.printable", Boolean.TRUE); // NOI18N
        }
        ...
      }

How to use Ant-Based Project Support?

Provides the basic infrastructure by which Ant-based projects can be created, read and write configuration parameters and properties from/to disk, satisfy common queries and interfaces, etc. See Javadoc and build system design document.

Mostly an SPI for use by project type providers to create the project type. Also includes a small API/SPI for other projects to find what Ant build steps are necessary to create a certain build product, for use in inter-project dependencies.

Ant project support faq:

How to use support for storing project properties?

Q: I'm creating a customizer (properties dialog) for my project type. I wan't to use the support for simple data types. What do I need to do?

You basicaly need to do two things. First create the representation of the project properties which can be used in the GUI. Second at some time convert the objects back to the ANT properties form and store them into the project.


How to use External Libraries?

Permits libraries to be defined, customized, and stored by the user for reuse in multiple projects. For example, a Java JAR library has a classpath (usually one JAR), and an optional source path and Javadoc path that may be used for development-time features.

Different technology support modules will supply definitions of different kinds of libraries, e.g. Java JARs, that may be reused in user projects. Modules may register library predefinitions to wrap libraries they bundle. Project type providers can refer to available libraries in customizer dialogs.


How to use Project API?

Provides a generic infrastructure for modelling projects. Documentation available in the Javadoc. The build system design overview describes the basic purpose of modelling projects.

The SPI should be used by modules defining particular project types, e.g. the J2SE project type. The API is to be used primarily by GUI infrastructure and some queries, though other module code may on occasion need to refer to the API.


How to use Project UI?

General user interface implementation for the project system. UI Specification

Needed for working with projects in the IDE.

API can be used to get list of information about recently opened projects in IDE. API provides project display name, icon and URL of project folder location. Listeners can be registered to learn about change of the list.


How to use Project UI API?

The module supplies the APIs for the basic, generic UI infrastructure for projects: list of opened projects, main project, basic project-sensitive actions, template wizards, etc.

The main use case is for project type providers to supply logical views and customizers for the project. Also for template providers to create project-aware file templates. Can also get a list of open projects, create different kinds of project-related actions, and select projects on disk.


How to use General Queries API?

General kinds of queries between modules. Queries are one way of solving the intermodule communication problem when it is necessary for some modules to obtain basic information about the system (e.g. whether a particular file is intended for version control) without needing direct dependencies on the module providing the answer (e.g. the project type which controls the file). Details are covered in the Javadoc.

Particular use cases are enumerated in the Javadoc for each query API. Usage consists of simple static method calls. Potentially a wide variety of modules could use these queries; implementations are typically registered by project type providers, though also by Java library and platform implementations.


How to use Refactoring API?

Refactoring module allows developer to do high level code transformations aka refactorings.

Refactoring module provides API for refactorings. The idea is that at least the most elementary set of refactorings should be available via an API, so that the refactorings could be invoked programmatically. This is particulary useful when creating more complex refactorings. These can then be composed from the primitive refactorings accessible via an API using delegation. As an example we can use a simple rename refactoring. When renaming a class in a J2SE environment, simple rename refactoring (which renames all occurrences of the class) is sufficient. However in a J2EE environment, renaming a class may require renaming of other classes to preserve the functionality of the application (e.g. synchrinized renaming a home and remote interface for an EJB). This could be achieved by creating a more complex rename refactoring composed of two simple rename refactorings (one for each class to be renamed).

When analyzing flow of various refactorings, we have found out that the steps in the flow are very common for all refactorings. The flow is as follows: To make the implementation of various refactorings consistent, the refactoring module provides an API and UI framework that allows these refactorings to be plugged in. This framework enforces the above flow. Using this framework (set of SPI and API) the refactoring implementor can focus purely on the things specific to that particular refactoring (specific pre-conditions checks, parameters checks, implementation of changes, etc.) and leave the functionality that is common for all refactorings (implementation of the flow) up to the framework.

It is quite common that some modules need to be able to affect the behavior of a refactoring. There are 4 typical use-cases when this is desirable:
  1. A module wants to implement refactoring features for their own elements. For instance Java Refactoring module wants to implement Refactoring for Java elements.
  2. A module wants to participate in existing refactoring. E.g. refactoring of java files requires refactoring of non-java files in J2EE area. When a code is refactored, these non-java files need to be refactored too. We can mention JSP files or deployment descriptors as an example.
  3. A module introduces some hidden relationships between several elements. E.g. a single logical EJB consists of several physical classes. When one of these classes are refactored, the other classes need to be refactored as well.
  4. A module generates some derived code into the guarded blocks. In such case it is desirable that the provider of the guarded block refactors the guarded code, since the refactoring module itself has no knowledge of where the guarded code comes from.
The refactoring module provides hooks for other modules - an SPI that allows other modules to participate in refactorings. The modules can participate on all refactoring phases from "preCheck" (checking preconditions), through "checkParameters" (checking validity of refactoring parameters) to "prepare" (collecting changes). Use-cases number 1), 2) and 3) are covered by the same SPI (interfaces RefactoringPluginFactory and RefactoringPlugin). The forth use-case (guarded blocks) are covered by a separate set of interfaces, since for this use-case the module does not need to participate in all refactoring phases. The refactoring framework itself automatically detects that a given change points to a code in guarded blocks and requests all registered guarded block providers to handle that situation.

The rest of this section provides simple orientational examples of API/SPI usage.

Refactoring API can be used for programmatical invocation of refactorings and for pluging ui for these refactorings in.

Refactoring API Example:

Intention: Programatically rename java filecom/company/Test.java to com/company/RenamedTest.java and update references.

  	FileObject fo = ...com/company/Test.java...
        RefactoringSession renameSession = RefactoringSession.create("Rename Class");
        refactoring = new RenameRefactoring(fo);
        Problem pre = refactoring.preCheck();
        if (pre!=null && pre.isFatal()) {
     	  //fatal problem in precheck
     	  return;
        }
        refactoring.setNewName("RenamedTest");
        Problem p = refactoring.prepare(renameSession);
        
        if (p!=null && p.isFatal()) {
     	  //fatal problem in precheck
     	  return;
        }
        
        renameSession.doRefactoring(true /* saveAll */);

Refactoring SPI permit other modules to plug into existing refactorings and allow them to participate. Client of SPI must implement factory class RefactoringPluginFactory and register this class into Lookup.

Refactoring SPI Example 1:

Intention: Create a plugin for RenameRefactoring, which will participate in existing refactoring (let say in java refactoring) and renames references in XML files.

//implementation of factory class
public class J2EERefactoringFactory implements RefactoringPluginFactory {
    
    public RefactoringPlugin createInstance(AbstractRefactoring refactoring) {
    
        if (refactoring instanceof RenameRefactoring) {
            //return our custom instance for RenameRefactoring
            if (wantToParticipate(refactoring.getRefactoredObject())
                return new J2EERenameRefactoringPlugin((RenameRefactoring) refactoring);
        }
        
        if (refactoring instanceof ... {
            ...
        }

        return null;
    }
    
}
It is necessary to register J2EERefactoringFactory in the lookup:
META-INF/services/org.netbeans.modules.refactoring.spi.RefactoringPluginFactory

and implement RefactoringPlugin interface:

//implementation of RefactoringPlugin
public class J2EERenameRefactoringPlugin implements RefactoringPlugin {
    
    private RenameRefactoring refactoring;
    
    public J2EERenameRefactoringPlugin(RenameRefactoring refactoring) { 
        this.refactoring = refactoring;
    }
 
    public Problem preCheck() {
        ...
    }
    
    public Problem checkParameters() {
        ...
    }
    
    public Problem fastCheckParameters() {
        ...
    }
    
    public void cancelRequest() {
        ...
    }
    
    public Problem prepare(RefactoringElementsBag refactoringElements) {
        RenameRefactoring renameRefactor = ((RenameRefactoring)refactoring);
        Object element = renameRefactor.getRefactoredObject();
        if (...) {
           ...
           //lets add our RefactoringElements for usages found in XML files 
           refactoringElements.add(refactoring, new XMLRenameRefactoringElement());
        }
        return null;
    }

    public class XMLRenameRefactoringElement implements RefactoringElementImplementation {

        public void performChange() {
            //do change
        }
    }
Refactoring SPI Example 2: Intention: Create a module, which will add Rename... to html files First you must create your ActionsImplementationProvider:
public class MyProvider extends ActionsImplementationProvider {
    
  public boolean canRename(Lookup lookup) {
    Node[] nodes = lookup.lookupAll(Node.class);
    if (..one node selected and the node belongs to html...)
      return true;
    else 
      return fals;
 }

  public void doRename(Lookup selectedNodes) {
    Node[] nodes = lookup.lookupAll(Node.class);
    final FileObject fo = getFileFromNode(nodes[0]);
    return new Runnable() {
      public void run() {
        UI.openRefactoringUI(new RenameRefactoringUI(fo);
      }
    }    
  }
}
And of course your own RefactoringPlugin and RefactoringPluginFactory see Refactoring SPI Example 1 and Refactoring SPI Example 2
Refactoring SPI Example 3 Module wants to implement it's own refactoring preview tree: Register your own TreeElementFactoryImplementation into META-INF/services if you want to build your own RefactoringPreview tree. For instance Java Refactoring understand Java - specific objects e.g. Projects, Groups, Methods etc.
public TreeElement getTreeElement(Object o) {
.
.
if (o instanceof SourceGroup) {
  return new SourceGroupTreeElement((SourceGroup)o);
} else if (o instanceof SomethingFromJava) {
   return new SomethingFromJavaTreeElement((SomethingFromJava) o);
}
TreeElement is then displayed in refactoring preview panel.


Other usecases are docummented in javadoc.

How to use Java Refactoring?

XXX no answer for arch-what

XXX no answer for arch-usecases


How to use Sampler API?

It allows NetBeans Platform developer to self-sample their application, which should provide them with a valuable information about CPU performance problems.

User controlled sampling

There needs to be a simple API for someone who wants to create simple user action which starts and stops self-sampling and presents user with sampled results.

The correct way to achieve this is to call Sampler.createManualSampler, followed by Sampler.start() and Sampler.stop().

Sampling of the slow operation

Second major use-case of the Sampling API is sampling of the slow operation.

The correct way to achieve this is to call Sampler.createSampler(), followed by Sampler.start() and Sampler.stopAndWriteTo(DataOutputStream dos).


How to use Command Line Parsing API?

GetOpts like infrastructure to parse command line arguments with the cooperative participation of various modules.

Just Parse the Command Line

There needs to be a simple API for someone who has an array of strings and wants to parse them. One does not need to search for providers, just ask the infrastructure to do the parse and get the result.

The correct way to achieve this is to call CommandLine.getDefault().process(args).

Parse the Command Line with Own Options

Since version 2.20 one can define own classes with fields and annotate them with @Arg annotation. Those classes can then be passed into a factory method that creates new command line. One can then process the arguments as many times as needed via the process method. Example:
public final class MyOption implements Runnable {
  @Arg(longName="hello")
  public String name;

  public void run() {
    System.out.println("Hello " + name + "!");
  }
  
  public static void main(String... args) {
    CommandLine line = CommandLine.create(MyOption.class);
    line.process(args);
  }
}

If the above main class is called with parameters --hello World it will print out Hello World!.

Short and Long options with or without an argument

The standard getopts supports short form of options - e.g. a dash followed with one letter - or long form using two dashes followed with a word. Moreover the long form is optimized for abbrevations. If there are no conflicts between multiple options, then one can only use double dash followed with a prefix of a long option.

When using the declarative annotation style one can always specify @Arg(longName="text", shortName='t'). The longName attribute is required, but if there is supposed to be no long version of the argument, it can be set to empty string.

One can create an Option by calling any of its factory methods (like withoutArgument) and provider char for the one letter option and/or string for the long getopts option.

Options with or without an argument

There are three types of options. Those without an argument, those with a required one and those with optional one. Each one can be created by appropriate factory method in the Option class.

When using the declarative annotation style one needs to annotate a field of type boolean to create an option without an argument.

Support for --

The getopts compliant command line parsers support --. If these characters do appear on the command line, the rest of it is treated as extra arguments and not processed. The sendopts infrastructure supports this as well.

Multiple Independent CLI Handlers

The handlers for the options need not know about each other and still have to be able to process the command line successfully. Any module which wishes to provide its own options can register its OptionProcessor with @ServiceProvider annotation. Alternatively the module can use the @Arg annotation of its fields and it will be registered as well.

Extensible Options Set

Q: How shall one write an OptionProcessor that recognizes set of basic options, however contains one open slot? The processor wants other modules to provide recognizers for that slot and wants to communicate with them. For example, by default the processor recognizes option --channel <name_of_the_channel> which describes a source of data, and stores such data into a sink. There can be multiple sinks - discard the output, save it to file, show it on stdout, stream it to network. The processor itself can handle the copying of data, but does not itself know all the possible sink types.

To implement OptionProcessor like this one shall define an additional interface to communicate with the sink providers:

   package my.module;
   public interface SinkProvider {
     /** gets the option (even composite) that this sink needs on command line */
     public Option getOption();

     /** processes the options and creates a "sink" */
     public OutputStream createSink(Env env, Map<Option,String[]> values) throws CommandException;
   }
       

Other modules would then registered implementations of this interface in the META-INF/services/my.module.SinkProvider files. The OptionProcessor itself would just look all the implementations up, queried for the sinks, and then did the copying:

   class CopyingProvider extends OptionProvider {
     public Option getOption() {
        List<Option> l = ...;
        for (SinkProvider sp : Lookup.getDefault().lookupAll(SinkProvider.class)) {
          l.add(sp.getOption());
        }

        // we need only one provider to be present
        Option oneOfSinks = OptionGroups.oneOf(l.toArray(new Option[0]));

        // our channel option
        Option channel = ...;

        // the channel option needs to be present as well as a sink
        return OptionGroups.allOf(channel, oneOfSinks);
     }

     public void process(Env env, Map<Option,String[]> values) throws CommandException {
        OutputStream os = null;
        for (SinkProvider sp : Lookup.getDefault().lookupAll(SinkProvider.class)) {
          if (values.containsKey(sp.getOption())) {
            os = sp.createSink(env, values);
            break;
          }
        }
        if (os == null) {
          throw CommandException.exitCode(2);
        }

        // process the channel option and
        // handle the copying to the sink os
     }
   }
       

Another possible approach how to allow sharing of one option between multiple modules is to expose the option definition and its handling code as an interface to other modules, and then let the modules to write their own OptionProcessors. Necessary condition is that each of the processor is uniquely identified by some additional option, so when the shared option appears the infrastructure knows which processor to delegate to. This is demonstrated in the SharedOptionTest which basically does the following:

   /** the shared option, part of an interface of some module */
   public static final Option SHARED = ...;
   /** finds value(s) associated with the SHARED option and 
   * creates a JPanel based on them */
   public static JPanel getSharedPanel(Map<Option,String[]> args) { ... }
       

Then each module who wishes to reuse the SHARED option and the factory method that knows how to process their values for their own processing can just:

  public static final class ShowDialog extends OptionProcessor {
    private static final Option DIALOG = Option.withoutArgument('d', "dialog");

    protected Set<Option> getOptions() {
        // the following says that this processor should be invoked
        // everytime --dialog appears on command line, if the SHARED
        // option is there, then this processor wants to consume it 
        // as well...
        return Collections.singleton(Option.allOf(DIALOG, Option.anyOf(SHARED)));
    }

    protected void process(Env env, Map<Option, String[]> optionValues) throws CommandException {
        JPanel p = getSharedPanel(optionvalues);
        if (p == null) {
           // show empty dialog
        } else {
           // show some dialog containing the panel p
        }
    }
  }
       

The other modules are then free to write other processors refering to SHARED, for example one can write ShowFrame that does the same, just shows the panel in a frame, etc. The infrastructure guarantees that the exactly one provider which matches the command line options is called.

Printing Full Help Text

Althrough the handlers are provided by independent parties, it must be possible to generate resonable and consistent help description from all of them, so for the end user it appears as well formated and easily understandable. That is why every option can be associated with a short description providing info about what it is useful for using Option.shortDescription method. When using the @Arg style, there is an additional @Description annotation which can be used to declaratively associate a localized display name and short description with the option. To get such descriptions for all available options one can use CommandLine.getDefault().usage(java.io.PrintWriter).

Finding and Reporting when Options Are Not Correct

In case the command line cannot be processed a clean error for programmatic consumation and also one that can be shown to the end user of the command line must be given. This is handled by throwing CommandException with appropriate message description and exit code.

Processing Extra Command Line Arguments

There can be non-option arguments in the command line and they can freely mix with the option ones. For example the getopts would treat the following command line arguments as the same:
       --open X.java Y.java Z.txt
       X.java Y.java --open Z.txt
       
if the option open handles extra arguments. The sendopts infrastructure must distinquish between them and pass the non-option ones to the only one handler (active because it processed an option) that knowns how to parse them. It is an error if more than one or no handler expresses an interest in extra arguments and those are given. One can register such option by using the Option.additionalArgument factory method.

When using the declarative annotation style one may annotate a field of type String[] which then means this field should be filled with all additional arguments.

Handling Input and Output

Handler's shall not use the input and output streams directly for their execution, they should rely on the framework provided ones. This allows NetBeans based application to transfer the I/O from second started instance to the master one which is already running. From the client side there is the CommandLine.getDefault().parse methods taking additional arguments like input and output streams. This gets transfered to providers as an Env argument of their methods.

Returning Exit Code

When Handler's get execute (in the order defined by the order of options on the command line), each of them can either execute successfully, or fail. If a handler succeeds, next one is executed, if it fails, the execution is terminated and its return code is returned to the caller. The error can be notified by creating and throwing CommandException.exitCode(int errorCode).

Processing Only Extra Command Line Arguments

Sometimes it is desirable to process non-option arguments like file names without providing any option. Handlers can declare interest in such arguments. It is an error if such non-options are provided and no or more than one handler is around to handle them. One can create such option by using Option.defaultArguments factory method. With the declarative annotation style one can annotate a field of type String[] and specify that it is supposed to be implicit.

Only those processor need to process the options are created

For purposes of usage in NetBeans, it is needed to not-initialize those handlers that are not really needed to process certain command line. The infrastructure decides which of them are going to be needed and instantiates only those. This is supported only when using the declarative annotation style - information about these options is recorded in declarative way and the system can decide without loading the provider classes whether they are present on the command line or not.

Complex Option Relations

Certain CLI processors may need more than one option before they can process the input. For example it is necesary to tune the radio and then also tell what to do with the output. It is unconvenient to process that as one option with argument(s), that is why one can use the OptionGroups.allOf, OptionGroups.someOf, for example like:
class PP extends OptionProcessor {
    private static Option tune = Option.requiredArgument(Option.NO_SHORT_NAME, "tune");
    private static Option stream = Option.requiredArgument(Option.NO_SHORT_NAME, "stream");
    
    public Set<Option> getOptions() {
      return Collections.singleton(
        OptionGroups.allOf(tune, stream)
      );
    }
    
    public void process(Env env, Map>Option,String[]> values) throws CommandException {
        String freq = values.get(tune)[0];
        String output = values.get(stream)[0];

        // XXX handle what is needed here
    }
}
When the two options are registered and command line like --tune 91.9 --stream radio1.mp3 is being processed, the PP's process method is going to get called with values 91.9 and radio1.mp3.

This kind of grouping is not currently supported with the declarative annotation style registration.

Alternative Options

Sometimes there may different ways to specify the same option and just one of them or none of them can be provided at given time. For example is there is a way to tune the radio with direct frequency or with name of the station. Just one can be provided and one is needed. This can be specified by using OptionGroups.oneOf factory methods:
Option freq = Option.requiredArgument(Option.NO_SHORT_NAME, "tune");
Option station = Option.requiredArgument(Option.NO_SHORT_NAME, "station");
Option tune = OptionGroups.oneOf(freq, station);    
The option tune then signals that just one of the station or freq options can appear and that they both are replaceable.


How to use Common Server?

Allows UI presentation of server instance without dependency on a server specific API (like j2eeserver).

Registering the server/cloud instance provider

An external module can register itself as the server instance provider. In order to do that it must register the implementation of ServerInstanceProvider in Servers or Cloud folder in the layer.xml.

When this is done the module will handle displaying of instances at appropriate IDE dialogs and views. Note that more specific SPIs can still be required for the technology specific dialogs and actions. This module covers the areas where the "common server" term makes sence.

Every ServerInstance returned by the provider is handled by this module. Some features of the ServerInstance are not mandatory (as described in javadoc). If new instances can be added or removed during the lifecycle of external module it has to notify all listeners of the ServerInstanceProvider.

Registering the server/cloud wizard

An external module can register the wizard(s) in order to allow the user to add new instances. In order to do that it must register the implementation of ServerWizardProvider in Servers or Cloud folder in the layer.xml.

When this is done the module will offer this wizard in UI (at contexts where it makes sense).

Persisting instance properties

The Commons Server SPI implemetor has to usually implement persistence of its instances somehow. There are many ways how this can be done. To make it easier InstancePropertiesManager can be used. It provides a way how to store and retrieve properties of the server instance.


How to use UI Gestures Collector Infrastructure?

XXX no answer for arch-what

Gather information about UI gestures

Primary purpose of this module is collect information about the user actions that take place in the running NetBeans based application.

The info about various UI events in the system is collected thru listening on log records send to Logger.getLogger(UI_LOGGER_NAME_VALUE) , where UI_LOGGER_NAME_VALUE is a value of UI_LOGGER_NAME resource bundle key, defining the name of the UI usage logger. Any code in the system can get instance of this logger or any child logger and send useful informations to it. At the end of the session the last few hundereds events is taken and displayed to the user for further processing. The info about various UI events in the system is collected thru listening on log records send to Logger.getLogger(METRICS_LOGGER_NAME_VALUE) , where METRICS_LOGGER_NAME_VALUE is a value of METRICS_LOGGER_NAME resource bundle key, defining the name of the metrics logger. Any code in the system can get instance of this logger or any child logger and send useful informations to it. At the end of the session the last few hundereds events is taken and displayed to the user for further processing.

Presenting usage statistics

Important part of the behaviour of this module is the ability to cooperate with information analyzing tools and present their results. This is done thru special HTTP contracts, where the module reads and understands various server responses and is able to open browser after submitting data to analysis.

There is a key in the org.netbeans.modules.uihandler.Bundle that specifies the location of the page on a server one shall query and display to the user when the module is about the submit usage data for analysis. There is a key in the org.netbeans.modules.uihandler.Bundle that specifies the location of the page on a server one shall query and display to the user when the module is about the submit metrics data for analysis. There is a key in the org.netbeans.modules.uihandler.Bundle that specifies the location of the page on a server one shall query and display to the user when the module is about the submit an error report. The page pointed by WELCOME_URL can contain any XHTML text, but it also should contain a <form/> tag that defines <input type="hidden" name="submit" value="localizedName"/>. The localizedName is then going to be used for a button for the dialog displaying the summary. When this button is invoked, the "action" URL is then feed with data from the UI logs. The server is then supposed to process the data, create some analytics pages and return them back to the client. If the returned page contains tag like <meta http-equiv='Refresh' content='3; URL=somepage'> an (external) browser is opened with the specified URL and the user can then interact directly with the server, thru pages it serves. For testing purposes one can specify different URL for upload of files, by setting org.netbeans.modules.uihandler.Submit property when invoking NetBeans.

Adding own UI gestures

The base module is in fact just an infrastructure which collects data about UI gestures, but the actual gestures need to be delivered to it somehow. Here is the description of the ways how one can extend own modules to cooperate with this UI gestures infrastructure.

To feed own data about special UI gestures one can just create own Logger.getLogger(UI_LOGGER_NAME_VALUE+".ownname") and send own log records to it. UI_LOGGER_NAME_VALUE is a value of UI_LOGGER_NAME resource bundle key, defining the name of the logger. The format of the log messages shall follow the one described by the structured logging document, e.g. the LogRecord shall have associated ResourceBundle and the record's getMessage shall point to a key in that bundle. there is an extension to the regular formatting done by the logging formatter that, in order to achieve nicer appearance to the user, allows each record to be associated with an icon. Just define MSG_KEY_ICON_BASE in the bundle associated with the LogRecord (where the MSG_KEY is the string returned by record.getMessage()) and the value is then going to be used for the Node representing the UI gesture.

Sometimes direct logging may not be possible. For example for performance data it might be meaningful to collect the information over a longer time period and only at the end output some statistics. This is supported as well. Just implement and register one of the interfaces from the API of this module and properly register them and the implementation will be called when the logger module is activated or when the user finishes the work with the application. In order to keep dependencies clean, it is strongly adviced to make modules that implement this API eager, so they get enabled as soon as the UI logger module is enabled.

These usecases are realized as described in here in provided UI specification.


How to use Versioning?

The module allows SCM systems to fully integrate into the IDE workflow.

Main and Popup Menu usecases come from the UI spec available here: Versioning UI spec

Main Menu Itegration

All installed SCM systems must cooperate while constructing popup and main menus, see UI spec.

Popup Menu Itegration

All installed SCM systems must cooperate while constructing popup and main menus, see UI spec.

Coloring and Badging (annotations)

An SCM system needs a way to annotate labels and icons in the IDE.

Automated Versioning

To enable automated versioning (adds, removes, moves, delets), a SCM system needs to integrate at the lowest level into the IDE's filesystem layer. Refactoring is the most critical filesystem client here.


How to use Versioning Core?

XXX no answer for arch-what

Main and Popup Menu usecases come from the UI spec available here: Versioning UI spec

Main Menu Itegration

All installed SCM systems must cooperate while constructing popup and main menus, see UI spec.

Popup Menu Itegration

All installed SCM systems must cooperate while constructing popup and main menus, see UI spec.

Coloring and Badging (annotations)

An SCM system needs a way to annotate labels and icons in the IDE.

Automated Versioning

To enable automated versioning (adds, removes, moves, delets), a SCM system needs to integrate at the lowest level into the IDE's filesystem layer. Refactoring is the most critical filesystem client here.


How to use Extensible Abstract Model (XAM)?

The xam module (XAM Module) provides a framework for domain model developers to use when creating new models. This framework was started to encapsulate common practices used when creating XML based models for XML schema and WSDL. List of the main features: Definition and partial implementation of both a generic and XML specific model. The model supports eventing, Undo/Redo, sync, and simple transactions. XML based models extend generic models and add support for resolution.

domain model developer

A domain model developer would determine the appropriate extension package. A model outside of XML would extend org.netbeans.modules.xml.xam.AbstractModel, and have the components in the domain extend org.netbeans.modules.xml.xam.AbstractComponent. The org.netbeans.modules.xml.xam.AbstractFactory can also be used for creation of models. The factory provides the creational, the model provides the entry point into the domain model as well as a concrete reference point to register for events. The component serves as the root of the domain level objects. This provides some consistency across models as the original intention was to be able to provide a unified model across different XML vocabularies. An XML model developer would likely want to start using the XDM model which provides the full fidelty XML document model. This is in the xml/xdm module (described seperately). The XML module developer would also incorporate the facilities for reading and writing to a catalog. This is incorporated into methods available to subclasses in the xam.dom and xdm.xam models. The project based catalog facility provides the ability to support versioned catalog files which allow local access but URL based location attributes.


How to use XML Document Model (XDM)?

The XDM module provides a basis for tool ready XML language models that require full document fidelity, undo/redo, and the ability to sync with the underlying source. List of the main features: Support for full document fidelity. The users text including spacing and comments are preserved. Undo / Redo is supported using the concept of an immutable tree. XDM nodes do not have parent pointers (only a pointer to the model). Thus a node can be in multiple trees, where each tree is a version. When a mutation to the tree occurs a clone is made of each node in the parent path from the root to the mutated node. All unchanged nodes are simply referenced and thus will live in multiple trees. Thus an undo / redo is simply a reference change. The cost of storing multiple tree is minimized as only the diffs are stored in each version of the tree. The visitor pattern is used in addition to the DOM interfaces which allows easier tree walking An XML diff visitor supports XML difference. Element identity can be supplied by the client.

The typical client of XDM would be a tool author supporting an XML language who wants to provide a custom client API. A concrete example of this is the XML Schema model. The XML Schema model starts by subclassing AbstractXDMModel and providing the component updater, which is called in conjunction with sync to mutate the model according to changes in the underlying source.

WSDL model

The WSDL model is based on the XDM model and relies on the XDM capabilities to provide the infrastructure necessary for providing a XAM based model.

Schema model

The Schema model is based on the XDM model and relies on the XDM capabilities to provide the infrastructure necessary for providing a XAM based model.

BPEL model

The BPEL model is based on the XDM model and relies on the XDM capabilities to provide the infrastructure necessary for providing a XAM based model. The XDM model can be used in standalone mode.

BaseDocument sd = ...;
Lookup lookup = Lookups.singleton(sd);
// create an editable ModelSource with base document
// in the lookup (this is required)
ModelSource ms = new ModelSource(lookup, true);
// create an XDMModel
XDMModel model = new XDMModel(ms);
// sync the XDM model with the underlying source
model.sync();
// create customer element, same as dom
Element customer = model.getDocument().createElement("customer");
// add to the model as 0th child of employee element, not shown
model.add(employee,customer,0);


How to use Debugger Core - UI?

The debuggercore module (Debugger Core UI) contains shared UI components for all debugger implementations, and defines some SPI for sharing of them.

UseCase I. - Install and use CPP debugger plug-in to NetBeans + Java Debugger.

CPP debugger plug-in installs support for debugging of some new language to the NetBeans IDE, and some new debugging engine. This implementation of debugger should share UI components (actions, Debugger Views, ...) with default NB Java Debugger. It should share basic debugger model too - notion of current context, current session, thread, call stack line, ...

CPP debugger plug-in installs:

UseCase II. - Install and use JSP debugger plug-in to NetBeans + Java Debugger.

JSP debugger plug-in installs support for debugging of some new language to the NetBeans Java Debugger. It does not contain a new debugger engine, but it delegates to standard NB Java debugger. So it does not depends on Debugger Core API only, but it depends on JavaDebugger API too.

JSP debugger plug-in installs:

UseCase III. - Install and use J2EE debugger plug-in to NetBeans + Java Debugger.

J2EE debugger plug-in installs some enhancements to the standard Java Debugger. It does not contain a new debugger engine or language support. So it does not depends on Debugger Core API only, but it depends on JavaDebugger API too.

J2EE debugger plug-in installs:

UseCase IV. - Install and use DBX debugger plug-in to NetBeans.

DBX debugger plug-in installs support for debugging of some new language (CPP) to the NetBeans IDE, and some new debugging engine. But it contains debugger engine for Java debugging too. DBX debugger engine has its own session management (or will have in the next versions). One debugger engine can manage more than one sessions. One engine supports debugging in more than one language.

UseCase V. - Implement Debugger Core UI module on top of Debugger Core API / SPI.

Debugger Core UI needs:


How to use Editor Hints?

XXX no answer.

redunderline

Assume that you have a module using e.g. Parsing API to parse the source files and wants to mark the errors in the editor to be shown as red underlined in the editor. Here is the pseudo code that achieves this:
Document doc = ...;
ArrayList<ErrorDescription> errors = new ArrayList<ErrorDescription>();
for (<all errors from the parser that have parsed the doc>) {
    errors.add(
        ErrorDescriptionFactory.createErrorDescription(
            Severity.ERROR,
            d.getMessage(Locale.getDefault()),
            doc,
            doc.createPosition(start),
            doc.createPosition(end)
        )
    );
}
HintsController.setErrors(doc, "myerrors", errors);

warningwithfix

Adding a warning with fixes:
static final class FixImpl implements Fix {
...
}
...
Document doc = ...;
List<Fix> fixes = Arrays.<Fix>asList(new FixImpl(...));
ArrayList<ErrorDescription> warnings = new ArrayList<ErrorDescription>();
for (<all places where the warning should be displayed>) {
    warnings.add(
        ErrorDescriptionFactory.createErrorDescription(
            Severity.WARNING,
            displayName,
            fixes,
            doc,
            doc.createPosition(start),
            doc.createPosition(end)
        )
    );
}
HintsController.setErrors(doc, "mywarnings", warnings);


How to use Java Hints SPI?

XXX no answer for arch-what

Creating a new Java Hint

Simple way to create a new Java hint is as follows:
Tips:

Creating a new Java Hint Without a Class

For simple hints, it is possible to annotate the hint method with the @Hint annotation. The hint then consists of this sole method. Any number of such hints may be created in a single class.

Creating a Tests for the Newly Created Java Hint

Creating automated tests for the hints is simple: create a test class, and use HintTest to setup the test, run the hint and verify that its outcomes are correct. The tests automatically run with test branding, so create Bundle_test.properties, and add bundle keys into it for ErrorDescription and Fix display names, to isolate the test from changes in the production Bundle.properties.

Adding options to a Java Hint

To add a simple boolean option to your hint, use @BooleanOption.


How to use Navigator API?

Navigator module is a base API module which provides: A place for modules to show structure/outline of their documents Ability for modules to show their view only when special document(node) is active in the system UI for switching between multiple views available for currently active document(node) Coalescing of fast coming selected node changes to show content for

Basic Usage Steps

In order to plug in a view into Navigator UI for certain document (data) type, module writers need to write a NavigatorPanel implementation marked with @Registration.

Writing NavigatorPanel implementation

Implementing NavigatorPanel interface is easy, you can copy from template basic implementation BasicNavPanelImpl.java.

Advices on important part of panel implementation:

Registering NavigatorPanel impl

Declarative registration of your NavigatorPanel impl connects this implementation with specific content type, which is type of the document, expressed in mime-type syntax, for example 'text/x-java' for java sources. Infrastructure will automatically load and show your NavigatorPanel impl in UI, when currently activated Node is backed by primary FileObject whose FileObject.getMimeType() equals to content type specified in your registering annotation (see more options below).

Advanced Content Registration - Linking to Node's Lookup

There may be situations where linking between your Navigator view and activated Node's primary FileObject is not enough or not possible at all. This simply happens when the data you want to represent in Navigator are not accessible through primary FileObject or DataObject. Usual example is Multiview environment, where more views of one document exists.

The solution is to bind content of your Navigator view directly to your TopComponent. Then, whenever your TopComponent gets activated in the system, Navigator UI will show th content you connected to it.

Steps to do:

Programmatic activation of NavigatorPanel

Programmatic activation of specific navigator panel activates and shows navigator panel in navigation area, as if user had selected the panel manually. API clients are expected to use programmatic activation to activate/select preferred panel from a set of available panels.

Example: Several TopComponents in multiview arrangement, TopComponentA and TopComponentB. Both components provide the same NavigatorLookupHint impl, which is recognized by two providers NavigatorPanelA and NavigatorPanelB. Now when TopComponentA becomes activated (has a focus), it's desirable to select/show NavigatorPanelA from navigator panels. On the other side, when TopComponentB is activated, NavigatorPanelB should be activated automatically.

Steps to do to activate panel programmatically:

Setting activated node of Navigator window

Sometimes clients need to alter activated Nodes of Navigator window, to better represent Navigator area content within the whole application. See TopComponent.getActivatedNodes() and TopComponent.Registry.html#getActivatedNodes() to find out what activated nodes of TopComponent and whole system mean.

Use Case Example: NavigatorPanel implementation shows list or tree of some Nodes in Navigator area. When user selects a Node in the list or tree, it is desirable to show selected Node's properties in Properties window and enable proper actions in main menu. Exactly this can be done by presenting Node selected in the list/tree as activated Node of Navigator window.

Steps to specify activated Nodes of Navigator window:

Adding UndoRedo support to the navigation view

Some complex navigation views need support for undoing and redoing edit changes done either directly in the view or in document which the view is representing.

Steps to support undo and redo in navigation view:

Removing active Node/DataObject related NavigatorPanels from Navigator window

In certain situations it's not desired to show NavigatorPanel implementations related to DataObject of active Node in Navigator window. Typically you need to have active Node of some type, so that actions in the system works properly. But you don't want to show NavigatorPanels that "come" with such active Node.

Steps to remove such NavigatorPanels:

Integration of Explorer view into Navigator

Explorer views comes handy when showing Nodes in varienty of situations and it is just natural to be able to integrate them into Navigator window. Working with explorer views is described at ExplorerUtils javadoc. Integration with Navigator is easy and there are only subtle differencies from integration into TopComponent.

Steps to integrate some kind of Explorer View into Navigator:

How to use Common Palette?

The project implements a new component palette that will be reused by other projects. The new palette should provide a common look and feel for Form editor, Mobility, J2EE and possible other modules as well. UI draft specification is available at http://ui.netbeans.org/docs/ui/palette/index.html

Palette Content

The Common Palette content is a two-level hierarchy. The top-most level are Categories, the Category children are Items. It's possible to select (highlight) items in the palette panel using a mouse or keyboard and then inserted/dropped into an editor that supports the palette.

The palette content can come from two different sources:

Basic usage

The following steps must be taken if a module wants to define its own palette content as a hierarchy of folders and files in its XML layer:

When an item is selected in the palette and user clicks into the editor window then the module can ask for selected item by calling PaletteController.getSelectedItem(). This method returns a Lookup that holds object(s) representing the selected item. After the item is inserted into the editor window the module may clear palette's selection (PaletteController.clearSelection()) or leave the item selected to implement 'multi drop' insertion scenario.

Filtering

It is possible to filter palette content and hide some categories and/or items from the user by extending PaletteFilter class.

       class MyPaletteFilter extends PaletteFilter {

            public boolean isValidItem(Lookup lookup) {
                Node itemNode = (Node)lookup.lookup( Node.class );
                return isItemVisibleInCurrentEditorContext( itemNode );
            }

            public boolean isValidCategory(Lookup lookup) {
                Node categoryNode = (Node)lookup.lookup( Node.class );
                return isCategoryVisibleInCurrentEditorContext( categoryNode );
            }

            private boolean isItemVisibleInCurrentEditorContext( Node item ) {
                boolean res = true;
                //check current cursor positions and/or item type and decide whether
                //the item is valid, i.e. can be selected and dropped into editor
                return res;
            }

            private boolean isCategoryVisibleInCurrentEditorContext( Node item ) {
                boolean res = true;
                //check current cursor positions and/or category type and decide whether
                //the category is valid, i.e. its items can be selected and dropped into editor
                return res;
            }
          

Then initialize the palette using the following method:

                MyPaletteFilter filter = new MyPaletteFilter();
                PaletteController controller = PaletteFactory.createPalette( "MyPalette", new MyPaletteActions(), filter, null );
          

It is necessary to call PaletteController.refresh() to refresh and repaint the palette window whenever the filtering condition has changed:

              myPaletteFilter.setShowSomeSpecialCategories( false );
              paletteController.refresh();
          

Default Settings

The initial state of the palette can be overridden by setting appropriate attributes to palette model. The list of supported attributes is defined in PaletteController class. If the palette model is create from Nodes then the attributes are extracted by calling Node.getValue() method on the root Node and category and item nodes. If the palette model is defined as folders and files in the layer then the attributes are extracted by calling FileObject.getAttribute().

In the example below the palette will not show item names initially (only icons are visible), the user can change this in palette's context menu. Category1 is read-only therefore the user cannot remove it. Category2 is not initially visible, the user can change this in palette's customizer.

      <filesystem>
          <folder name="MyModulePalette">
              <attr name="showItemNames" stringvalue="false"/>

              <folder name="Category1">
                  <attr name="isReadonly" stringvalue="true"/>

                  <file name="PaletteItem_1.myitem" url="palette/PaletteItem_1.myitem" />
                  <file name="PaletteItem_2.myitem" url="palette/PaletteItem_2.myitem" />
                  <file name="PaletteItem_3.myitem" url="palette/PaletteItem_3.myitem" />
              </folder>

              <folder name="Category2">
                  <attr name="isVisible" stringvalue="false"/>

                  <file name="PaletteItem_4.myitem" url="palette/PaletteItem_4.myitem" />
                  <file name="PaletteItem_5.myitem" url="palette/PaletteItem_5.myitem" />
                  <file name="PaletteItem_6.myitem" url="palette/PaletteItem_6.myitem" />
              </folder>
          </folder>
      </filesystem>
            

Adding categories and items at runtime

It is possible to add new palette categories and/or palette item at runtime when the palette window is already visible.

Adding a new category is very straight-forward, it basically means creating a new folder under palette's root folder in XML layer:

        FileObject paletteRoot = FileUtil.getConfigFile( "MyModulePalette" );
        paletteRoot.createFolder( "NewCategory" );
        

Adding a new item is a similar task:

        FileObject paletteRoot = FileUtil.getConfigFile( "MyPalette" );
        FileObject targetCategoryFO = paletteRoot.getFileObject( "CategoryName" );
        DataFolder targetCategoryDF = DataFolder.findFolder( targetCategoryFO );
        DataObject dobj = (DataObject)itemNode.getLookup().lookup( DataObject.class );
        dobj.copy( targetCategoryFolder );
        

Please refer to Nodes API in case the palette content is defined as a hierarchy of arbitrary Nodes.

Palette content for text-based editors

The following steps must be taken when writing the item using the support provided by this module:

  1. Create XML file with item definition according to the editor-palette-item-1_0.dtd.
  2. Register it in the editor's layer file (see Basic usage).
  3. Provide custom item implementation of the ActiveEditorDrop interface if needed. I must be referenced from the definition file.


How to use Quick Search API?

QuickSearch API and its implementations provides way for end user to learn system earlier and easier and also to find various things in the system more quickly, conveniently and in standard way. Main project page is on nb wiki, http://wiki.netbeans.org/QuickSearch

How To Add New Quick Search Provider

In order to plug in a new Quick Search provider and new category of results, module writers need to complete following steps:
1. Implement SearchProvider
2. Register SearchProvider implementation in xml layer
Register your SearchProvider implementation in your module's xml layer file under main "/QuickSearch" folder. Registration xml syntax is following:
              <folder name="QuickSearch">
                  <folder name="Category1_ID">
                      <attr name="position" intvalue="300"/>
                      <file name="org-netbeans-module1-package1-Provider1Impl.instance"/>
                  </folder>
                  <folder name="Category2_ID">
                      <!--Attribute for localization - provide localized display name of category!-->
                      <attr name="SystemFileSystem.localizingBundle" stringvalue="org.netbeans.modules.yourmodule.YourBundle"/>
                      <!--Attribute for command prefix - used to narrow search to this category only!-->
                      <attr name="command" stringvalue="p"/>
                      <!--Attribute for category ordering!-->
                      <attr name="position" intvalue="200"/>
                      <!--Note that multiple providers can contribute to one category!-->
                      <file name="org-netbeans-module2-package2-Provider2Impl.instance"/>
                      <file name="org-netbeans-module2-package3-Provider3Impl.instance"/>
                  </folder>
              </folder>
            
Syntax explanation:

How To Share Category Of Results

Quick Search UI shows search results divided into visually separeted sections, called categories. Several SearchProvider implementations may decide to display their results in one shared category of results in Quick Search UI.

In order to share category, module writers have to agree on shared category and its properties, especially its name. It means that all providers (possibly in different NetBeans modules) need to be registered under the same folder, as shown below:

Provider 1
Provider 1 is category "owner", which defines properties of SharedCategory such as display name, position and command prefix.
              <folder name="QuickSearch">
                  <folder name="SharedCategory">
                      <attr name="SystemFileSystem.localizingBundle" stringvalue="org.netbeans.modules.yourmodule.YourBundle"/>
                      <attr name="command" stringvalue="p"/>
                      <attr name="position" intvalue="200"/>
                      <file name="org-netbeans-module1-package1-Provider1Impl.instance">
                          <attr name="position" intvalue="300"/>
                      </file>                          
                  </folder>
              </folder>
            
Provider 2
Other providers from other modules are sharing category with Provider 1. Provider 2 does not define properties of SharedCategory, as they were already defined by Provider 1. Note that module dependency on the module of Provider 1 is needed to ensure that SharedCategory is fully defined.
              <folder name="QuickSearch">
                  <folder name="SharedCategory">
                      <file name="org-netbeans-module2-package2-Provider2Impl.instance"/>
                          <attr name="position" intvalue="200"/>
                      </file>                          
                  </folder>
              </folder>
            
Provider 3
The same rules apply like for Provider 2. Note that position attribute can be used to control position of provider's results in shared category. Results from provider with lowest position will go first and so on.
              <folder name="QuickSearch">
                  <folder name="SharedCategory">
                      <file name="org-netbeans-module2-package3-Provider3Impl.instance"/>
                          <attr name="position" intvalue="100"/>
                      </file>                          
                  </folder>
              </folder>
            

How To Define and Modify Order of Categories

Order of categories of results can be set by using "position" attribute of category xml folder definition. Following example will result in FirstCategory to be first, and SecongCategory to be second :), which means that FirstCategory and its results will be displayed above Secondcategory in QuickSearch results window.
              <folder name="QuickSearch">
                  <folder name="SecondCategory">
                      <attr name="position" intvalue="300"/>
                      ...
                  </folder>
                  <folder name="FirstCategory">
                      <attr name="position" intvalue="200"/>
                      ...
                  </folder>
             </folder>
            

How To Hide Recent Searches Results and Others

"Recent Searches" provider is contained directly in spi.quicksearch module, so its functionality is automatically always available by default. However, if your module wants to disable "Recent Searches" or any other category, follow the steps below:
Define module dependency
Your module have to depend on module where provider you want to disable is contained. In case of "Recent Searches" provider, it's spi,quicksearch, on which you probably already depend.
Disable provider using "_hidden"
For example, to disable "Recent Searches" provider, write into your layer:
              <folder name="QuickSearch">
                  <folder name="Recent_hidden">
                  </folder>
              </folder>
           
"Recent" is a name of category for "Recent Searches" provider and by appending "_hidden" suffix you are telling system to "hide" it. This technique can be used also to disable invidual search providers.

How To Use Quick Search in Platform Application

Quick Search UI is disabled by default in application built on top of NetBeans platform. To enable Quick Search feature in your application, complete following steps:
1. Write XML layer registration
Add the following lines to XML layer of some of your modules in your application suite:
        <folder name="Toolbars">
            <folder name="QuickSearch">
            <attr name="SystemFileSystem.localizingBundle" stringvalue="com.myapp.mymodule.MyBundle"/>
                <file name="org-netbeans-modules-quicksearch-QuickSearchAction.shadow">
                    <attr name="originalFile" stringvalue="Actions/Edit/org-netbeans-modules-quicksearch-QuickSearchAction.instance"/>
                </file>
            </folder>
        </folder>
        
2. Localize Toolbar Name
Replace com.myapp.mymodule.MyBundle in the xml registration above with path to your properties file, in which you'll define localized name of Quick Search toolbar:
                Toolbars/QuickSearch=Quick Search
             

By default, providers for searching in actions and recent searches will be enabled. Web search provider is disabled by default, see use case below for info how to turn it on.

How To Add a Default Web Search Provider

There is a default implementation of web search provider which uses Google to search for the given text on the web. Simply add the following lines to your XML layer to enable this search provider in your application:
          <folder name="QuickSearch">
              <folder name="WebSearch">
                  <!--Attribute for localization - provide localized display name of category!-->
                  <attr name="SystemFileSystem.localizingBundle" stringvalue="com.myapp.mymodule.MyBundle"/>
                  <!--Attribute for command prefix - used to narrow search to this category only!-->
                  <attr name="command" stringvalue="g"/>
                  <!--Attribute for category ordering!-->
                  <attr name="position" intvalue="200"/>
                  <!--Note that multiple providers can contribute to one category!-->
                  <file name="org-netbeans-modules-quicksearch-web-WebQuickSearchProviderImpl.instance"/>
              </folder>
          </folder>
        
You can also add branding for org.netbeans.modules.quicksearch.web Bundle to restrict the search to a particular site only:
            quicksearch.web.site=mywebsite.com
        
And you can also restrict the search to some parts your website only:
            quicksearch.web.url_patterns=mywebsite.com/docs,mywebsite.com/files/tutorials
        

How to customize Look&Feel properties

If you need to adjust border of the Quick Search component for your Look&Feel, you can put a Border instance into UIManager under key nb.quicksearch.border.


How to use Task List API?

This module provides SPI for third parties that want to display some sort information for the user in the Task List / Problems window. A typical example are Java errors, warnings, TODOs etc. Part of the integration are several implementation modules that provider task list user interface, TODO task scanning, Java integration.

Task Scanners

The main feature of the Task List SPI is the ability to 'plug-in' additional task providing modules that generate tasks for the task list window.

The plugable task scanners can either push new Tasks to the Task List window whenever they want - PushTaskScanner - or they can inherit from FileTaskScanner and the Task List framework will actively poll them for new tasks for each file under the current scanning scope (see below).

Scanner instances are registered in XML layer in folder "/TaskList/Scanners". The framework keeps track of modified files and notifies the scanners whenever a file under the scanning scope needs to be rescanned.

Task Scanning Scope

Scanning scope defines which files/folders will be scanned for tasks. The default implementation includes scopes for currently edited file, scope for files and folders in the main project and projects that depend on it and scope for all opened projects.

Additional scopes may be provided by extending TaskScanningScope class and registering instances in folder "/TaskList/ScanningScopes" in XML layer.

Task Groups

Tasks are organized into Groups according to their importance. Each task can be in one group only. The default implementation includes "Error", "Warning" and "TODO" groups. Additional groups can be registered in XML layer in folder "/TaskList/Groups". Each task group is identified by its unique name.


How to use TreeTableView Model?

The debuggercore/ViewModel module (View Model) allows to share one TreeTableView among different modules.

Used by debugger to display various information - threads, call stack, variables, etc.

How to use ETable and Outline?

XXX no answer for arch-what

XXX no answer for arch-usecases


How to use Look & Feel Customization Library?

The plaf library consists primarily of code that used to be in core. What it does: Installs a custom look and feel if a custom look and feel class is passed to it Sets the correct fonts in the Swing UIDefaults if a custom fontsize is desired for the application's UI Loads a UI theme if a URL for the theme file (no format changes since NetBeans 3.4) is passed to it Installs custom UI keys and values used by other components of NetBeans, such as colors and UI delegate class names used by other parts NetBeans. Examples of these: Tab control UI delegate class name, depending on the look and feel, for the window system Definitions of colors which the tab control, property sheet and output window will use, if present in UIDefaults, to color themselves in accordance with the UI spec for them on a given look and feel Custom border implementations NetBeans uses for scroll panes to reduce "border-buildup" A custom implementation of ToolbarUI which NetBeans uses for its toolbars, and a custom UI for toolbar buttons which sizes them correctly (GTK and Aqua only, currently) Insets definition for the editor scrollbar, used to get the height of the upper and lower button of the scrollbar for purposes of the Error Stripe. The appropriate key value is "Nb.Editor.ErrorStripe.ScrollBar.Insets". Compensate for missing elements on some (GTK) look and feels, which standard Swing code expects to be present, i.e. UIManager.getColor ("control"), to enable older code to run unmodified on newer look and feels. Its API consists of a single method, org.netbeans.swing.plaf.Startup.run (Class lookAndFeel, int fontSize, URL themeFile), which should be called early in NetBeans startup sequence by core, to initialize UIDefaults values before any main window GUI is constructed. It provides a minimal SPI in the form of the abstract class LFCustoms, which an alternate look and feel could use to provide lists of keys and values which should be installed into UIDefaults, via the mechanism documented in the documentation for LFCustoms. PlafAPI

Used by NetBeans to customize the UI to conform to UI design specifications; can be used by third parties who are employing parts of the NetBeans platform in their applications, such as the windowing system.

How to use Tab Control?

The tab control is a swing control used by NetBeans window system, similar in function to a JTabbedPane, which allows the user to see and select tabs that contain different components. It defines two GUI components: TabbedContainer (similar to JTabbedPane) and TabDisplayer, a generic component for displaying tabs which is not associated with any particular container. Several different types of UIs (view, editor, sliding) are provided, each of which is handled by a different UI delegate class; UI delegate subclasses designed to fit with Windows, Metal, Aqua and GTK look and feels are provided. TabbedContainerAPI PopupSwitcherAPI

Primary use cases are in the NetBeans window system, as top level containers in the main window; future use cases include providing a consistent UI for tabs in the property sheet, the component inspector and the output window, but this probably will not happen for 4.0.

How to use Actions APIs?

Actions provides system of support and utility classes for 'actions' usage in NetBeans.

First see the API description. Here is just a list of frequently asked or interesting questions slowly expanding as people ask them:

Actions faq:

How to define configurable Shortcut for Component based shortcut?

Q: The usual Swing way of defining Actions for your component is to create an Action instance and put it into the Input and Action maps of your component. However how to make this Action's shortcut configurable from the Tools/Keyboard Shortcuts dialog?

In order for the action to show up in Keyboards Shortcut dialog you need the action defined in the layer file under "Actions" folder and have the shortcut defined there under "Keymaps/<Profile Name>" linking to your action.

    <folder name="Actions" >
        <folder name="Window">
            <file name="org-netbeans-core-actions-PreviousViewCallbackAction.instance"/>
        </folder>
    </folder>

    <folder name="Keymaps">
        <folder name="NetBeans">
            <file name="S-A-Left.shadow">
                <attr name="originalFile" stringvalue="Actions/Window/org-netbeans-core-actions-PreviousViewCallbackAction.instance"/>
            </file>
        </folder>
    </folder>

The mentioned Action has to be a subclass of org.openide.util.actions.CallbackSystemAction. It does not necessarily has to perform the action, it's just a placeholder for linking the shortcut. You might want to override it's getActionMapKey() and give it a reasonable key.

The actual action that does the work in your component (preferably a simple Swing javax.swing.Action) is to be put into your TopComponent's ActionMap. The key for the ActionMap has to match the key defined in the global action's getActionMapKey() method.

        getActionMap().put("PreviousViewAction", new MyPreviousTabAction());

This way even actions from multiple TopComponents with the same gesture (eg. "switch to next tab") can share the same configurable shortcut.

Note: Don't define your action's shortcut and don't put it into any of the TopComponent's javax.swing.InputMap. Otherwise the component would not pick up the changed shortcut from the global context.


How to use UI Utilities API?

The org.openide.awt provides API/SPI for UI related aspects of application.

Cover of NetBeans Platform for Beginners book For general overview of the concepts of NetBeans action system and related UI elements, together with code samples, see chapter 5, of NetBeans Platform for Beginners by Jason Wexbridge and Walter Nyland.


How to use Compatibility APIs?

XXX no answer for arch-what

XXX no answer for arch-usecases


How to use Dialogs API?

The DialogsAPI allows creating a user notification, a dialog's description and also permits it to be displayed. The wizard framework allows create a sequence of panels which leads a user through the steps to complete any task. This API is part of package org.openide.

There is a Wizard Guide Book providing the introductionary information, moreover here is a list of frequently asked questions and their answers:

How to change the title of a wizard?

Q: Although none of my panels have names set (using setName() method) and the method name() in the WizardDescriptor.Iterator returns an empty string, I'm getting "wizard ( )" as the title of each panel in my wizard. When I set the name of the panel and return a string from the method name() I get: "panelName wizard (myName)". The wizard steps are labeled correctly, it just the panel title/name that looks like it adds "wizard ()" to any of my panels. I don't mind the "( )", but I would like to rid of the word "wizard".

A: You can change the format of your wizard's title by WizardDescriptor.setTitleFormat(MessageFormat format) and rid of 'wizard' word in the default wizard's title.


How to use Explorer & Property Sheet API?

The ExplorerAPI is build around Explorer - solely a user-interface device: it has no particular knowledge of the structure of the IDE. Rather, it provides the physical user interface for the Node hierarchy, as described in the NodesAPI. A given Explorer instance will be some visual component (such as a Swing panel) displaying some representation of a subtree of the complete Node hierarchy; the topmost node being displayed is said to be the root of the Explorer. Be careful not to confuse the root of a particular Explorer instance, which is selected according to what the user wishes to see, with the root(s) of the entire Node hierarchy, which generally are fixed.

Cover of NetBeans Platform for Beginners book For general overview of the concepts related to nodes and explorers, together with code samples, see chapter 7, of NetBeans Platform for Beginners by Jason Wexbridge and Walter Nyland.


How to use File System API?

The Filesystems API provides a common API to access files in a uniform manner. It is available as standalone library and also is bundled together with other parts of the openide. Specification

Cover of NetBeans Platform for Beginners book For general overview of the filesystem concepts, related topics, together with code samples, see chapter 3, of NetBeans Platform for Beginners by Jason Wexbridge and Walter Nyland. Many of the usecases are described at the overall documentation, in a way how to register a mime type. Some of the additional usecases are covered here.

How to change menus, etc. after login?

See documentation about dynamically changing the system filesystem.


How to use Filesystems API 8.0 Compatibility?

Preservation of compatibility

Allows to run modules compiled against FileSystems 8.0 APIs


How to use I/O APIs?

The Input/Output API is a small API module which contains InputOutput and related interfaces used in driving the Output Window. The normal implementation is org.netbeans.core.output2.

There is an SPI but additional implementations are not expected. The API is most important.

Simple usage example:


InputOutput io = IOProvider.getDefault().getIO("My Window", true);
io.select();
OutputWriter w = io.getOut();
w.println("Line of plain text.");
OutputListener listener = new OutputListener() {
    public void outputLineAction(OutputEvent ev) {
        StatusDisplayer.getDefault().setStatusText("Hyperlink clicked!");
    }
    public void outputLineSelected(OutputEvent ev) {
        // Let's not do anything special.
    }
    public void outputLineCleared(OutputEvent ev) {
        // Leave it blank, no state to remove.
    }
};
w.println("Line of hyperlinked text.", listener, true);

How to use Datasystems API?

In summary, the LoadersAPI is responsible for scanning files in a directory on disk, weeding out irrelevant files of no interest to the IDE, and grouping the rest into logical chunks, or just determining what type of data each represents. It does this scanning by asking each registered data loader whether or not the given file(s) should be handled. The first loader to recognize a file takes ownership of it, and creates a matching data object to represent it to the rest of the IDE.

A lot of usecases is described in the javadoc. Here is the list of some faqs:

Using Scripting and Templating Languages

Often many people require ability to create a "clever" template - e.g. write piece of simple text and at the time of its processing do some advanced changes to it using either scripting or templating languages.

This traditionally used to be a bit complicated task, however since version 6.1 there are new interfaces can be registered as a services in a lookup and it is reponsible for handling the whole copy of the template file(s) to the destination folder. and can be registered as a services in a lookup and it is reponsible for providing "hints" - e.g. map mapping strings to various objects. and these interfaces allow anyone to extend the behaviour during creation of new files without writing new DataLoader and co.

Smart Templating Quick How-To
First of all create a file in your module layer located somewhere under the Templates/ folder. Make it a template by adding <attr name="template" boolvalue="true"/>. Associate this template with a scripting language, for example by <attr name="javax.script.ScriptEngine" stringvalue="freemarker"/>. Now make sure that the scripting language integration is also available by requesting a token in standard format, for freemarker just put OpenIDE-Module-Needs: javax.script.ScriptEngine.freemarker in your manifest. This tells the NetBeans module system that a module providing integration with such scripting engine has to be enabled. Now you can use regular script language tags inside of your template file. When you write your instantiate method in your wizard, you can create a Map<String,Object> and fill it with parameters collected from your wizard and then pass it to createFromTemplate(targetFolder, targetName, mapWithParameters) . This will invoke the scripting language and make the mapWithParameters values available to it. Beyond this there is few standard parameters predefined including name, user, date, time, etc. and also additional parameters are collected from all registered CreateFromTemplateAttributesProviders.

Moreover there is a built in support for scripting languages in the standard NetBeans IDE. If a template is annotated with a property that can be associated to templates that either should return real instance of ScriptEngine interface or a String name of the engine that is then used to search for it in the javax.script.ScriptEngineManager. Usually the freemarker engine is the one that is supported by the NetBeans IDE - if your module wants to use it then include a token dependency OpenIDE-Module-Needs: javax.script.ScriptEngine.freemarker in your manifest file (also accessible through project customizer GUI) to indicate to the system that you need it. then the scripting engine is then used to process the template and generate the output file. While running the engine one can rely on few predefined properties:

Other properties can indeed be provided by CreateFromTemplateAttributesProviders. After processing, the output is also sent to appropriate org.openide.text.IndentEngine associated with the mime type of the template, for formating.

How to add action to folder's popup menu?

The actions that the default folder loader shows in its popup menu are read from a layer folder Loaders/folder/any/Actions so if any module wishes to extend, hide or reorder some of them it can just register its actions there. As code like this does:
    <folder name="Loaders" >
        <folder name="folder" >
            <folder name="any" >
                <folder name="Actions" >
                    <file name="org-mymodule-MyAction.instance" >
                        <attr name="instanceCreate" stringvalue="org.mymodule.MyAction" />
                    </file>
                </folder>
            </folder>
        </folder>
    </folder>
    
As described in general actions registration tutorial.

This functionality is available since version 5.0 of the loaders module. Please use OpenIDE-Module-Module-Dependencies: org.openide.loaders > 5.0 in your module dependencies.

In version 5.8 all the standard loaders were changed to read actions from layer:

How to allow others to enhance actions of your loader?

If you want other modules to enhance or modify actions that are visible on DataObjects produced by your DataLoader and you are either using DataNode or its subclass, you can just override protected String actionsContext() method to return non-null location of context in layers from where to read the actions.

The usual value should match Loaders/mime/type/Actions scheme, for example java is using Loaders/text/x-java/Actions, but the name can be arbitrary.

This functionality is available since version 5.0 of the loaders module. Please use OpenIDE-Module-Module-Dependencies: org.openide.loaders > 5.0 in your module dependencies.

How to use Module System API?

The Modules API lies at the core of NetBeans and describes how plug-in modules are added and managed. ModulesAPI

Cover of NetBeans Platform for Beginners book For general overview of the concepts, together with code samples, see chapter 2, of NetBeans Platform for Beginners by Jason Wexbridge and Walter Nyland. Gory technical details are explained on API overview page . Other interesting topic(s) follow:

How a classpath of my module is constructed?

The NetBeans is defacto a container that manages individual module's lifecycle and other runtime aspects. One of the important things is that it creates a runtime classpath for provided modules based on dependencies they specify in their manifests. The overview of the runtime infrastructure is a good starting place for everyone who wishes to learn more about the NetBeans runtime container behaviour.

Runtime compatibility patches

To maintain binary compatibility, method implementations may be injected at runtime, in a form of a superclass in the class' inheritance hierarchy. Modules compiled against older version of APIs which contains MethodReferences to methods removed from the oficial APIs will be then linked according to JVM Resolution algorithm to a matching method present in the superclass of the referenced type.

Annotations are used to instruct the ClassLoader to make transformations to the API classes. PatchFor causes the annotated class to be injected as a superclass of the API class identified by the annotation's value. ConstructorDelegate marks a method, which is called as constructor implementation in the case that it is necessary to preserve a constructor for binary compatibility.


How to use Nodes API?

Nodes API serves as the main aparatus for visualisation of objects in NetBeans. Nodes augment objects with standard aspects used for visualisation (e.g. name, displayName, icons, set of proerties, subnodes hierarchy, etc.) Once a Node is defined for given object it can be visualised using diferent views e.g. trees, lists, tables etc. Descripion of nodes can be found here.

Cover of NetBeans Platform for Beginners book For general overview of the concepts related to nodes and explorers, together with code samples, see chapter 7, of NetBeans Platform for Beginners by Jason Wexbridge and Walter Nyland.


How to use Settings Options API?

org.openide.options

N/A


How to use Text API?

The EditorAPI is used for accessing editor-related functionality from within the IDE for use by other modules and the core IDE itself.

XXX no answer for arch-usecases


How to use Utilities API?

Described in the overall answer.

How shall I do or influence logging in NetBeans?

If you are interested in logging from inside your module, or in writing your own log handler or in configuring the whole system, then best place to start is the NetBeans logging guide.


How to use Base Utilities API?

Described in the overall answer.

Use-cases can be found in org.openide.util module arch summary.


How to use Old Enumeration API?

OldEnumerationsAPI

Most of the functionality is deprecated, so it is better to go and use the replacement API in org-openide-util.jar.


How to use Lookup API?

Described in the overall answer.

Cover of NetBeans Platform for Beginners book There is a great introduction to Lookup and its usage in its javadoc. For details on this topic, together with code samples, see chapter 4, of NetBeans Platform for Beginners by Jason Wexbridge and Walter Nyland. In addition to that here is a list of frequently asked or interesting questions slowly expanding as people ask them:

Lookup faq:

How to specify that a service in Lookup should be available only on Windows?

Q: Most of the time I specify interfaces that I want to add to the Lookup class in the layer.xml file. But, let's say I have a platform-specific interface (something on Windows only, for instance).

How can I specify (in the xml, or programmatically) that this service should only be added to the Lookup if the platform is Windows? >

In general there are three ways to achieve this.

How shall I write an extension point for my module?

Q: I have more modules one of them providing the core functionality and few more that wish to extend it. What is the right way to do it? How does the Netbeans platform declare such extension point?

Start with declaring an extension interface in your core module and put it into the module's public packages. Imagine for example that the core module is in JAR file org-my-netbeans-coremodule.jar and already contains in manifests line like OpenIDE-Module: org.my.netbeans.coremodule/1 and wants to display various tips of the day provided by other modules and thus defines:

 

package org.my.netbeans.coremodule;

public interface TipsOfTheDayProvider {
    public String provideTipOfTheDay ();
}

And in its manifest adds line OpenIDE-Module-Public-Packages: org.my.netbeans.coremodule.* to specify that this package contains exported API and shall be accessible to other modules.

When the core module is about to display the tip of the day it can ask the system for all registered instances of the TipsOfTheDayProvider, randomly select one of them:


import java.util.Collection;
import java.util.Collections;
import org.openide.util.Lookup;

Lookup.Result result = Lookup.getDefault ().lookup (new Lookup.Template (TipsOfTheDayProvider.class));
Collection c = result.allInstances ();
Collections.shuffle (c);
TipsOfTheDayProvider selected = (TipsOfTheDayProvider)c.iterator ().next ();

and then display the tip. Simple, trivial, just by the usage of Lookup interface once creates a registry that other modules can enhance. But such enhancing of course requires work on the other side. Each module that would like to register its TipsOfTheDayProvider needs to depend on the core module - add OpenIDE-Module-Module-Dependencies: org.my.netbeans.coremodule/1 into its manifest and write a class with its own implementation of the provider:


package org.my.netbeans.extramodule;

class ExtraTip implements TipsOfTheDayProvider {
    public String provideTipOfTheDay () {
        return "Do you know that in order to write extension point you should use Lookup?";
    }
}

Then, the only necessary thing is to register such class by using the J2SE standard into plain text file META-INF/services/org.my.netbeans.coremodule.TipsOfTheDayProvider in the module JAR containing just one line:

org.my.netbeans.extramodule.ExtraTip

and your modules are now ready to communicate using your own extension point.


How to use Window System API?

Window System API is used to display and control application GUI: Main window, frames, components.

Cover of NetBeans Platform for Beginners book For general overview of the concepts, together with code samples, see chapter 6, of NetBeans Platform for Beginners by Jason Wexbridge and Walter Nyland.

General Usecases

General usecases can be read in the design document created before work on new window system design started.

How to create a '.settings' file for a TopComponent?

Either write it by hand (not that hard if you copy other file and tweak it to match your TC), or start the IDE, instantiate the TC somehow (You have a "Window->Show My TC", right? ), copy the file that gets created in $userdir/config/Windows2Local/Component and cleanup the serialdata section - replace it with proper "<instance class='..." /> tag.

How to make a TopComponentGroup?

Q: I'm trying to make a TopComponentGroup. I've just read http://ui.netbeans.org/docs/ui/ws/ws_spec.html#3.9 I want to make a group that uses the first invocation strategy. That is, I want the group to open/close when I activate a certain subclass of TopComponent. Say, for example, I have a FooTopComponent, and when it's active, I want to open a FooPropertySheetComponent, docked in a mode on the right-hand side. I know I have to:
  1. declare the group in the layer file (Windows2/Groups)
  2. have code for opening the group
  3. have code for closing the group
I think I do #2 in FooTopComponent.componentActivated() and #3 in FooTopComponent.componentDeactivated(). Is that right?

A:Yes it is correct way. You can check simple test module. First you must get TopComponentGroup instance using find method then call TopComponentGroup.open()/close(). Here is the code in your componentDeactivated method:
   protected void componentDeactivated ()
   {
       // close window group containing propsheet, but only if we're
       // selecting a different kind of TC in the same mode
       boolean closeGroup = true;
       Mode curMode = WindowManager.getDefault().findMode(this);
       TopComponent selected = curMode.getSelectedTopComponent();
       if (selected != null && selected instanceof FooTopComponent)
           closeGroup = false;
             if (closeGroup)
       {
           TopComponentGroup group = WindowManager.getDefault().findTopComponentGroup(TC_GROUP);
           if (group != null)
           {
               group.close();
           }
       }
   }     
    

How to use Deprecated, old search API?

It allows other modules to define how the nodes they define should be searched, without depending on any concrete module containing the search feature.

The SearchInfo API+SPI allows other modules to specify whether and how should nodes they define be searched.

The definition is represented by objects implementing interface SearchInfo. To enable searching on a custom node, a SearchInfo object must be added to the node's lookup. In most cases, there is no need to define own class implementing the interface - one can use factory methods of class SearchInfoFactory.

Example:

import org.openide.util.lookup.Lookups;
  
public class MyNode extends AbstractNode {

    public MyNode(FileObject folder) {
        super( new MyNodeChildren(folder),
               Lookups.singleton(SearchInfoFactory.createSearchInfo(
                     folder,
                     true,
                     new FileObjectFilter[] {
                             SearchInfoFactory.VISIBILITY_FILTER
                     }) );
    }

    ...

}

One of the factory methods - createSearchInfoBySubnodes(...) - requires that a reference to the node itself. In this case, it is not possible to fully define the lookup in the super(...) statement of the constructor because a reference to the node is not available until the call of super(...) returns. In this case, a special technique must be used:

import org.openide.util.lookup.AbstractLookup;
import org.openide.util.lookup.InstanceContent;
  
public class MyNode extends AbstractNode {

    public MyNode() {
        this(new InstanceContent());
    }

    public MyNode(InstanceContent ic) {
        super(new AbstractLookup(ic));
        ic.add(SearchInfoFactory.createSearchInfoBySubnodes(this));
    }

    ...

}
defines interfaces SearchInfo, FileObjectFilter and a factory class SearchInfoFactory