Integrating the license manager with your JAVA software

The first step to take is to obtain the license manager class shown in section License manager integration and add it to your product code. For this tutorial we are going to use the default the Variant from license template.

This class can be changed at will, but avoid touching the code between comments saying /*CONSTANTS BEGIN - DO NOT CHANGE*/ and /*CONSTANTS END - feel free to modify everything else*/.

You will also need to have the univocity-license-manager.jar added to your classpath. See License manager download

Integrating the license manager with your product

Here is the full and complete source code of the product we are going to sell, before introducing any license management code:

class MagicalThing {

    public static void main(String ... args){
        System.out.println("Magic!");
    }
}

The template class we downloaded previously can now be introduced to the code to make our product “licenseable”:

class MagicalThing {

    public static void main(String... args) {
        //Get the license manager instance which allows you to manage the license currently in use
        LicenseManager licenseManager = MyProduct.licenseManager();

        // Displays the built-in license manager user interface. It's there for your convenience so
        // you don't have to write code for that. You don't have to use it if you don't want to.
        licenseManager.start();

        //Let's get license currently in use
        License license = licenseManager.getLicense();

        if (license == null) {
            System.out.println("No license found. Bye.");
            System.exit(0);
        } else { //print license details
            System.out.println(license.getProductName() + " - " + license.getProductVariant()
                    + " " + license.getProductVersion() + " - Licensed to " + license.getEmail());

            if (license.isTrial()) {
                System.out.println("Your trial will expire on " + license.getLicenseExpirationDate("yyyy-MM-dd"));
            } else {
                System.out.println("Upgrade support until " + license.getSupportEndDate("yyyy-MM-dd"));
            }
        }

        //validate license (locally). A remote background process will synchronize the local license with the server.
        LicenseValidationResult licenseValidationResult = MyProduct.licenseManager().validate();

        //verifies the result and execute program if the local license is valid.
        if (licenseValidationResult == VALID) {
            System.out.println("Magic!");
        } else {
            System.err.println("Invalid license: " + licenseValidationResult);
        }
    }
}

This code now checks whether a license exists and prints out its details to the output. A very basic license validation is performed here, by checking that LicenseValidationResult is VALID. The License validation section explores the possible outcomes of the license validation process in detail. For now, let’s keep it simple.

The code above will invoke the built-in license manager dialog, which looks like this:

If you run this on a server without a graphical user interface, then the built-in command-line license manager will start, displaying:

The built-in license manager allows you to provide a custom logo, icon and license agreement terms that the user must accept prior to obtaining the license and running your software:

licenseManager.setIcon(java.awt.Image);
licenseManager.setLogo(java.awt.Image);
licenseManager.setLicenseAgreementHtml(java.lang.String);
licenseManager.setLicenseAgreementText(java.lang.String);

With a proper icon and logo set, the dialog is much more presentable:

You don’t have to use the built-in dialog or command-line interfaces to manage the license workflow for you. The License management API section demonstrates how to programmatically interact with the license server.

Let’s obtain a trial license to get our program running. On the license dialog, click the Trial License button and then provide your name and e-mail:

Click on button Request trial and wait for your license.

Now the license manager dialog will display your trial license details:

Notice the serial key label has no value associated. That is generated for actual licenses that have been purchased and allocated to a given person.

If you run the code now that you have a license, the output of the program will be something like this:

MagicalThing -  1.0.0 - Licensed to jbax@univocity.com
Your trial will expire on 2018-09-03
Magic!

Our basic coding work is pretty much done. The product is ready to go to the market. We just need to see how an actual license purchase and activation works by buying our own product from the online store. For that, follow the steps in section Generating test licenses to generate a test license and assign it to yourself.

License activation

With a valid serial key and e-mail address, you can start the program again. The current trial license details will be shown to you:

You can click the Activate button to activate the serial key sent to your e-mail:

Once the activation process is complete, the details on the license dialog will be updated to reflect your current license details:

You are using a licensed product now!

License validation

Once the license is active, you can execute the software as many times as you want. On our example we made it show the license dialog at startup to easily allow you to play with the user interface.

There’s not a lot to see after the license is active. Let’s make changes to the license itself to see how the program behaves.

Removing a license and waiting for the server response

