Introduction
Scope and Audience
This document is intended as a developer’s guide to the Software Potential Distributor API for distributed or network licensing.
For information on aspects of Distributor other than the API (e.g. installing and configuring Distributor server) please see Getting Started - Distributor.
Distributor Overview
Network Licensing Model
The Distributor model extends basic Node Locked Standalone licensing to support floating, concurrent licensing scenarios, and can be combined with other models (such as Subscription Licensing). For an overview on licensing and details on other licensing models see http://support.softwarepotential.com.
In the Node Locked Standalone license model, the Software Potential Runtime included with the application manages access to licensed features by querying locally stored licenses.
With the Distributor or network licensing model, the runtime can additionally request features from a central Distributor server installed on the customer premises. Multiple runtime instances each on different devices can simultaneously request features from a single Distributor instance.
Distributor Server
Distributor is a centralized network license server installed on a customer’s premises. Distributor is hosted as a Windows Service and can be installed on any Windows desktop or server machine.
The Distributor server comprises:
- A centralized licensing service which communicates with SpAgent runtime clients over HTTP. The service listens for client requests on Port 8731 by default.
- An administrative web front end that is served from within the same host process which allows one to administer the Distributor service and its associated licenses. The administration portal is on Port 2468 by default.
For more information on the installation and configuration of this component see the Sp.Distributor README.
Distributor Client
A Distributor Client DLL is required by the SpAgent Runtime to connect to the Distributor Service. This is delivered as a separate NuGet package that is installed alongside the standard licensing package
For a more detailed guide to the Distributor architecture see: Getting Started - Distributor.
Feature Allocation
Concurrency Constraints
When issuing a Distributor license, the issuer can set concurrency constraints at both license and feature level. This allows for limiting their use to the specified number of client runtime instances.
Limits set at a license level constrain the number of concurrent instances of the licensed applications, while limits set at a feature level constrain the number of concurrent instances that can access that feature. It is possible to set a lower limit on a feature than is set at the license level e.g. to allow only a subset of permitted concurrent instances of the application to access a “scarce” or high value feature.
This allows for a wide range of business scenarios and levels of complexity. For example a single Distributor instance could support some or all of the following:
- A single license with no defined features that only constrains the number of concurrent seats or instances of the application.
- A single license that constrains the number of seats/instances but also further restricts some specialized features to an even smaller number of seats.
- Multiple licences each with different sets of features e.g. corresponding to differently featured editions of the software.
Each combination of license and feature concurrency constraints will result in different patterns of access as client runtimes acquire and release features, especially in cases where there is competition for the use of restricted features. The following section gives a brief overview of the Distributor pooling and allocation mechanisms; it is not necessary to understand this to use the Distributor API but it may be useful if implementing some of the more complex scenarios.
Distributor Concurrency Management
Distributor enforces concurrency constraints by maintaining a record of features currently accessed by each client runtime and using this to calculate feature availability for subsequent requests.
Distributor allocates features from pools of features of features as follows:
- Valid features are initially sorted into sets (one per license).
- Sets are pooled so that sets with the same features are added to the same pool.
A runtime request will only be fulfilled if the features requested can be allocated from one of the feature sets or subsets available.
- If available at that time, access to the feature(s) is temporarily granted to the client runtime, and the feature availability is decremented for subsequent competing requests from other runtimes for this period.
- The runtime will then receive an allocation of the required feature(s) for 2 minutes in duration.
- The runtime will automatically renew the allocation for a further 2 minutes and will repeat this renewal process until such time as the allocation is relinquished.
- Feature allocations acquired by the runtime are released automatically on application exit. Features can also be relinquished programmatically at any stage.
Feature Requests
Clients may requests features from Distributor in a number of ways:
Declarative Lease Requests
When a method marked by a Software Potential attribute for a given feature is invoked a Declarative request is made for that feature. If successful, the requested feature access is added to any previously acquired feature access. If a client already has access to Feature1, and then successfully executes the code for Feature2, the declarative lease retains access to both features.
So declarative feature acquisition is cumulative and all features acquired are retained until the application quits or they are explicitly released.
When Declarative requests are made, Distributor caches the License data in memory to optimize performance. The cache is retained for one minute.
For more detail on the implementation of Declarative Leasing, see the Licensing README.
Programmatic Lease Requests
Programmatic requests are made explicitly via calls in the code to the Distributor API rather than being triggered by invocations of licensed methods.
This means the request can be made ahead of time, before the code is executed e.g., to reserve access for an anticipated workflow. By acquiring and holding access to features before the relevant methods are invoked, a user can guard against their later unavailability due to competition among runtime requests when concurrency is limited.
Each time a request is successful, all the features previously acquired are implicitly released, and replaced by the newly acquired set of features. This happens even if the requested set and the previously acquired set contain common elements.
A previously acquired set, whether acquired programmatically or declaratively can also be explicitly released with acquiring a replacement set of features.
Once a set of features is acquired, it is retained until either the application exits, or until it is explicitly released.
To check if an instance of the application can be run then one can just request a lease for the Execute feature only. For example where one is only interested in copy protection one can define a product with no features; one can still issue a Distributor license with a limit set at the license level which will control the number of instances of the application that can be run concurrently.
Disconnected Mode
Disconnected Mode allows a licensed application to run even when disconnected from the Distributor service e.g. when leaving the office for travel, vacation etc.
In this case a programmatic checkout request is made to attempt to obtain a lease on a set of features for a predefined period. On a successful checkout the requested feature leases are cached locally on the device, allowing the licensed application to run without a connection to Distributor. The pool of features available in Distributor for allocation to other instances of the licensed application is reduced for the checkout period
While checked out it is not possible to dynamically acquired further features, either programmatically or declaratively.
At any stage during the checkout period, the client can again connect to Distributor and checkin the features leases. If not already checked-in the checkout will automatically expire at the end of the checkout period.
For more information on Distributor licenses see: Getting Started - Distributor.
Distributor API
One can use the Distributor API in a licensed application to programmatically acquire and release client access to features either for online use or checkout. For more detailed API documentation please see the detailed code commentary and IntelliSense in Visual Studio.
SpAgent.Distributed
The SpAgent.Distributed interface provides the means to programmatically
- Acquire feature leases from Distributor.
- Release acquired feature leases, making them available to other clients.
- Acquire and release checkouts in Disconnected Mode.
Querying the Acquired Feature Set
The SpAgent.Distributed.Features property returns a list of the currently acquired set of features.
The set of features acquired by a runtime instance at any instant are comprised of:
- Features declaratively acquired in the course of successful execution of [Feature]-attributed methods;
- Features programmatically acquired from a Distributor;
- Features checked out from a Distributor
Leases or Checkouts that have expired are excluded from the results.
Acquiring a Feature Lease
The SpAgent.Distributed.Acquire method enables a client to attempt to acquire a set of features from Distributor. The set of features to acquire must be a subset of one of the feature sets available from the Distributor license pools.
The subset to request is determined by an algorithm written in a delegate passed as an argument to the Acquire method. This is referred to as the Selector delegate.
If a request by Acquire is successful,
- A lease on the requested set of features is allocated to the requesting client.
- The availability of the requested features is reduced for other client runtime instances.
- The currently held set (if there is one) is dropped and its feature availability is reinstated for other client runtimes.
Subsequent requests are not restricted to the first accessed set (unlike Declarative acquisition).
If no valid licences are activated on the server the Selector is passed a single empty set.
If the client is disconnected from Distributor, Acquire will attempt to pass the Selector the current checkout if any. If there is no current checkout Acquire will result in an Sp.Agent.Distributor.DistributorRequestException.
Writing a selector delegate
The Selector is passed an array of all available sets as an argument when Acquire is executed.
The Selector delegate must return a valid subset of one of the available features sets
Example: Request largest available set:
SpAgent.Distributed.Acquire(allFeatureSets => { return allFeatureSets.OrderByDescending(Feature => Feature.Count).FirstOrDefault(); });
Releasing Acquired Features
You can use Acquire to drop the currently held set by returning an empty set from the Selector Delegate.
SpAgent.Distributed.Acquire(allFeatureSets => { return new string[] { }; });
Exception Handling
The developer should handle the following exceptions:
System.InvalidOperationException
:- thrown when requested features are unavailable, or if the requested set is invalid (E.g. requests features from more than one set).Agent.Distributor.CheckoutStorageAccessException
:- thrown if the client is in a Checked out state but the local store is inaccessible.Agent.Distributor.DistributorRequestException
:– thrown if there is an issue with the connection to the server.
Acquire and Release Checkout in Disconnected Mode
The SpAgent.Distributed.Checkout
property provides an ICheckoutContext
with AvailableNow
and TryGetCurrent methods
.
The checkout sequence involves:
- Determining if a checkout (I.e. a successfully leased feature set) already exists – an attempt to checkout while already checked out is not permitted.
- Determining what features sets are available for checkout.
- Attempting to checkout one of the available feature sets.
Determining if Checked Out
Use the SpAgent.Distributed.Checkout.TryGetCurrent
method to test if there is a currently held Checkout. This returns true if there is a current Checkout detected, and checkout is returned in the ICheckout Out parameter.
This ICheckout can now be used as a reference to see the current checkout properties and to call the Relinquish method to release (check in) the checkout once reconnected to Distributor. Once checked in one can either submit another checkout request, or resume normal connected mode.
Properties of the checkout are:
- Features - indicates which is a set of features are included in the ICheckout.
- ValidUntil – indicates UTC expiry date of the ICheckout.
Possible exceptions are:
Agent.Distributor.CheckoutStorageAccessException
:- thrown if there is an issue reading the checkout storage.
If not already checked out then one can continue to the next step in the checkout process.
Determining what features sets are available for checkout
To get a snapshot of features sets available to be checked out at a moment in time, invoke SpAgent.Distributed.Checkout.AvailibleNow
. This will return an array of IAvailableCheckouts, the sets that can be checked out, each with an AvailableUntil and ID property and Acquire method.
- The AvailableUntil property indicates the latest date until which the set can be acquired. This is determined by expiry constraints set on either the license or any of the associated features, and is limited to whichever of these is earliest.
- If a feature has been set to Gather Usage by the license issuer its containing set will not be available to be checked out.
- The ID property can be used to select a required set when requesting a checkout. The ID is an aggregation of the features contained in the set and it should be translated into something more meaningful when displayed to the end user e.g. Standard Edition etc
Please note that this array contains those checkouts that are available at the moment the request was made. This does not reserve any checkout and so there is no guarantee that any of the checkouts listed will still be available when one attempts to actually acquire a checkout from the list.
Possible exceptions are:
Agent.Distributor.NoDistributorException
- thrown if there is no Distributor configured or discoverable available at the present time.Agent.Distributor.DistributorRequestException
- thrown if there is a connectivity or related issue contacting the service.Agent.Distributor.DistributorIntegrityException
- thrown if there is an integrity issue on the server.
Requesting a checkout
To acquire a checkout select the required IAvailableCheckout from the list returned in a recent call to SpAgent.Distributed.Checkout.AvailiableNow and call its Acquire method.
The Acquire takes a date time parameter to set an expiry date on the checkout. This should use UTC to be consistent with the runtime management.
As checkout is not permitted if a checkout already exists before attempting a checkout be sure to call ICheckoutConext.TryGetCurrent early in the sequence to check whether a checkout already exists.
Possible exceptions are:
System.InvalidOperationException
:– thrown if there is a checkout already held locally when attempting a checkout.Agent.Distributor.NoLongerAvailableException
:– thrown if the requested set of features to be checked out has become unavailable.
Checking In
Once a reference to a currently held ICheckout has been obtained using TryGetCurrent it can be checked in by invoking its Relinquish method.
A client will not be able to make further checkout or acquire further feature leases from Distributor until this is done.
Comments
0 comments
Article is closed for comments.