Dependency Injection
Setup app with scopes
The Kiwa eLicense Holder SDK is using scopes to manage the lifecycle of the various components. More information about scopes can be found in the scopes section of the Identity Development Kit that the Kiwa SDK uses. See the IDK documentation for more information.
Initialize application component and scope
Typically there is only one application scope within a single app or service. Technically however multiple instances could be created. The app scope has an app component, that is initialized with some information. The app component acts as a singleton in the app scope.
The application parameter below for instance is the typically the Android context or Apple app object.
The appId is the name of your application. It is mainly being used in configuration management. All configuration properties being used, will use the appId internally.
Same for the profile. Within a single app you can support multiple profiles. However, a single app instance will only be started with a single profile. What a profile exactly is,
is up to you as a developer. A typical use case is the type of environment the app is running in. The profile is also being used in the configuration service to distinguish, for
instance, between different configuration values between your production and test app. Lastly there is the app version. Although the component expects your app version to be
supplied there, currently it is not in use in the Kiwa SDK.
// Create your application component
val appComponent = KiwaSdkAppComponent.init(
application = yourApplication, // This can be your mobile app reference instance
appId = "your-app-id", // A string denoting your app
profile = "prod", // A profile so you could have different properties for different environments or profiles of the app
version = "1.0.0" // The version of your app.
)
Now you get access to a few objects in the app scope via the appComponent above. The app component however knows about quite a lot more interfaces it can injects. Its primary
function is to ensure that any objects being created with these interfaces are using Dependency Injection, so a developer does not directly provide an actual implementation. This
allows for clean, cohesive code with low coupling. One of the most important objects on the app component is the contextManager which we will use next.
Initialize user context scope
Once the application component has been created it is time to create the context scope, which contains the tenant and principal values. A principal either is a natural person (user) or system account. This scope is used to allow separation of object instances and asynchronous code. It is also being used by the configuration system, meaning that it is possible to have different configuration values for different tenants, or even principals. If multi-tenancy is not needed in your use case, you can either always initialize with a fake tenant and principal, or simply leverage the anonymous context scope.
// Initialize context with tenant and principal information
val userContextComponent = appComponent.contextManager
.getOrCreateFromInputs(
TenantInputString("your-tenant-id"),
PrincipalInputString("your-principal-id@for-instance-an-email.com")
)
// As an anonymous user, or if you don't use multi-tenancy at all:
// val contextComponent = appComponent.contextManager.getOrCreateAnonymous()
Initialize Session scope
Now we have a singleton app scope, and a context scope for the tenant and principal, it is time to create a session. You can define what a session entails. It could be a long-lived session (from user login to logout in a mobile app) or a short-lived one (a single request/response in a REST API, for instance). The session scope is mainly used to bind all objects and asynchronous code together. This means that any outstanding work within a session will be stopped once the session is destroyed.
// Initialize session
val sessionContextManager = userContextComponent.sessionContextManager
val sessionComponent = sessionContextManager.getOrCreateFromId("unique-example-session") // A unique value for the session
Get Service Instances
Now that the app scope, context scope, and session scope have been initialized, you can get the main entry point into the Kiwa eLicense SDK services:
// Get the service factory
val kiwaServices = sessionContextManager.getService<IKiwaServices>(IKiwaServices.SERVICE_ID)
// Get the holder, auth, and verifier services
val holderService =
kiwaHolderServices.holder // Provides access to license holder operations including issue, assign, confirm, and decode commands.
val authService =
kiwaHolderServices.auth // Provides access to wallet certificate authentication and management operations.
It makes sense to have the above code somewhere early in your application. For instance during app start, or close to the authentication process.
You could be using kotlin-inject in your own code as well, in which case you could inject an IKiwaHolderServices property as constructor argument. You would automatically be provided with an instance. See also the IDK DI documentation