Go to the license management page and remove your license (as shown in section Removing a license).

Now, if you run the code again, it will perform the license validation against the license stored locally first (so your program can start as soon as possible), while a remote validation process will soon update the local copy in the background. As our test program doesn’t do a lot it will still execute normally on the first run, while the license is removed in the background. From the second run the license won’t be available anymore.

You can make the program wait for the server validation result and only execute the code after that result is ready by rewriting it like this:

class MagicalThing {

    public static void main(String... args) {
        //Get the license manager instance which allows you to manage the license currently in use
        LicenseManager licenseManager = MyProduct.licenseManager();

        // Displays the built-in license manager user interface. It's there for your convenience so
        // you don't have to write code for that. You don't have to use it if you don't want to.
        licenseManager.start();

        //wait for license server to return validation result
        licenseManager.validate(new LicenseValidationAction() {
                @Override
                public void licenseValidated(LicenseValidationResult result) {
                    if (result == VALID) {
                        System.out.println("Magic!");
                    } else {
                        System.err.println("Invalid license: " + result);
                    }

                    //Let's get the license currently in use
                    License license = MyProduct.licenseManager().getLicense();
                    if (license != null) {
                        System.out.println(license.getProductName() + " - " + license.getProductVariant()
                                + " " + license.getProductVersion() + " - Licensed to " + license.getEmail());

                        if (license.isTrial()) {
                            System.out.println("Your trial will expire on " + license.getLicenseExpirationDate("yyyy-MM-dd"));
                        } else {
                            System.out.println("Upgrade support until " + license.getSupportEndDate("yyyy-MM-dd"));
                        }
                    }
                }
            }
        );
    }
}

However on a typical application (which runs for more than a few seconds at a time) you won’t have to do this.

License management API

The univocity-license-manager.jar comes with an easy to use API that allows you to code your own software activation workflow, so you don’t have to use the built-in license dialog or the command-line interfaces to manage the license workflow for you.

We are happy to introduce alternative licensing workflows that can for you at no cost if we think it’s useful to other users as well. Contact us with your requirements and we may work on your use case.

So let’s get started with the API.

Activating a user license

To activate a user license, use method assignLicense of class LicenseManager:

// ask user for e-mail and serial key:
String email = "user@email.com";
String serialKey = "SOME-USER-KEY0-CODE";

try {
    License license = MyProduct.licenseManager().assignLicense(email, serialKey);
    
    //got a valid license, let's read some of its details:
    
    String formattedExpirationDate = license.getLicenseExpirationDate("dd MMM yyyy");
    String formattedSupportEndDate = license.getSupportEndDate("dd MMM yyyy");
    
} catch(LicenseRegistrationException e){
    // could not process the email and serial key.
    
    // the `validationResult` encodes the cause of the error
    LicenseValidationResult validationResult = e.getValidationResult();
    
    // and you also have an error message explaining what went wrong.
    String errorMessage = e.getMessage();
}

Requesting a trial license

To activate a user license, use method assignTrial of class LicenseManager:

//ask user for e-mail, first and last name:
String email = "user@email.com";
String firstName = "John";
String lastName = "Doe";

try {
    License license = MyProduct.licenseManager().assignTrial(email, firstName, lastName);

    //got a valid license, let's read some of its details:

    String formattedExpirationDate = license.getLicenseExpirationDate("dd MMM yyyy");
    String formattedSupportEndDate = license.getSupportEndDate("dd MMM yyyy");

} catch(LicenseRegistrationException e){
    // could not process the email and serial key.

    // the `validationResult` encodes the cause of the error
    LicenseValidationResult validationResult = e.getValidationResult();

    // and you also have an error message explaining what went wrong.
    String errorMessage = e.getMessage();
}

Validating the user’s license

To validate the user license, use method validate of class LicenseManager:

// validates the current license.
LicenseValidationResult licenseValidationResult = MyProduct.licenseManager().validate();

// you can test each result type to give your user a human-readable message that explains what is going on.
switch (licenseValidationResult) {
    case VALID: //that's the only result that indicates the license is valid.
        return;
    case INVALID:
        System.err.println("Your license is not valid");
        break;
    case EXPIRED:
        System.err.println("Your license expired");
        break;
    case SUPPORT_ENDED:
        System.err.println("You can't upgrade to this version as your license is too old. Please renew your license.");
        break;
    case INCOMPLETE:
        System.err.println("Your license details are incomplete");
        break;
    case UNKNOWN_HOST:
        System.err.println("This computer is not recognized.");
        break;
    case TRIAL_EXPIRED:
        System.err.println("Your trial period has ended.");
        break;
    case TRIALS_DISABLED:
        System.err.println("No trial licenses allowed.");
        break;
    case DISABLED:
        System.err.println("Your license has been disabled.");
        break;
    case RETRIAL_ATTEMPTED:
        System.err.println("You can't request another trial license.");
        break;
    case LICENSE_TRANSFER_DISABLED:
        System.err.println("Your license has already been registered elsewhere and can't be transferred to this device.");
        break;
    case NOT_FOUND:
        System.err.println("No license found.");
        break;
    case ERROR:
        System.err.println("Internal error validating your license. Please contact support.");
        break;
}
//makes the program exit as the license is not valid.
System.exit(0);

The above example runs the validation against the license stored locally and at the same time, if it is the first time it’s called since the program started, validates the license against the server.

Any updates to the license that are returned by the server will be applied in the background.

You can call this method multiple times as the internal implementation will only connect to the remote license server once every few hours.

If you want to implement any custom logic to handle when the license server responds, use method validate of class LicenseManager that takes a LicenseValidationAction parameter:

The LicenseValidationAction is a callback that will be called once the server returns its remote license validation result.


LicenseValidationResult localValidationResult = licenseManager.validate(new LicenseValidationAction() {
    @Override
    public void licenseValidated(LicenseValidationResult remoteValidationResult) {
        //executes eventually, when the license server returns its validation result
        if (remoteValidationResult != VALID && remoteValidationResult != ERROR) {
            System.out.println("Sorry to interrupt you, but no valid license has been found. Exiting...");
            System.exit(0);
        }
    }
});

// The local result will be available immediatelly. The code inside the
// `LicenseValidationAction` defined above will execute some time after this code
// block executes 
if(localValidationResult == VALID){
    //allow the program to start normally.
}

Configuring the path to the license file

By default the license manager will store copies of the software license in 2 locations:

  1. An operating-system dependent store (such as the Window’s registry) that the user has no (easy) access to.

  2. A local file in the filesystem, used as backup if the operating-system store is not available.

The license text is not human readable to prevent tampering.

To update the location of the local file mentioned in item (2), use getLicenseFilePath:

String pathToLicenseFile = MyProduct.licenseManager().getLicenseFilePath();

boolean pathChanged = MyProduct.licenseManager().setLicenseFilePath("/some/other/path");
if(pathChanged){
    System.out.println("License path updated successfully");
}

Deleting the local license

You can delete locally stored license with:

    MyProduct.licenseManager().deleteLicense();

This allows your user to provide another license key, or reactivate their existing license.

Configuring a proxy

Corporate users are usually behind a proxy that must be configured to allow your software to communicate with the license server. In such cases, you should use the setProxy method to pass along the configuration required before any contact with the license server is attempted (via validate, assignLicense or assignTrial):

Proxy.Type proxyType = Proxy.Type.HTTP;
String host = "corporate.proxy";
int port = 50600;
String username = "username";
char[] password = "S3cret!".toCharArray();

MyProduct.licenseManager().setProxy(proxyType, host, port, username, password);

Further Reading

If you find a bug

We deal with errors very seriously and stop the world to fix bugs in less than 24 hours whenever possible. It’s rare to have known issues dangling around for longer than that. We provide a test environment for you to test whether our updates work for you as soon as the adjustments are made.

If you have suggestions or find a bug don’t hesitate to open an issue here or send us send us an e-mail.

We are happy to help if you have any questions in regards to how to use our app for your specific use case. Just send us an e-mail with your query and we’ll reply as soon as humanely possible.

We can work for you

If you don’t have the resources or don’t really want to waste time coding we can build a custom solution for you using our products. We deliver quickly as we know the ins and outs of everything we are dealing with. Send us an e-mail to sales@univocity.com with your requirements and we’ll be happy to assist.

The univocity team.

www.univocity.com