BookNBPlatformCookbookCH0303

Contents

NetBeans Platform Cookbook Chapter 03 03

Provide Service Implementation

Some modules have defined an API interfaces (or base classes) for some functionality. If they need use them they ask the central registry of services if any implementation is installed. If yes then it uses it. If several implementation of the service are installed it uses the first one or lets the user select which provider will be used. This is called as extension point. Other modules provide an implementation of the service and register it into the central registry - they are called service providers.


Preparation

We suppose for this example that some MyView API module defines the MyView interface for View - object that knows how to visualize MyData data - hierarchical tree of data. This module is described in the previous tip Offer an Extension Point. The MyView interface looks like:

/** General interface for view used in MyView-like application.
 * New instances are made by MyViewFactory.
 * If you do not look up its any implementation the default one will be used.
 */
public interface MyView {

    public JComponent getComponent();

    public MyData getMyData();

    public void setMyData(MyData myData);

}

The factory creating new MyView instances is described so:

/** General interface for factory creating MyView instances.
 * If you do not look up its any implementation the default one will be used.
 */
public interface MyViewFactory {

    public String getFactoryName();

    public MyView createMyView(); 

}

The method getFactoryName() returns name of the implementation. You can use it when the user selects the implementation for an action or in the Options window.

Describe the extension point in the documentation - what is needed, interface contract and how to register a new service provider. We define an interface MyData for data in base package mymodule.pkg.api:

public interface MyData {
    public void addChild(MyData chch);
 
    public MyData [] getChildren();
    public String getText();
    public void setText(String s);
}  

How to

Create the default implementation of the service if you will provide it. We will visualize the data structure by structured printed text in the TextArea.First create subpackage - e.g. dftview - of the base package and implement the factory in it:

/** Default implementation of MyViewFactory interface 
 * creating MyView instances
 * - is used when any other implementation was not found.
 *
 * Note the position parameter is so big
 * to esure other better implementations will be found before it.
 * If no other implementation is found then the default this is used.
 */
@ServiceProvider(service=MyViewFactory.class, position=9999999)
public class DefaultMyViewFactory implements MyViewFactory {

    private static final String implName =
                            NbBundle.getMessage(DefaultMyViewFactory.class
                          , "DefaultMyViewFactory.implementationName");
    
    public DefaultMyViewFactory() {
    }

    public String getFactoryName() {
        return implName;
    }

    public MyView createMyView() {
        return new DefaultMyView();
    }

}

The annotation line

@ServiceProvider(service=MyViewFactory.class, position=9999999)

registers this class as a service implementing MyViewFactory interface. The big position parameter ensures that each other added service provider will be found before this default.

Now the DefaultMyView class. For our example we create simple visualization by printing the data structure to the text area. Create new JPanel form, set the BorderLayout and add the JTextArea into it.

Switch to the source editor and implement the MyView interface. (We can implement it in the panel. It is not need to create new class.):

public class DefaultMyView extends javax.swing.JPanel  implements MyView {  
...

Add the new myData property (by IDE) of type MyData, methods getMyData() and setMyData() will be created.

Initialize the myData member:

      
     // if you provide MyData by service similar as MyView implementation
     MyDataFactory fac = Lookup.getDefault().lookup(MyDataFactory.class);
     this.myData = fac.createMyData();

In the getComponent() return this (we did not create an extra object for MyView interface plus the JPanel).

    public JComponent getComponent() {
        return this;
    }

Add the reloadText() method call into the setMyData() method to refresh the view.

Implement the reloadText() method to load text from data structure.

    private void reloadText() {
        StringBuilder sb = new StringBuilder();
        reloadText(this.myData, sb, "");
        txtArea.setText( sb.toString() );
    }

    private void reloadText(MyData data, StringBuilder sb, String pref) {
        sb.append( pref );
        sb.append( data.getText() );
        sb.append( "\n" );

        MyData[] chs = data.getChildren();
        for (int i = 0; i < chs.length; i++) {
            MyData dta = chs[i];
            reloadText(dta, sb, pref + "   ");
        } // for i chs
    }

Pass through data tree and print it by indentation.

Take care about other functionality and listen to changes in your object.

And More

Try to create the next implementation of the MyView service and add it to the application. Create new module viewtxttree module within your suite. Set its dependency on view_api module. And on Lookup API and Utilities API.

It is an exercising. So copy the default implementation here and change it. Right-click on the DefaultMyViewFactory, select Refactor item in the pop-up menu, then select Copy. Change new name to TxtTreeMyViewFactory and select moving into viewtxttree module.

Do the same for DefaultMyView class, name the copy TxtTreeMyView. Change text of the implementation name (e.g. “Tree view by text”) and returned class in the createMyView() method to TxtTreeMyView.

Create visualizing by other way. We will simulate the structure of nodes (a JTree) by printed text, tree lines are printed by '-' and '|' chars:

    private void reloadText(MyData data, StringBuilder sb, String pref) {
        sb.append( pref );
        sb.append("- ");
        sb.append( data.getText() );
        sb.append( "\n" );

        MyData[] chs = data.getChildren();
        for (int i = 0; i < chs.length; i++) {
            MyData dta = chs[i];
            reloadText(dta, sb, pref + "   |");
        } // for i ch
    }

Do not set any other dependency and do not publish any publish package. We expose the MyViewFactory interface as a service only.

Build and run the application used your provider (it si in example sources and described in the previous tip Offer an Extension Point) again. If you click on top component (set it activated) the date gets visible. There are two implementations in the combo box. You can switch these two visualizations:

 DefaultMyView          Tree view by text 
 from API module        from txttreeview module
      
 root                             - root
   1                                |- 1
      1.1                           |  |- 1.1
      1.2                           |  |- 1.2
      1.3                           |  |- 1.3 
   2                                |- 2
      2.1                           |  |- 2.1
      2.2                           |  |- 2.2
      2.3                           |  |- 2.3 
      ....                            .....

Now open examples prepared for this book, find the treenode module (com-packtpub-nbpcook-service-view-treenode.nbm file) in the 03_Lookup/Service/ directory.

Run the application, if it is not running.

Install prepared module com-packtpub-nbpcook-service-view-treenode.nbm. (You did it in the previous section, too. See images there.)

Choose in menu Tools / Plugins.

Switch to the Downloaded tab.

Press Add Plugin button. The File Chooser is appeared. Find the nbm-file.

Press Install button (the plugin must be selected), pass through installation wizard and close the Plugins frame.

Explore content of the combo box - the "Tree view by nodes" provider was appeared.

Select it. The data structure is shown by Nodes tree.

image:Nbpcook_03_04_serviceplugin.png

Figure 3.5 Usage of the new installed view.


Sort example

To show how you can provide an extension point - visualizing sort - we prepared an ServiceSort example in the 03_Lookup/Service/ directory.

Sort algorithms were taken from JDK Sort Demo (and other pages - see example description) and ugly adapted to NBP service. The basic module sorting defines interfaces, panels and a TopComponent to show running algorithms and provides some implementations, too: empty NoSort, Bubble Sort, Bidirectional Sort and Quick sort. The next module SortMergeAlg provides Merge Sort as a service provider in its own module.

image:Nbpcook_03_06_serviceSort.png

Figure 3.6 Sort algorithms as a service.


Text and sources were created under NB 6.8, 6.9, 7.0, 7.1.

Navigation

Not logged in. Log in, Register

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo