FeaturesPluginsDocs & SupportCommunityPartners

Writing POV-Ray Support for NetBeans V - Creating an API

Tim Boudreau
7 June 2006

Feedback

This is a DRAFT!

This is a continuation of the tutorial for building POV-Ray support for NetBeans. If you have not read the first or second, third and fourth parts of this tutorial, you may want to start there.

Creating the API

As discussed when we designed POV-Ray support, we will need an API - there will be some intercommunication between POV-Ray files and the project. In particular, we will need some interfaces:
  • MainFileProvider - find the main file of a project - the one to render when the whole file is built, and allow a POV-Ray scene file node to find out if it is the main file (so it can bold-face its display name).
  • RendererService - an API a POV-Ray file node can call to ask that it be rendered as an image
  • ViewService - an API a POV-Ray file can call to ask that its associated image be shown in the IDE, rendering it if necessary.
For this, we will actually create a separate module. That way we avoid a dependency between file support and project support - either module will be loadable by itself as long as the module providing the API is there. Also, this helps in delivering updates - the API presumably will remain stable, and psychologically having it in a separate module helps the developer to be aware when they are making API changes. It also means that a completely different module supporting POV-Ray files could still get them rendered via this API, and completely different project support could be provided with no changes to the file support module. So it's generally healthy for the codebase to do it this way.
  1. Create a new abstract Java class in org.netbeans.modules.examples.api.povray called MainFileProvider, and implement it as follows:
    public abstract class MainFileProvider {
        public abstract FileObject getMainFile();
        public abstract void setMainFile (FileObject file);
        public boolean isMainFile (FileObject file) {
            return obj.equals(getMainFile());
        }
    }
    

  2. Create a new abstract Java class in org.netbeans.modules.examples.api.povray called RendererService, and implement it as follows:
        public static final String PROJECT_RENDERER_KEY_PREFIX = "renderer.";
        public static final String PRODUCTION_RENDERER_SETTINGS_NAME = "production";
        public abstract FileObject render(FileObject scene, String propertiesName);
        public abstract FileObject render (FileObject scene, Properties renderSettings);
        public abstract FileObject render (FileObject scene);
        public abstract FileObject render();
        public abstract String[] getAvailableRendererSettingsNames();
        public abstract Properties getRendererSettings (String name);
        public abstract String getPreferredRendererSettingsNames();
        public abstract String getDisplayName (String settingsName);
        

  3. Create a new Java interface in org.netbeans.modules.examples.api.povray called ViewService, and implement it as follows:
        boolean isRendered (FileObject file);
        boolean isUpToDate (FileObject file);
        void view (FileObject file);
    
    (if you are wondering why the first two are abstract classes instead of interfaces, the answer is simple: In the case of MainFileProvider, it allows us to implement isMainFile(); in the case of the other RendererService, it is highly probably that there will be new requirements for it in the future, and you can add methods [with some sort of default implementation] to an abstract class semi-backward-compatibly [name collisions with subclasses are still possible], but not to an interface. ViewService is simple and well-defined enough that it will probably never change).

  4. On the main menu, select File > New Project

  5. In the New Project wizard, select NetBeans Module Projects > Module Project and click Next or press Enter

  6. Name the project "api" and click Next or press Enter
  7. Provide the code name "org.netbeans.examples.api.povray" - this follows the NetBeans package naming conventions that public packages shall have the name org.netbeans.api... to indicate visually that they are intended to be API (and thus kept backward compatible).

  8. Provide the display name "Povray API". Make sure the Add to Module Suite radio button is checked and pointing at the POV-Ray module suite

  9. Click Finish or press Enter to create the project

  10. Right click the newly created project in the Projects tab, and choose Properties. Go to the API Versioning page in the dialog.

  11. Fill in "1" for the Major Version Number

  12. Click the Autoload radio button - this means this module is a library - it will only be loaded if something else starts to use a class from it, which is more effecient

  13. On the libraries page, add a new dependency on the Filesystems API module (look for AbstractFileObject for a fast way to find it).

  14. In the editor, run Fix Imports on MainFileProvider and ViewService to import FileObject.

  15. Right click the Povray Projects project and add a dependency on our new module - just search for one of the classes we've added. Then do the same for the Povray File Support module, so both of these modules can see API classes (but not each others' classes).

Using the API from PovrayDataNode

We haven't implemented the API yet, but we can set up some code that will use it - we know we want the node for the file which is the "main file" of our project to be shown in bold text. And having some code that uses the API will help to test it once it is written, which will be a bit of work.

  1. Right-click the Povray File Support project, choose Properties and open the Libraries page of the Project Properties dialog

  2. Click the Add button, and in the dialog type "FileOwnerQuery" - we are adding a dependency on the Projects API. FileOwnerQuery is part of that API - a class with static methods that will return the project (if any) which owns a given file. Our Node will need to look up the project it belongs to, and then query the project's Lookup to try to find an implementation of our API classes.
  3. Open org.netbeans.examples.modules.povfile.PovrayDataNode in the code editor.

  4. Add the following methods to PovrayDataNode:
        private FileObject getFile() {
            return getDataObject().getPrimaryFile();
        }
    
        private Object getFromProject (Class clazz) {
            Object result;
            Project p = FileOwnerQuery.getOwner(getFile());
            if (p != null) {
                result = p.getLookup().lookup (clazz);
            } else {
                result = null;
            }
            return result;
        }
    
        private boolean isMainFile() {
            MainFileProvider prov = (MainFileProvider)
                getFromProject (MainFileProvider.class);
            boolean result;
            if (prov == null) {
                result = false;
            } else {
                FileObject myFile = getFile();
                result = prov.isMainFile(myFile);
            }
            return result;
        }
    
        public String getHtmlDisplayName() {
            return isMainFile() ? "" + getDisplayName() + "" : null;
        }
    
    
    What the above code does is fairly straightforward. getFile() returns a FileObject (NetBeans virtual filesystem file) that this Node represents. getFromProject tries to find the project that owns the file, and if it finds one, queries its Lookup, asking it for an instance of the Class that was passed into this method (e.g. one of the classes in the API we just defined). isMainFile() uses the above two methods to decide if this Node represents the "main file" of the project (the one that should be rendered by POV-Ray if the user chooses to "build" the project - POV-Ray supports file includes, so there may be many files in a project, but only one master image. getHtmlDisplayName() is where the rubber meets the road - this method will return a boldface HTML string if this Node represents the main file.

Next Steps

In the next section we will implement the API we have created.

Companion
Projects:
MySQL Database Server   Open JDK: an Open SourceJDK   GlassFish Community: an Open Source Application Server    Mobile & Embedded Community    Open Solaris   java.net - The Source for Java Technology Collaboration   Virtual Box - full virtualizer  Open ESB - The Open Enterprise Service Bus Powered by