This console sample shows how to integrate a software licensing platform via API, including license management, entitlement management, usage analytics, floating licenses, and offline licensing. Going beyond simple API connectivity, it is designed as a production-oriented integration template for real-world licensing scenarios, including temporary offline operation, local license caching, and resilient handling of transient technical failures such as 5xx responses.
It includes examples for the most important licensing, analytics, and resilience workflows:
- license activation and heartbeat
- floating session management
- license file validation (offline activation)
- analytical, usage, and consumption heartbeats
- offline fallback using cached license data
- response and file integrity validation
- error handling and retry logic
For more information, see the SLASCONE website, the support center, and the SLASCONE API.
- What This Sample Demonstrates
- Getting Started
- Connecting to Your SLASCONE Environment
- Typical Licensing Flow
- Offline Licensing and Freeride Period
- Configuration and Storage
- Error Handling and Retry Logic
- Technical Details
- Project Structure
- API Client
- Further Reading
This sample application showcases the following key features of the SLASCONE licensing service.
License Activation (online)
- Activates a license for a specific device using its unique device ID
- Demonstrates how to activate a license key for the first time on a specific machine
- Handles activation responses and potential warnings or errors
License Heartbeat
- Sends periodic license verification requests to the SLASCONE server
- Retrieves up-to-date license information including features, limitations, and expiration details
- Caches license information for offline use
License Activation (offline)
- Validates the digital signature of license files to prevent tampering
- Reads and displays comprehensive license information from XML files
- Provides detailed analysis of license validity, features, and limitations
Offline License Support
- Reads license information when temporarily disconnected from the internet
- Uses cached license data stored during the last successful heartbeat
- Ensures the software can continue to function during temporary network outages
License Unassignment
- Demonstrates how to unassign a license from a device
- Allows a license to be transferred to a different machine
Analytical Heartbeat
- Gathers general troubleshooting statistics
- Supports custom fields for application-specific metrics
Feature Usage Tracking
- Records which specific features are being used within the application
- Tracks usage frequency and patterns for specific functionality
- Provides insights for product development and pricing decisions
Consumption Tracking
- Monitors consumption-based licensing metrics such as API calls or processed documents
- Supports pay-per-use licensing models
- Reports consumption against pre-defined limitations
Session Management
- Opens licensing sessions for floating license scenarios
- Supports concurrent user licensing models
- Allows software to be installed on multiple machines while limiting concurrent use
Offline Session Handling
- Reads and validates locally stored session data when temporarily disconnected
- Ensures continuation of work during network interruptions
- Maintains license compliance even in offline mode
Session Closure
- Properly releases floating licenses back to the pool
- Ensures efficient use of available licenses
- Prevents license hoarding by inactive installations
Device Identification
- Cross-platform device fingerprinting for Windows, Linux, and macOS
- Secures licenses to specific hardware
- Helps prevent unauthorized license transfers
Digital Signature Validation
- Verifies the authenticity of license files and server responses
- Prevents tampering with license data
- Supports both symmetric and asymmetric cryptographic validation
Replay Protection
- Uses a nonce-based challenge-response flow
- Java 11 or newer
- Maven 3.6+
mvn clean compilecd slascone-provisioning-sample
mvn exec:javaAfter starting the application, use the interactive menu to explore the different licensing and analytics scenarios.
For integration into your own software product, focus on the parts that match your licensing model and runtime requirements.
By default, the application is configured to connect to a SLASCONE demo environment.
To connect it to your own SLASCONE environment, adjust the values in Settings.java:
API_BASE_URL: your API endpointPROVISIONING_KEY: your provisioning API keyISV_ID: your ISV identifierPRODUCT_ID: your product identifier
You can find these values as explained here. For meaningful testing and evaluation, your SLASCONE environment should have at least one active license.
Keep provisioning keys secure and do not embed production secrets in publicly accessible repositories. More about secrets, see the Secrets section in the SLASCONE Help Center.
A typical integration follows this sequence:
- Identify the current client or device.
- Activate the license for that client.
- Send regular heartbeats to retrieve the latest license state.
- Store the last valid license information locally.
- Fall back to the cached license state during temporary connectivity issues.
- Open and close sessions when using floating licenses.
- Send analytical, usage, or consumption heartbeats as required by your product.
- Unassign the license when needed.
This sample demonstrates each of these steps in a compact console application so you can adapt the relevant parts to your own product.
The SLASCONE licensing system provides robust support for (temporary) offline scenarios, which is especially important for desktop applications and intermittently connected systems. For more background on temporary and permanent offline scenarios, see the Offline & Connectivity section in the SLASCONE Help Center.
This sample demonstrates how to implement this behavior.
-
License Caching
- During a successful license heartbeat, the application saves the license data locally
- The cached license information includes features, limitations, and expiration details
- The data is protected with digital signatures to prevent tampering
-
Offline Validation
- When the application cannot connect to the SLASCONE server, it falls back to the cached license data
- The application verifies the digital signature of the cached data before using it
- All relevant license rules such as features, limitations, and expiration continue to be enforced based on the cached state
-
Implementation
- The sample stores license data in
license.txtand its signature inlicense_signature.txt - For floating licenses, session information is stored in
session.txtandsession_signature.txt - The sample demonstrates how to read and validate this information in offline mode
- The sample stores license data in
The freeride period provides flexibility when heartbeats fail, allowing users to continue using the software for a defined grace period.
-
Purpose
- Prevents immediate software lockout when a heartbeat fails
- Gives users time to resolve connectivity issues
- Ensures a smoother user experience in environments with intermittent connectivity
-
Functionality
- If a heartbeat fails, the software continues to work normally during the freeride period
- The application tracks the time since the last successful heartbeat
- Once a successful heartbeat occurs, the freeride period is reset
- If the freeride period expires without a successful heartbeat, license enforcement takes effect
-
Configuration
- Freeride periods are configured at the license edition level in the SLASCONE portal
- The freeride duration is typically specified in days
- This sample demonstrates how to implement and respect freeride periods
- The
checkAndReadOfflineLicenseExamplemethod shows how to display freeride information
-
Example Scenario
- With a daily heartbeat requirement and a 7-day freeride period
- If heartbeats fail, the application continues working for 7 days
- During this time, the application should notify the user about the need to go online
- If a heartbeat succeeds within those 7 days, normal operation resumes
- After 7 days without a successful heartbeat, the license becomes invalid
This approach ensures that temporary network issues or brief periods offline do not disrupt users' work while still maintaining proper license enforcement in the long term.
For detailed guidance on what should be stored locally, why it matters, and how cached license state supports offline and freeride scenarios, see What to Store Locally in Your Client.
The sample application stores license and session files in a dedicated application data folder instead of the current working directory.
This provides several benefits:
-
Persistent Storage
- License and session files remain accessible across application restarts
-
Centralized Location
- All application data is stored in a single, dedicated location
-
Security
- Files are stored outside of the application directory, reducing the risk of accidental deletion
By default, the application data is stored in:
~/.slasconeon Linux and macOS%ProgramData%\Slasconeon Windows
The application data folder is managed by the FileService class.
To use a custom location for application data, specify it when initializing FileService:
// Create a FileService with a custom app data folder
FileService fileService = new FileService("/path/to/custom/folder");
// Pass this FileService instance to other components that need it
CombinedInterceptor interceptor = new CombinedInterceptor(fileService);
// ... other service initializationsThe FileService constructor accepts a custom folder path and handles:
- Creating the directory if it does not exist
- Validating that the directory is writable
- Preparing the folder for storing license and session data
Alternatively, you can create a FileService with the default location and then change it:
FileService fileService = new FileService(); // Uses the standard location
boolean success = fileService.setAppDataFolder("/path/to/custom/folder");
if (!success) {
// Handle error case - folder could not be set
}To ensure that all components use the same application data folder, create the FileService early in your application startup and pass the same instance to all dependent services.
The following files are managed in the application data folder:
license.txt: cached license information from the last successful heartbeatlicense_signature.txt: digital signature used to verify the license filesession.txt: information about the current floating license session, if applicablesession_signature.txt: digital signature used to verify the session file
All files are automatically created, updated, and removed as needed during application operation.
For detailed information about SLASCONE API error codes, refer to the SLASCONE error handling documentation.
This sample application demonstrates how to handle SLASCONE API errors and implement retry logic using the ErrorHandlingHelper class.
All API calls are routed through this helper, which provides:
- consistent error classification
- automatic retries for transient failures
- a unified response wrapper
The ErrorHandlingHelper classifies API errors into three categories.
-
Functional Errors (HTTP 409)
- Represent business logic conflicts returned by the SLASCONE API
- Examples include attempting to activate an already activated license, unknown client IDs, or exceeded license limits
- The response body is automatically parsed into an
ErrorResultObjectsinstance with a specific error code and message - These errors are never retried because they require the caller to address the underlying business logic issue
-
Technical Errors (HTTP 4xx and 5xx)
- Represent server-side or request issues such as internal server errors, bad gateways, or service unavailability
- Transient HTTP errors such as
408,429,500,502,503,504, and507are automatically retried - Non-transient errors such as
401,403, or404are returned immediately without retry
-
Network Errors
- Represent connectivity issues such as socket timeouts, connection refusals, DNS resolution failures, or SSL errors
- Transient network exceptions such as
SocketTimeoutException,ConnectException, andUnknownHostExceptionare automatically retried - Non-transient network exceptions are returned immediately
The ErrorHandlingHelper implements automatic retry logic for transient errors.
-
Retry Count
- By default, the helper performs a maximum of one automatic retry via
MAX_RETRY_COUNT - This follows the SLASCONE recommendation of a moderate retry policy
- By default, the helper performs a maximum of one automatic retry via
-
Wait Time
- The default wait time between retries is 30 seconds via
RETRY_WAIT_TIME
- The default wait time between retries is 30 seconds via
-
Retry-After Header
- For HTTP errors that include a
Retry-Afterresponse header, commonly with429or503, the helper uses the server-specified wait time instead of the default - This helps align the client with rate limiting and server availability signals
- For HTTP errors that include a
-
Non-Transient Errors
- Errors that are not classified as transient, such as
404or a functional409conflict, are returned immediately without any retry attempt
- Errors that are not classified as transient, such as
All API calls wrapped by ErrorHandlingHelper.execute() return a ResultWithError object, which encapsulates either a successful result or error details.
-
Success Check
- Call
result.hasError()to determine whether the API call succeeded or failed
- Call
-
Success Path
- Use
result.getResult()to access the API response data such asLicenseInfoDtoorSessionStatusDto
- Use
-
Error Inspection
-
When an error occurs, use the following methods:
result.getErrorType()returns the error category:FUNCTIONAL,TECHNICAL, orNETWORKresult.getErrorMessage()returns a formatted error descriptionresult.getErrorResult()returns the parsedErrorResultObjectsfor functional errorsresult.getApiException()provides access to the underlyingApiExceptionfor advanced handling
-
-
Usage Example
var result = ErrorHandlingHelper.execute(
provisioningApi::activateLicenseWithHttpInfo,
activateInfo,
"activateLicense"
);
if (result.hasError()) {
System.out.println("Error Type: " + result.getErrorType().toString());
System.out.println("Message: " + result.getErrorMessage());
if (ErrorType.FUNCTIONAL == result.getErrorType() && result.getErrorResult() != null) {
// Handle specific business logic error codes
int errorId = result.getErrorResult().getId();
}
return;
}
LicenseInfoDto licenseInfo = result.getResult();Based on the SLASCONE error handling guidelines, consider the following strategies when integrating SLASCONE licensing into your application.
-
Always Handle HTTP 409 Explicitly
- These are business logic responses, not unexpected errors
- Check the specific error code from
getErrorResult().getId()and handle each case according to your application's needs - Refer to the endpoint-specific documentation in the SLASCONE API for possible conflict scenarios
-
Fallback for Transient Failures
- The built-in retry logic handles the first retry automatically
- If retries are exhausted, implement a fallback strategy such as using cached license data from the last successful heartbeat
-
Heartbeat Failure Resilience
- When a license heartbeat fails after retries, fall back to the locally cached license data
- The freeride period provides a grace period during which the application can continue operating
- Reserve freeride logic for true offline scenarios rather than generic server-side errors
-
Session Open Resilience
- For floating license session open failures caused by transient errors, consider a resilience strategy that preserves usability while maintaining long-term license compliance once connectivity is restored
- Java Version: Java 11 or newer is required. The project was developed and tested with OpenJDK 17.
- Maven: Apache Maven 3.6 or newer for dependency management and build automation
- Network: Internet connectivity is required for initial license activation and for online heartbeat operations
This application relies on several key libraries:
- Apache HTTP Client for REST API communication with the SLASCONE server
- Jackson and Gson for JSON and XML serialization and deserialization
- Apache Commons Codec for encoding and decoding operations
- XML Security for digital signature validation of license files
The application includes platform-specific code to obtain device IDs on:
- Windows: uses WMI to query the system UUID
- Linux: reads from
/etc/machine-idor generates a UUID from the hostname - macOS: uses
ioregto obtain the system hardware UUID
This project includes a development container configuration for Visual Studio Code, which provides:
- a pre-configured Java development environment
- the necessary tooling and dependencies
- a consistent development experience across different machines
For details, refer to README-DEVCONTAINER.md.
- API Keys: The sample uses demo API keys. In production, keep provisioning keys secure.
- Signature Validation: The sample demonstrates both symmetric and asymmetric signature validation.
- Device Binding: Licenses are bound to specific devices by their hardware IDs.
slascone-demo-java/
├── slascone-provisioning-sample/ # Main application module
│ ├── src/
│ │ ├── Model/ # Data models specific to the sample application
│ │ └── Program/ # Main program and helper classes
│ ├── assets/ # License file examples
│ └── pom.xml # Maven configuration for the sample
├── slascone-client/ # Generated API client module
│ ├── src/main/java/ # Auto-generated API client code
│ ├── docs/ # API documentation
│ └── pom.xml # Maven configuration for the client
├── pom.xml # Parent Maven configuration
├── run.sh # Convenience script to run the application
└── build-and-run.sh # Script to build and run the application
This application uses a client generated by the OpenAPI Generator with the java generator.
You can provide a config.json file to configure the generator. For this demo application, the generated client is placed in the slascone-client module and uses the package structure expected by the sample application.
The generated client can be regenerated when the API definition changes, while the sample application code remains focused on integration logic such as:
- activation and heartbeat workflows
- response handling
- signature validation
- local persistence
- offline fallback
- retry and resilience behavior
If you use the generated client in your own application, it is recommended to keep your integration-specific logic outside of the generated code so that client regeneration remains straightforward.