NetBeans Project Type Extension Module Tutorial

This tutorial needs a review. You can open a JIRA issue, or edit it in GitHub following these contribution guidelines.

This tutorial demonstrates how to extend an existing project type.

This document uses NetBeans Platform 7.1 and NetBeans IDE 7.1. If you are using an earlier version, see the previous version of this document.

You will also make use of this icon, which you can right-click here and download: image::images/webPagesBadge.gif[]

Introduction to Project Extensions

New NetBeans IDE APIs since NetBeans IDE 6.0 enable you to add new nodes to an existing project type’s logical view, new objects to an existing project type’s lookup, and new panels to an existing project type’s Project Properties dialog box. For example, in this tutorial, to illustrate these extensions, we extend the web application project type, by adding a new 'Important Files' node, exposing the content of the project’s 'nbproject' folder, as shown here:

result 69

Prior to NetBeans IDE 6.0, no NetBeans IDE APIs existed for extending existing project types. Instead, you would need to create new project types from scratch. From 6.0 onwards, you are recommended to extend existing project types rather than create new ones. This will keep the number of project types to a minimum and avoid a large number of project types with very small differences. However, it is still possible to create project types from scratch, as before.

Annotations are used throughout this tutorial to register the lookup extension, logical view extension, and project customizer extension. As you will see below, the extensions will be registered for the project type "org-netbeans-modules-web-project", which is the web application project type. Here is a list of strings representing other project types supported by NetBeans IDE:

  • org-netbeans-modules-ant-freeform

  • org-netbeans-modules-apisupport-project

  • org-netbeans-modules-apisupport-project-suite

  • org-netbeans-modules-j2ee-archiveproject

  • org-netbeans-modules-j2ee-clientproject

  • org-netbeans-modules-j2ee-earproject

  • org-netbeans-modules-j2ee-ejbjarproject

  • org-netbeans-modules-java-j2seproject

Other project types may be available, depending on the modules that are part of your specific installation of NetBeans IDE or other application on the NetBeans Platform.

Creating the Module Project

We begin by working through the New Module Project wizard. At the end of it, we will have a basic source structure, with some default files, that every NetBeans module requires.

  1. Choose File > New Project (Ctrl+Shift+N). Under Categories, select NetBeans Modules. Under Projects, select Module. Click Next.

  1. In the Name and Location panel, type ImportantWebFiles in the Project Name field. Change the Project Location to any directory on your computer. Click Next.

  1. In the Basic Module Configuration panel, type org.netbeans.modules.importantwebfiles in Code Name Base. Click Finish.

The IDE creates the ImportantWebFiles project. The project contains all of your sources and project metadata, such as the project’s Ant build script. The project opens in the IDE. You can view its logical structure in the Projects window (Ctrl-1) and its file structure in the Files window (Ctrl-2).

Setting Dependencies

We will need to make use of several NetBeans APIs. In this step, we select the modules that provide the NetBeans APIs that we will need.

  1. Right-click the project node and choose Properties. The Project Properties dialog box opens.

  1. In the Libraries panel, add dependencies on the following modules:

    • Datasystems API

    • File System API

    • Lookup API

    • Nodes API

    • Project API

    • Project UI API

    • Utilities API

    • Web APIs

  1. Click OK.

Extending the Project Lookup

We start by implementing the LookupProviderImpl class, which we will register via an annotation.

  1. Create a Java class called LookupProviderImpl .

  1. Change the default code to the following:

@LookupProvider.Registration(projectType = "org-netbeans-modules-web-project")
public class LookupProviderImpl implements LookupProvider {

    public Lookup createAdditionalLookup(Lookup lookup) {

        Project prj = lookup.lookup(Project.class);

        *//If there is a web module provider in the
        //project's lookup, add a new lookup item to
        //the lookup, which we will look for to determine
        //whether a node should be created:*
        WebModuleProvider wmp = lookup.lookup(WebModuleProvider.class);
        if (wmp != null) {
            return Lookups.fixed(new MyCoolLookupItem(prj));
        }

        *//If there is no web module in the lookup,
        //we do not add a new item to our lookup,
        //so that later a node will not be created:*
        return Lookups.fixed();

    }

}
  1. Create a new Java class called MyCoolLookupItem .

1. Change the default code to the following:

public class MyCoolLookupItem {

    public MyCoolLookupItem(Project prj) {
    }

}

You now have a module that adds an object named MyCoolLookupItem to the Lookup of web projects. The object has access to the web project, via the Project class received from the createAdditionalLookup method.

Extending the Project Logical View

We start by implementing the ImportantFilesNodeFactoryImpl class, which we will register via an annotation.

  1. Create a Java class called ImportantFilesNodeFactoryImpl .

  1. Change the default code to the following:

@NodeFactory.Registration(projectType = "org-netbeans-modules-web-project")
public class ImportantFilesNodeFactoryImpl implements  link:https://bits.netbeans.org/dev/javadoc/org-netbeans-modules-projectuiapi/org/netbeans/spi/project/ui/support/NodeFactory.html[NodeFactory] {

    Project proj;

    public  link:https://bits.netbeans.org/dev/javadoc/org-netbeans-modules-projectuiapi/org/netbeans/spi/project/ui/support/NodeList.html[NodeList] createNodes(Project project) {

        this.proj = project;

        *//If there is no 'nbproject' folder,
        //return an empty list of nodes:*
        if (proj.getProjectDirectory().getFileObject("nbproject") == null) {
            return NodeFactorySupport.fixedNodeList();
        }

        *//If our item is in the project's lookup,
        //return a new node in the node list:*
        MyCoolLookupItem item = project.getLookup().lookup(MyCoolLookupItem.class);
        if (item != null) {
            try {
                ImportantFilesNode nd = new ImportantFilesNode(proj);
                return NodeFactorySupport.fixedNodeList(nd);
            } catch (DataObjectNotFoundException ex) {
                Exceptions.printStackTrace(ex);
            }
        }

        *//If our item isn't in the lookup,
        //then return an empty list of nodes:*
        return NodeFactorySupport.fixedNodeList();

    }

}
  1. Create a new Java class called ImportantFilesNode .

1. Change the default code to the following:

public class ImportantFilesNode extends  link:https://bits.netbeans.org/dev/javadoc/org-openide-nodes/org/openide/nodes/FilterNode.html[FilterNode] {

    private static Image smallImage =
          ImageUtilities.loadImage("/org/netbeans/modules/importantwebfiles/webPagesBadge.gif"); // NOI18N

    public ImportantFilesNode(Project proj) throws DataObjectNotFoundException {
        super(DataObject.find(proj.getProjectDirectory().getFileObject("nbproject")).getNodeDelegate());
    }

    public String getDisplayName() {
        return "Important Files";
    }

    *//Next, we add icons, for the default state, which is
    //closed, and the opened state; we will make them the same.
    //Icons in project logical views are
    //based on combinations--you must combine the node's own icon
    //with a distinguishing badge that is merged with it. Here we
    //first obtain the icon from a data folder, then we add our
    //badge to it by merging it via a NetBeans API utility method:*

    public Image getIcon(int type) {
        DataFolder root = DataFolder.findFolder(FileUtil.getConfigRoot());
        Image original = root.getNodeDelegate().getIcon(type);
        return ImageUtilities.mergeImages(original, smallImage, 7, 7);
    }

    public Image getOpenedIcon(int type) {
        DataFolder root = DataFolder.findFolder(FileUtil.getConfigRoot());
        Image original = root.getNodeDelegate().getIcon(type);
        return ImageUtilities.mergeImages(original, smallImage, 7, 7);
    }

}
  1. Right-click this icon and save it in the main package of your module: image::images/webPagesBadge.gif[]

Extending the Project Customizer

Finally, we create two new tabs in the Project Properties dialog of the web application project type.

  1. Create a Java class called ImportantFilesCustomizerTab .

  1. Change the default code to the following:

@NbBundle.Messages({
    "LBL_Config_Murphy1=Murphy 1",
    "LBL_Config_Murphy2=Murphy 2 "})
public class ImportantFilesCustomizerTab implements ProjectCustomizer.CompositeCategoryProvider {

    private String name;

    @ProjectCustomizer.CompositeCategoryProvider.Registration(projectType = "org-netbeans-modules-web-project", position = 100)
    public static ImportantFilesCustomizerTab createMurphy1() {
        return new ImportantFilesCustomizerTab(Bundle.LBL_Config_Murphy1());
    }

    @ProjectCustomizer.CompositeCategoryProvider.Registration(projectType = "org-netbeans-modules-web-project", position = 110)
    public static ImportantFilesCustomizerTab createMurphy2() {
        return new ImportantFilesCustomizerTab(Bundle.LBL_Config_Murphy2());
    }

    private ImportantFilesCustomizerTab(String name) {
        this.name = name;
    }

    @Override
    public Category createCategory(Lookup lkp) {
        ProjectCustomizer.Category toReturn = null;
        if (Bundle.LBL_Config_Murphy1().equals(name)) {
            toReturn = ProjectCustomizer.Category.create(
                    Bundle.LBL_Config_Murphy1(),
                    Bundle.LBL_Config_Murphy1(),
                    null);
        } else {
            toReturn = ProjectCustomizer.Category.create(
                    Bundle.LBL_Config_Murphy2(),
                    Bundle.LBL_Config_Murphy2(), // NOI18N
                    null);
        }
        return toReturn;
    }

    @Override
    public JComponent createComponent(Category category, Lookup lkp) {
        String nm = category.getName();
        if (Bundle.LBL_Config_Murphy1().equals(nm)) {
            JPanel jPanel1 = new JPanel();
            jPanel1.setLayout(new BorderLayout());
            jPanel1.add(new JLabel(Bundle.LBL_Config_Murphy1()), BorderLayout.CENTER);
            return jPanel1;
        } else {
            JPanel jPanel2 = new JPanel();
            jPanel2.setLayout(new BorderLayout());
            jPanel2.add(new JLabel(Bundle.LBL_Config_Murphy2()), BorderLayout.CENTER);
            return jPanel2;
        }
    }

}

Installing the Module

Finally, we install the module and make use of the result.

  1. Right-click the module project and run it.

1. Create a new web application, or open an existing one, and notice that it has an Important Files node, containing the files from the 'nbproject' folder:

result 69
  1. Right-click the web application project and choose Properties. In the Project Properties dialog box, notice your new tabs:

proj props 69

Next Steps

For more information about creating and developing NetBeans modules, see the following resources: