# Using the API

Your generated project provides an internationalized Application Programming Interface (API) for vending and consuming license keys in the modules keygen (alias Key Generator) and keymgr (alias Key Manager) respectively. This page walks you through the typical lifecycle of a license key using these modules.

TIP

The generated classes in these modules depend on the TrueLicense API, among others. Source code and Javadoc for the TrueLicense API are available on Maven Central (opens new window).

# Using the Key Generator API

WARNING

The Key Generator module generates license keys for your software product without requiring authorization! Therefore, you should keep this module under lock and key. In particular, do not distribute it to users or the public. The same concern applies to any derivative work which includes this module.

# Setting Up the Class Path

# With Maven

Using Maven is the recommended way to integrate the generated project into your software product. Add the following dependency to the POM for your software product:

<dependency>
    <groupId>${groupId}</groupId>
    <artifactId>${artifactId}-keygen</artifactId>
    <version>${version}</version>
</dependency>

Assuming the property values of the page Getting Started, this would expand to:

<dependency>
    <groupId>com.company.product</groupId>
    <artifactId>stargazer-keygen</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

# Without Maven

Without a build tool, you need to manually add the JARs of the project to the classpath of your software product.

You can add the standalone JAR keygen/target/${artifactId}-keygen-${version}-standalone.jar to the classpath. This is convenient because the standalone JAR contains all transitive dependencies, so you only need to add this JAR to the classpath.

If some dependencies bundled in the standalone JAR conflict with other dependencies of your software product however, then you may need to add only selected JARs to the class path. First, copy the runtime dependencies to the directory keygen/target/dependency using:

$ export JAVA_HOME=$(/usr/libexec/java_home -v 1.8) # on macOS only
$ chmod +x mvnw
$ ./mvnw package dependency:copy-dependencies -DincludeScope=runtime --projects keygen
[...]
$ ls keygen/target/dependency
fun-io-api-2.3.0.jar             jackson-annotations-2.10.2.jar   truelicense-core-4.0.3.jar
fun-io-bios-2.3.0.jar            jackson-core-2.10.2.jar          truelicense-obfuscate-4.0.3.jar
fun-io-jackson-2.3.0.jar         jackson-databind-2.10.2.jar      truelicense-spi-4.0.3.jar
fun-io-spi-2.3.0.jar             truelicense-api-4.0.3.jar        truelicense-v4-4.0.3.jar

Now you can select each JAR which you want to add to the classpath from this directory. Don’t forget to add the regular JAR keygen/target/${artifactId}-keygen-${version}.jar to the classpath, too.

# Introduction to the API

When building your project, the following classes get generated from a set of Apache Velocity template files - listed in alphabetic order:

com.company.product.keygen.LicenseManager

The enumeration of the vendor license managers for your software product. The managers get named like each configured edition and ordered from superset to subset. Each manager gets configured with the algorithms and parameters for generating license keys for the respective edition.

com.company.product.keygen.Main

The command line interface for vending license keys.

The main entry point to the API is the enumeration class LicenseManager. For example, if the project sets the property editions to enterprise standard, then this class looks as follows:

package com.company.product.keygen;

public enum LicenseManager implements VendorLicenseManager {

    enterprise { /*...*/ },
    standard { /*...*/ };

    /*...*/
}

For the following examples, it’s necessary to add the following imports:

import com.company.product.keygen.*;
import global.namespace.fun.io.api.*;
import global.namespace.truelicense.api.*;

import static global.namespace.fun.io.bios.BIOS.*;

# Generating a License Key

You can generate a license key using:

VendorLicenseManager manager = LicenseManager.${edition};
License input = manager.context().licenseFactory().license();
Sink sink = file("${license-key-path}");
License output = manager.generateKeyFrom(input).saveTo(sink).license();

… where ${edition} expands to an edition of your software product and ${license-key-path} expands to the path of the license key file. For a fully elaborated example, please have a look at the Main class.

TIP

You can omit the last call to license() if you are not interested in a duplicate of the saved (output) license bean.

# Working with Runtime Exceptions

The VendorLicenseManager interface may throw a LicenseManagementException, which extends GeneralSecurityException, which in turn extends the checked Exception. Working with checked exceptions may be cumbersome in contexts where a method gets constrained to only throw unchecked exceptions, e.g. when implementing functional interfaces like Runnable.run(). For cases like this there is an adapter method named VendorLicenseManager.unchecked(): This method adapts a vendor license manager so that it may throw a UncheckedLicenseManagementException, which extends the unchecked RuntimeException and simply wraps the original LicenseManagementException. Here’s the general usage pattern:

VendorLicenseManager checkedManager = LicenseManager.${edition};
UncheckedVendorLicenseManager uncheckedManager = checkedManager.unchecked();
License input = uncheckedManager.context().licenseFactory().license();
Sink sink = file("${license-key-path}");
License output = uncheckedManager.generateKeyFrom(input).saveTo(sink).license();

As you see, the call sequence is the same as in the previous example. You can get back the original (checked) vendor license manager by calling:

UncheckedVendorLicenseManager uncheckedManager = ...;
VendorLicenseManager checkedManager = uncheckedManager.checked();

# Using the Key Manager API

# Setting Up the Class Path

# With Maven

Using Maven is the recommended way to integrate the project into your software product. Add the following dependency to the POM for your software product:

<dependency>
    <groupId>${groupId}</groupId>
    <artifactId>${artifactId}-keymgr</artifactId>
    <version>${version}</version>
</dependency>

Assuming the property values of the page Getting Started, this would expand to:

<dependency>
    <groupId>com.company.product</groupId>
    <artifactId>stargazer-keymgr</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

# Without Maven

Without Maven, you need to manually add the JARs of the project to the classpath of your software product.

You can add the standalone JAR keymgr/target/${artifactId}-keymgr-${version}-standalone.jar to the classpath. This is convenient because the standalone JAR contains all transitive dependencies, so you only need to add this JAR to the classpath.

If some dependencies bundled in the standalone JAR conflict with other dependencies of your software product however, then you may need to add only selected JARs to the class path. First, copy the runtime dependencies to the directory keymgr/target/dependency using:

$ export JAVA_HOME=$(/usr/libexec/java_home -v 1.8) # on macOS only
$ chmod +x mvnw
$ ./mvnw package dependency:copy-dependencies -DincludeScope=runtime --projects keymgr --also-make
[...]
$ ls keymgr/target/dependency
fun-io-api-2.3.0.jar             jackson-core-2.10.2.jar          truelicense-spi-4.0.3.jar
fun-io-bios-2.3.0.jar            jackson-databind-2.10.2.jar      truelicense-swing-4.0.3.jar
fun-io-jackson-2.3.0.jar         truelicense-api-4.0.3.jar        truelicense-ui-4.0.3.jar
fun-io-spi-2.3.0.jar             truelicense-core-4.0.3.jar       truelicense-v4-4.0.3.jar
jackson-annotations-2.10.2.jar   truelicense-obfuscate-4.0.3.jar

Now you can select each JAR which you want to add to the classpath from this directory. Don’t forget to add the regular JAR keymgr/target/${artifactId}-keymgr-${version}.jar to the classpath, too.

# Introduction to the API

When building your project, the following classes get generated from a set of Apache Velocity template files - listed in alphabetic order:

com.company.product.keymgr.LicenseManager

The enumeration of the consumer license managers for your software product. The managers get named like each configured edition and ordered from superset to subset, including an optional FTP. Each manager gets configured with the algorithms and parameters for installing, loading, verifying and uninstalling license keys for the respective edition.

com.company.product.keymgr.Main

The command line interface for consuming license keys.

The main entry point to the API is the enumeration class LicenseManager. xFor example, if the project sets the properties editions and freeTrialPeriod to enterprise standard and 30 respectively, then this class looks as follows:

package com.company.product.keymgr;

public enum LicenseManager implements ConsumerLicenseManager {

    enterprise { /*...*/ },
    standard { /*...*/ },
    ftp { /*...*/ };

    public static LicenseManager get() { return ftp; }

    /*...*/
}

Consumer license managers get arranged in a chain of responsibility, ordered from feature subset to feature superset (which is the reverse order of the items in the enumeration class LicenseManager): When installing, loading, verifying or uninstalling a license key, each operation gets tried using the parent manager first. If the operation succeeds using the parent manager then the processing stops, otherwise the operation gets retried using the child manager. This repeats recursively until the operation either succeeds using some manager or no more managers are available, in which case a LicenseManagementException gets thrown.

This design allows you to use the API for installing, loading, verifying and uninstalling license keys without knowing for which edition a license key has been generated. To facilitate this, the LicenseManager class provides the get() method which returns the first manager in the configured chain-of-responsibility.

For the following examples, it’s necessary to add the following imports:

import com.company.product.keygen.*;
import global.namespace.fun.io.api.*;
import global.namespace.truelicense.api.*;

import static global.namespace.fun.io.bios.BIOS.*;

# Installing a License Key

You can install a license key using:

ConsumerLicenseManager manager = LicenseManager.get();
Source source = file("${license-key-path}");
manager.install(source);

… where ${license-key-path} expands to the path of the license key file.

ConsumerLicenseManager.install(Source) recursively tries each consumer license manager until the given license key fits the respective lock and saves it. If the given file does not hold a license key for the lock of any license consumer manager, then a LicenseManagementException gets thrown.

TIP

Assuming the previous configuration, LicenseManager.get() is the same as LicenseManager.ftp.

TIP

It’s not necessary to know for which edition the license key has been generated.

# Loading the License Key

You can load the installed license key using:

License bean = LicenseManager.get().load();

ConsumerLicenseManager.load() recursively tries each consumer license manager until an installed license key gets found and returns a duplicate of its encoded license bean. If there is no license key installed, then a LicenseManagementException gets thrown.

WARNING

This method does not validate the encoded license bean: For example, it’s term may have already expired.

TIP

It’s not necessary to know for which edition the installed license key has been generated.

# Verifying the License Key

You can verify the installed license key using:

LicenseManager.get().verify();

You need to call this method before you want to access a licensed feature of your software product!

ConsumerLicenseManager.verify() recursively tries each consumer license manager until an installed license key gets found which passes the validation function, too. If there is no license key installed, then a LicenseManagementException gets thrown. If there is a license key installed, but the encoded license bean is invalid, then a LicenseValidationException gets thrown.

TIP

Calling this method frequently ensures that your software product detects any license term expiration as soon as possible. You don’t need to worry about performance: TrueLicense maintains a time sensitive cache in order to speed up subsequent processing. For example, on an Intel i7 at 2.2 GHz, once there is a valid V2/JSON license key installed, you can get about 9.5 million successful license key verifications in a single thread! Of course, this depends not only on the hardware, but also on the configuration of the licensing schema, so your mileage may vary.

# Supporting Multiple Editions

The use case for verifying a license key is different from the use case for the other operations: When installing, loading or uninstalling a license key, it’s not relevant for which edition a license key has been generated. The chain-of-responsibility pattern then ensures that these operations will succeed when calling them on LicenseManager.get(), which is the first manager in the chain.

However, when verifying access to a feature, then you want to make sure that access gets granted if and only if there is a valid license key installed for the respective edition or any of its supersets, but not its subsets. To do this, you need to directly use the instances of the enumeration class LicenseManager. For example, assuming the same definition of this class, the following code accepts a valid license key for the enterprise edition only:

LicenseManager.enterprise.verify();

In contrast, the following code accepts a valid license key for the enterprise edition or the standard edition:

LicenseManager.standard.verify();

Last but not least, the following code accepts a valid license key for the enterprise edition or the standard edition or the FTP edition:

LicenseManager.ftp.verify();

Note that modelling the FTP as an edition allows you to limit access to some features to registered customers only. Employing this option is trivial: Just call ConsumerLicenseManager.verify() on any license manager other than LicenseManager.ftp.

# Uninstalling the License Key

You can uninstall the license key using:

LicenseManager.get().uninstall();

ConsumerLicenseManager.uninstall() recursively tries each consumer license manager until an installed license key gets found and deletes it. If there is no license key installed or it's only an auto-generated FTP license key, then a LicenseManagementException gets thrown.

TIP

It’s not necessary to know for which edition the installed license key has been generated.

# Working with Runtime-Exceptions

The ConsumerLicenseManager interface may throw a LicenseManagementException, which extends GeneralSecurityException, which in turn extends the checked Exception. Working with checked exceptions may be cumbersome in contexts where a method gets constrained to only throw unchecked exceptions, e.g. when implementing functional interfaces like Runnable.run(). For cases like this there is an adapter method named ConsumerLicenseManager.unchecked(): This method adapts a consumer license manager so that it may throw an UncheckedLicenseManagementException, which extends the unchecked RuntimeException and simply wraps the original LicenseManagementException. Here’s the general usage pattern:

ConsumerLicenseManager checkedManager = LicenseManager.get();
UncheckedConsumerLicenseManager uncheckedManager = checkedManager.unchecked();
Source source = file("${license-key-path}");
uncheckedManager.install(source);

As you see, the call sequence is the same as in the previous example. You can get back the original (checked) consumer license manager by calling:

UncheckedConsumerLicenseManager uncheckedManager = ...;
ConsumerLicenseManager checkedManager = uncheckedManager.checked();