Welcome Vivek's Weblog

Monday Mar 12, 2007

In my previous blog I have mentioned that you need Netbeans 5.5.1 + Enterprise Pack 5.5.1 for getting schema based code completion. Actually schema-based code completion for XML files was possible since 5.5
Enterprise Pack, but there was an important issue that was fixed in
5.5.1, see issue 91333 for details.

Tuesday Mar 06, 2007

I wanted to post this tutorial long back, but couldn't due to lack of time. Anyways here it is:

The following topics are covered below:


  • Setting Up a Plug-in Module Project
    • Installing the Software
    • Creating a NetBeans Plug-in Module Project

  • Adding Libraries to the Project
  • Implementing the Catalog Registration Class
  • Register XML module catalog plugin to Layer.xml
  • Installing and Using the Plug-in Module
    • Installing the Plug-in Module
    • Using the NetBeans Plug-in Module


This tutorial can be completed in 20 minutes.

For more information on NetBeans plug-in modules, see the
NetBeans Development Project home
on the NetBeans website. If you have questions, visit the
NetBeans Developer FAQ or use the feedback link
at the bottom of this page.


Setting Up a Plug-in Module Project


Before you start writing the plug-in module, you have to make sure you have all of the necessary software
and that your project is set up correctly. NetBeans provides a wizard that sets up all the basic files
needed for a plug-in module.



Installing the Software

Before you begin, you need to install the following software on your
computer:


  • NetBeans IDE 5.5.1 (download) (daily build)
  • NetBeans IDE Enterprise Pack 5.5.1 (download) (daily build)
  • Java Standard Development Kit (JDK™) version
    1.4.2 (download)
    or 5.0 (download)

Creating a NetBeans Plug-in Module Project

  1. Choose File > New Project. Under Categories, select NetBeans Plug-in Modules.

    NetBeans plug-in module support provides three project types:

    • Module Project. Creates a template for a standalone plug-in module.
    • Library Wrapper Module Project. Creates a plug-in module for an external JAR file required by one or more plug-in modules.
    • Module Suite Project. Creates a template for a set of interdependent plug-in modules and library wrapper modules, which you want to deploy
      together.

    Create Module Project
  2. Select Module Project. Click Next.
  3. In the Name and Location panel, type CodeCompletion in Project Name.
    Change the
    Project Location to any directory on your computer, such as c:\Documents and Settings\Administrator. Leave the Standalone Module radio button
    and the Set as Main Project checkbox selected.
    Click Next.Create Module Project
  4. In the Basic Module Configuration panel, replace yourorghere in Code Name Base with myorg,
    so that the whole code name base is org.myorg.codecompletion.
    Notice that the localizing bundle and the XML layer will
    be stored in the package org.myorg.codecompletion. These files do the following:
    • Localizing Bundle. Specifies language-specific strings for internationalization.
    • XML Layer. Registers items such as menus and toolbar buttons in the NetBeans System Filesystem.

     

    Click Finish. The IDE creates the "Schema Based Code Completion"
    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).

Adding Libraries to the Project

Add the following libraries to this project. We will be using classes of these libraries in our Catalog Registration class.

1) XML Entity Catalog

2) Utilities API



 

Implementing the Catalog Registration Class

Here we will see the implementation of "RgisterCatalog.java" class. Create a java pacakge called "org.myorg.codecompletion.catalog" inside the project. Create new java class, and name it "RgisterCatalog" and click finish.

 

Implement three interfaces to this class ie: CatalogReader, CatalogDescriptor, EntityResolver.

Import all the three interfaces to this class:

After importing these interfaces, a light buld will appear on the left side of the class declaration. Click that bulb and it will ask you to implement all abstract methods. Just click that, and your class will get empty implementation of all abstract methods.

Also create the new package "org.myorg.codecompletion.catalog.resources". Place any 16x16 icon and the schema xsd file to that package. I have used this icon in my project. The schema file used by me is po.xsd.

After implementing the empty methods, your class will look something like this:


package org.myorg.codecompletion.catalog;

import java.awt.Image;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.netbeans.modules.xml.catalog.spi.CatalogDescriptor;
import org.netbeans.modules.xml.catalog.spi.CatalogListener;
import org.netbeans.modules.xml.catalog.spi.CatalogReader;
import org.openide.util.Utilities;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 * Catalog to register Schema files to runtime tab
 *
 * -AT-author Vivek Jain (Vivek.Jain@Sun-DOT-COM)
 */
public class RegisterCatalog implements CatalogReader, CatalogDescriptor, EntityResolver {
   
    private static final String PURCHASE_ORDER_XSD = "po.xsd";
    private static final String PURCHASE_ORDER = "http://www.w3.org/2001/XMLSchema/po.xsd";
    private static final String PURCHASE_ORDER_URL = "nbres:/org/myorg/codecompletion/catalog/resources/po.xsd";
    private static final String PURCHASE_ORDER_ID = "SCHEMA:" + PURCHASE_ORDER;
   
    /** Creates a new instance of RegisterCatalog */
    public RegisterCatalog() {
    }
   
    public Iterator getPublicIDs() {
        List<String> list = new ArrayList<String>();
        list.add(PURCHASE_ORDER_ID);
       
        return list.listIterator();
    }
   
    public void refresh() {
    }
   
    public String getSystemID(String publicId) {
        if(publicId.equals(PURCHASE_ORDER_ID)) {
            return PURCHASE_ORDER_URL;
        } else {
            return null;
        }
    }
   
    public String resolveURI(String string) {
        return null;
    }
   
    public String resolvePublic(String string) {
        return null;
    }
   
    public void addCatalogListener(CatalogListener catalogListener) {
    }
   
    public void removeCatalogListener(CatalogListener catalogListener) {
    }
   
    public Image getIcon(int i) {
        return Utilities.loadImage("org/myorg/codecompletion/catalog/resources/Schema.gif";);
    }
   
    public String getDisplayName() {
        return "PurchaseOrder Catalog";
    }
   
    public String getShortDescription() {
        return "XML Catalog for PurchaseOrder Schema";
    }
   
    public void addPropertyChangeListener(PropertyChangeListener propertyChangeListener) {
    }
   
    public void removePropertyChangeListener(PropertyChangeListener propertyChangeListener) {
    }
   
    public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
        if (PURCHASE_ORDER.equals(systemId)){
            return new org.xml.sax.InputSource(PURCHASE_ORDER_URL);
        }
        if (systemId != null && systemId.endsWith(PURCHASE_ORDER_XSD)){
            return new org.xml.sax.InputSource(PURCHASE_ORDER_URL);
        }

        return null;
    }
   
}

Register XML module catalog plugin to Layer.xml


You have to register the Catalog class to Layer.xml inside Plugin/XML/UserCatalogs. You can register it as following:

    <folder name="Plugins">
        <!-- Register XML module catalog plugin -->
        <folder name="XML">
            <folder name="UserCatalogs">
                <file name="org-myorg-codecompletion-catalog-RegisterCatalog.instance">
                    <attr name="instanceCreate" newvalue="org.myorg.codecompletion.catalog.RegisterCatalog"/>
                    <attr name="instanceOf" stringvalue="org.netbeans.modules.xml.catalog.spi.CatalogReader"/>
                </file>
            </folder>
        </folder>
    </folder>

Installing and Using the Plug-in Module


The IDE uses an Ant build script to build and install your plug-in module. The build script is created for you
when you create the plug-in module project.



Installing the Plug-in Module

  • In the Projects window, right-click the "Schema Based Code Completion" project and choose Install/Reload
    in Target Platform.

    The plug-in module is built and installed in the target platform. The target
    platform is set in Tools > NetBeans Platform Manager. The target platform opens so that you
    can try out your new plug-in module. The default target IDE or Platform is the
    installation used by the current instance of the development IDE.

Using the NetBeans Plug-in Module

  •  After your plug-in is built and installed in the target platform, you can go to the runtime tab and see that the schema file gets registered to the XML catalog.
  • Create a new project and create a new empty xml document. Write the xml root element, its namespace and schemaLocation. In our example, xml will look something like this:  
    • <?xml version="1.0" encoding="UTF-8"?>
      <purchaseOrder xmlns='http://www.w3.org/2001/XMLSchema/po.xsd'
                     xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
                     xsi:schemaLocation='http://www.w3.org/2001/XMLSchema/po.xsd po.xsd'>

      </purchaseOrder>
This is all you have to do. You can see the code completion while writing new elements, attributes, etc









  • You can also validate this xml against the schema. The "Validate XML" contextual action will validate your xml file against the schema and report the output.


In case you want to refer the project, I have attached this module project here.