Tuesday Apr 29, 2008

Introducing "Feature on Demand"

As your application gets larger, the end user experiences two problems: the download size increases and performance slows down. Not necessarily so, but the likelihood of these problems increases as time goes by. That's where modular systems come in handy, because they let the end user choose the modules they want while discarding all those they don't need. However, that process is problematic. How does the end user know which module provides which features? And then there's the problem of the ui that you provide for making features available, which is often not optimal for all your users. Sure, you could let the application automatically install all features and all updates to all features. That might be useful for many of your users. However, not all users want all features and all updates. On the one hand, these users would like to be able to select which features (and which updates to features) they want, but they also want the process to be really simple.

Welcome to "feature on demand". That's a new NetBeans Platform concept that's in the process of being evolved. It aims to enable you to provide the user with a really lightweight application (i.e., very small download, very small footprint, very small number of modules, very small everything). However, despite the lightness of the application, all/most of its ui is already available. Then, whenever the end user wants to use a feature in the application, such as a particular window, the application will automatically install that window, in the background. How? By making a menu item (or other entry point) available which, when invoked, causes the related module to download in the background, install itself automatically into the application, and immediately make its ui elements (such as a new window) available to the end user.

Potentially three parties are involved in this process:

  • The end user. I.e., granny Smith at home, filling in her tax returns in an application created on top of the NetBeans Platform.

  • The "feature on demand" service consumer. This is the developer who makes use of an existing entry point in the application by plugging into it. For example, let's say the developer writes a module and puts it into an update center. The module provides a new window in the application. In a separate module that is part of the application's official distribution (i.e., or that is installed automatically, or in some very simple way) the developer specifies that the module should be installed on demand, i.e., only when granny Smith invokes the related menu item. This module, i.e., the module consuming an entry point, is very small (just one or two XML files, as you can see in the example screenshot below), whereas the module (or multiple modules, including external libraries) providing all the functionality is much larger. Hence, distributing entry point consumers with your application is much more economical than distributing fully fledged features. In effect, you're distributing fake ui (such as a menu item that appears to invoke a window, while in fact it also installs it), while the real feature will be installed when the fake ui is used.

  • The "feature on demand" service provider. By default, "feature on demand" entry points exist (at least, currently) for new actions and new project types. That means that the service consumer can make use of these two entry points out of the box. However, potentially, you'd want additional entry points for your own features. Possibly your feature is not related to a menu item or project type. For example, when granny Smith tries to hyperlink in NetBeans IDE from one location to another, the module that provides that feature could be installed in the background, if the service provider provides such an entry point to the service consumer. The service provider is not concerned with specific modules, i.e., the service provider doesn't know what modules the service consumers will want to make available. The service provider simply makes entry points into the application available. This person will have a very technical knowledge of the application, while the service consumer needs to do nothing other than provide XML files that define how the entry point should be consumed in a particular case. The service provider and the service consumer could be the same person. And, of course, granny Smith at home could be all three at once, although this is less likely.

The end user, i.e., granny Smith, only gets involved in this whole cycle when she selects the menu item (or whatever the service provider makes available to the service consumer to let granny Smith demand the feature). But what about the service consumer? How does the service consumer consume the entry point? Let's say the service consumer wants to make the Module Manager available to granny Smith, but only when granny Smith selects the menu item to invoke it. Note that the Module Manager is a window in the IDE, provided by a module that's in the Update Center in 6.0 and 6.1, but never installed by default. Here's all that the service consumer needs to do to provide a fake "Module Manager" menu item in the Window menu which, when clicked, will install the Module Manager in the background:

Here's the content of the "modulemanager.xml" file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd">
<filesystem>
    //We want to contribute a new menu item to the application:
    <folder name="Menu">
        //The new menu item will be within the Window menu:
        <folder name="Window">
            //The unique identifier of the menu item:
            <file name="org-yourorghere-modulemanager-ModuleManagerAction.instance">
                //The reference to the API to which we delegate the creation of the menu item:
                <attr name="instanceCreate" methodvalue="org.netbeans.spi.actions.support.Factory.delegate"/>
                //The reference to the service provider's action that will be invoked when the menu item is created:
                <attr name="delegate" methodvalue="org.netbeans.modules.autoupdate.featureondemand.api.Factory.newAction"/>
                //The module that will be installed when the menu item is selected:
                <attr name="codeName" stringvalue="org.netbeans.modules.modulemanager"/>
                //The localization bundle that contains the display name of the menu item:
                <attr name="SystemFileSystem.localizingBundle" stringvalue="org.yourorghere.modulemanager.Bundle"/>
                //The key in the localization bundle that defines the display name of the menu item:
                <attr name="ActionName" stringvalue="org-yourorghere-modulemanager-ModuleManagerAction" />
                //The position of the menu item within the Window menu:
                <attr name="position" intvalue="10"/>
            </file>
        </folder>
    </folder>
</filesystem>

The above looks a lot like a layer.xml file, doesn't it? That's because that's what it is. It is known as the "delegate layer file", which is injected into the System FileSystem under certain conditions. Which conditions? The conditions are specified in the layer.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd">
<filesystem>
    //The official "feature on demand" folder in the System FileSystem:
    <folder name="FeaturesOnDemand">
        //The unique name of this entry in the "feature on demand" folder:
        <file name="org-yourorghere-modulemanager-ModuleManagerAction.instance">
            //The API class that holds the delegate layer file, with related information:
            <attr name="instanceCreate" methodvalue="org.netbeans.modules.autoupdate.featureondemand.api.FeatureInfo.create"/>
            //The presence of this plugin determines whether the delegate layer will be injected
            //i.e., if this plugin is not installed, the menu item will be shown, and vice versa,
            //this plugin could potentially be different to the plugin that the menu item will install:
            <attr name="codeName" stringvalue="org.netbeans.modules.modulemanager"/>
            //The location of the delegate layer file:
            <attr name="delegateLayer" urlvalue="nbresloc:/org/yourorghere/modulemanager/modulemanager.xml"/>
        </file>
    </folder>
</filesystem>

So, now, granny Smith, filling in her tax returns, would see "Module Manager" in the Window menu (if the Module Manager plugin isn't already installed). She would, if she selects the Module Manager menu item, see that the related plugin installs and then immediately makes the Module Manager available. Until that point, the Module Manager will not be installed in the application and thus will not be weighing down the application, in terms of download size, footprint, and performance. By the way, all of this assumes that the plugin that will be installed on demand is actually available in one of the registered update centers.

Everything required for implementing "Feature on Demand" is already available in the "contrib" module in the NetBeans sources. For more information on this, together with several demos, including how to provide a new entry point, come to the JavaOne BOF "Toward a Consumer IDE: Get What You Want When You Want It (BOF 5091)", on Wednesday 18.30-19.20. I will be presenting this BOF together with the engineer who conceptualized and implemented "Feature on Demand", the NetBeans update center guru Jiri Rechtacek.

About

Geertjan Wielenga (@geertjanw) is a Principal Product Manager in the Oracle Developer Tools group living & working in Amsterdam. He is a Java technology enthusiast, evangelist, trainer, speaker, and writer. He blogs here daily.

The focus of this blog is mostly on NetBeans (a development tool primarily for Java programmers), with an occasional reference to NetBeans, and sometimes diverging to topics relating to NetBeans. And then there are days when NetBeans is mentioned, just for a change.

Search

Archives
« April 2008 »
SunMonTueWedThuFriSat
  
2
4
5
13
18
19
23
30
   
       
Today