License Management on the NetBeans Platform

The question of the day comes from Manish Dalakoti, working on a freight management system at Lynden in Seattle: "Is it possible to enforce load sequence on modules (something like if an application has four modules A,B,C,D  – B, C and D  loads only if authentication in A succeeds)."

So, I've made a small sample to simulate the scenario:

The "Editor" module and the "Viewer" module are only installed if the "LicenseManager" is installed. That conditional loading is obtained by means of this section in the project.xml of the "LicenseManager":

<module-dependencies>
    <dependency>
        <code-name-base>org.con.editor</code-name-base>
        <run-dependency>
            <specification-version>1.0</specification-version>
        </run-dependency>
    </dependency>
    <dependency>
        <code-name-base>org.con.viewer</code-name-base>
        <run-dependency>
            <specification-version>1.0</specification-version>
        </run-dependency>
    </dependency>
    ...
    ...
    ...

The above shows the "LicenseManager" has runtime dependencies on the "Editor" (org.con.editor)  and on the "Viewer" module (org.con.viewer).

In addition, the "Editor" module and the "Viewer" module are both marked as being "Autoload" modules, which means that when the "LicenseManager" is loaded (it is a "Regular" module) it will, because of the above runtime dependencies, result in the "Editor" and "Viewer" module being loaded.

The "LicenseManager" will, itself, only load under a specific condition, which is set in its "ModuleInstall" class:

public class Installer extends ModuleInstall {

    @Override
    public void validate() throws IllegalStateException {
        NotifyDescriptor.InputLine inputMessage = new NotifyDescriptor.InputLine(
                "Enter License Key:",
                "License Key",
                NotifyDescriptor.OK_CANCEL_OPTION,
                NotifyDescriptor.QUESTION_MESSAGE);
        Object result = DialogDisplayer.getDefault().notify(inputMessage);
        if (NotifyDescriptor.YES_OPTION.equals(result)) {
            String enteredLicenseKey = inputMessage.getInputText();
            if (!enteredLicenseKey.equals("123456")) {
                throw new IllegalStateException(
                        "License Key was incorrect. "
                        + "Editor and Viewer will not be installed.");
            }
        } else {
            throw new IllegalStateException(
                    "License Key was not entered. "
                    + "Editor and Viewer will not be installed.");
        }
    }
    
}

Now the "LicenseManager" is only installed if "123456" is typed (i.e., a dummy license key) when the application starts. If the correct license key is entered, the "LicenseManager" is installed, together with the "Editor" module and the "Viewer" module, as well as the "Analyzer" module, which has not conditional loading defined (it is a "Regular" module). If the license key is not entered, only the "Analyzer" module will be installed, together with the NetBeans Platform itself, of course.

The above is one solution for a license management scenario and I'll be looking into a Maven based solution too, which Manish will be interested in, I'm sure, since Lynden has a Mavenized NetBeans Platform application. I'm sure others have other solutions here and I'm looking forward to a few ideas on this topic in the comments to this blog entry!

Comments:

Making the license manager depend on the feature modules is perverse, and will not work if you want to have different distributions of the app with varying feature subsets. Your scheme will also cause the feature modules to be enabled if any regular module depends on them by accident.

What you want is to make the feature modules (which should generally be regular modules!) depend on the license manager. Either way, using Maven vs. Ant makes no difference.

Keep in mind that any such system does not offer any real protection; any user can trivially edit out the dependency on the license manager in the feature module's manifest. Nor is it sufficient for apps needing authentication to some server: every call to a remote API will anyway need to pass a valid authentication token; at best you will just hide some functions from the GUI if a user refuses to authenticate.

And this is a crappy way to do that UI, since you have to restart the app (and possibly reenable things in Plugin Manager) if you later decide to buy a license, suddenly remember the name of your first pet, or whatever the app is asking for.

IMHO shoving this kind of logic into the module layer is a bad idea. Better to leave all modules unconditionally enabled and just show an authentication dialog, license key entry dialog, etc. the first time the user uses some feature which actually requires it. (You can use the Keyring API to avoid prompting in subsequent sessions.)

If many users are expected to use some, but not other, features of the app on a long-term basis, they can use Plugin Manager to disable the controlled features so they do not clutter the UI; and a license/auth dialog upon being canceled without a passing response could prompt to turn off the controlled features as a convenience (while clearly indicating how to undo this).

Posted by Jesse Glick on December 23, 2011 at 02:42 AM PST #

Post a Comment:
  • HTML Syntax: NOT allowed
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 2014
SunMonTueWedThuFriSat
  
12
13
14
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today