Overview Current DAC design assumes that AWC will behave as a proxy to LISA API and will be it's only consumer. Main reason for such decision was dictated by requirement of tracking and controlling LISA usage to prevent situation when application is currently started and external client (eg. DAC Manager ) would call LISA's uninstall API. This would cause undefined behaviour, due to removal of application during active state. Covering LISA's API by AWC would prevent such situation by blocking uninstall request on AWC level.
Above approach unfortunately has cons:
Violates SRP, AWC should be only responsible for controlling application window(size, position) and state (start, stop). It creates strong dependency between AWC and LISA. Code bloat by providing unnecessary proxy layer. LISA by design cannot be used standalone, and some external application manger needs to protect access to LISA to prevent above situation. This design resolve this issue by extending LISA API with locking mechanism, decoupling it from AWC and expose LISA API to external clients.
Design LISA API should be extended with three additional methods: l ock , u nlock, getLockInfo . Those methods are used by entity which manages application state (AWC) to block any operations (uninstall) on application during it's active state (started, suspended). Lock is performed with id, version of the application, lock owner and lock reason, we are only blocking specific version of application.
After sending asynchronous request (uninstall) to LISA, requesting client (eg. DAC Manager ), if application is currently used (active - locked by AWC), will receive error result with information about lock reason(eg. ERROR_APP_ACTIVE). Additional API method getLockInfo will allow to check who is the lock owner.
If application is not currently in locked state (is in stopped state) asynchronous operation can be performed.
From other end if AWC will receive Start (or initiate itself) request from MainUI, it should send lock signal to the LISA to prevent its uninstallation/update by external LISA's API client (eg. DAC Manager ) during application active state. If lock request initiated by AWC succeeds application can be started, otherwise return error will be sent to the caller (MainUI) that application is in currently being processed (uninstall) by LISA.
Both scenarios and API change are described below.
API Extension When LISA's client (DAC Manager, UI) will request to uninstall application which is currently used (locked) by AWC following error will be returned:
Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
{
"code": 1009,
"message": "ERROR_APP_ACTIVE"
} Lock/Unlock calls should be used exclusively by AWC (for now, maybe other use cases will show up which require locking by DAC Manager eg batching)Â Â just before transition to start and after transition to stop of the DAC application.
If AWC will try to activate (lock) application during ongoing uninstallation procedure, following error will be returned
Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
{
"code": 1010,
"message": "ERROR_APP_UNINSTALLING"
} By calling getLockInfo caller can receive more details about current lock owner and reason (for now there will be only 2 lisa and awc).
call getLockInfo from AWC → { "owner": "lisa", "reason": "uninstalling" }
call getLockInfo z DACM/UI ->Â { "owner": "awc", "reason": "active"Â }
API Schema
{
"$schema": "interface.schema.json",
"jsonrpc": "2.0",
"info": {
"title": "Lisa API",
"class": "Lisa",
"description": "Lisa JSON-RPC interface",
"version": "0.0.2"
},
"common": {
"$ref": "common.json"
},
"methods": {
"lock": {
"summary": "Lock application",
"description": "Lock and take control over application state until unlock is called",
"params": {
"type": "object",
"properties": {
"type": {
"description": "Application type (mime-type)",
"type": "string",
"example": "application/vnd.rdk-app.dac.native"
},
"id": {
"description": "id of the application, assumed reverse domain name notation, the id should match the [ASMS application id](https://wikiprojects.upc.biz/display/SPARK/ASMS+API+specification)",
"type": "string",
"example": "com.libertyglobal.app.awesome"
},
"version": {
"description": "version of the application",
"type": "string",
"example": "1.0.0"
},
"owner": {
"description": "Owner of the lock",
"type": "string",
"example": "awc"
},
"reason": {
"description": "Reason for the lock",
"type": "string",
"example": "active"
}
},
"required": [
"type",
"id",
"version"
]
},
"result": {
"type": "object",
"properties": {
"handle": {
"type": "string",
"example": "a76a9ad56769634dbbc9c54bac15ddb9"
}
},
"required": [
"handle"
]
},
"errors": [
{
"description": "WrongParams",
"code": 1001,
"message": "Request not accepted because of wrong parameters"
},
{
"description": "Initializing",
"code": 1004,
"message": " LISA is performing initialization, wait for operationStatus event"
},
{
"code": 1009,
"message": "ERROR_APP_ACTIVE"
},
{
"code": 1010,
"message": "ERROR_APP_UNINSTALLING"
}
]
},
"unlock": {
"summary": "Unlock application",
"description": "Unlock application and make it available to be used by other components",
"params": {
"type": "object",
"properties": {
"handle": {
"type": "string",
"example": "a76a9ad56769634dbbc9c54bac15ddb9"
}
},
"required": [
"handle"
]
},
"result": {
"type": "object",
"properties": {}
},
"errors": [
{
"description": "WrongParams",
"code": 1001,
"message": "Request not accepted because of wrong parameters"
},
{
"description": "Initializing",
"code": 1004,
"message": " LISA is performing initialization, wait for operationStatus event"
},
{
"description": "WrongHandle",
"code": 1007,
"message": "The handle is not correct, e.g. the operation has finished."
}
]
},
"getLockInfo": {
"summary": "Get lock details",
"description": "Returns info about lock owner and lock reason",
"params": {
"type": "object",
"properties": {
"type": {
"description": "Application type (mime-type)",
"type": "string",
"example": "application/vnd.rdk-app.dac.native"
},
"id": {
"description": "id of the application, assumed reverse domain name notation, the id should match the [ASMS application id](https://wikiprojects.upc.biz/display/SPARK/ASMS+API+specification)",
"type": "string",
"example": "com.libertyglobal.app.awesome"
},
"version": {
"description": "version of the application",
"type": "string",
"example": "1.0.0"
}
},
"required": [
"type",
"id",
"version"
]
},
"result": {
"type": "object",
"properties": {
"owner": {
"description": "Owner of the lock",
"type": "string",
"example": "awc"
},
"reason": {
"description": "Reason for the lock",
"type": "string",
"example": "active"
}
}
},
"errors": [
{
"description": "WrongParams",
"code": 1001,
"message": "Request not accepted because of wrong parameters"
},
{
"description": "Initializing",
"code": 1004,
"message": " LISA is performing initialization, wait for operationStatus event"
},
{
"description": "WrongHandle",
"code": 1007,
"message": "The handle is not correct, e.g. the operation has finished."
}
]
}
},
"events": {
"operationStatus": {
"summary": "Completion of asynchronous operation.",
"description": "Notification sent on the completion of asynchronous operation.",
"params": {
"type": "object",
"properties": {
"handle": {
"type": "string",
"example": "4c4712a4141d261ec0ca8f9037950685"
},
"operation": {
"description": "Operation producing the event (Installing, Uninstalling)",
"type": "string",
"example": "Installing"
},
"type": {
"description": "Application type (mime-type)",
"type": "string",
"example": "application/vnd.rdk-app.dac.native"
},
"id": {
"description": "id of the application, assumed reverse domain name notation, the id should match the [ASMS application id](https://wikiprojects.upc.biz/display/SPARK/ASMS+API+specification)",
"type": "string",
"example": "com.libertyglobal.app.awesome"
},
"version": {
"description": "version of the application",
"type": "string",
"example": "1.0.0"
},
"status": {
"description": "Status of the operation (Success, Failed, Progress, Cancelled)",
"type": "string",
"example": "Success"
},
"details": {
"type": "string",
"example": "Downloaded 2342 KB, unpacked 3233 KB"
}
},
"required": [
"handle",
"operation",
"type",
"id",
"version",
"status"
]
}
}
}
}
API Description <!-- Generated automatically, DO NOT EDIT! -->
<a name="head.Version"></a>
Version: 0.0.2
<a name="head.Description"></a>
Lisa JSON-RPC interface.
<a name="head.Methods"></a>
<a name="method.lock"></a>
Lock application.
Lock and take control over application state until unlock is called
Name Type Description params object params.type string Application type (mime-type) params.id string id of the application, assumed reverse domain name notation, the id should match the ASMS application id params.version string version of the application params?.owner string <sup>(optional) </sup> Owner of the lock params?.reason string <sup>(optional) </sup> Reason for the lock (must be one of the following: active , installing , uninstalling )
Name Type Description result object result.handle string
Code Message Description 1001 Request not accepted because of wrong parameters
WrongParams 1004 LISA is performing initialization, wait for operationStatus event
Initializing 1009 ERROR_APP_ACTIVE
1010 ERROR_APP_UNINSTALLING
{
"jsonrpc": "2.0",
"id": 1234567890,
"method": "Lisa.1.lock",
"params": {
"id": "com.libertyglobal.app.awesome",
"version": "1.0.0",
"owner": "awc",
"reason": "active"
}
}
{
"jsonrpc": "2.0",
"id": 1234567890,
"result": {
"handle": "a76a9ad56769634dbbc9c54bac15ddb9"
}
}
<a name="method.unlock"></a>
Unlock application.
Unlock application and make it available to be used by other components
Name Type Description params object params.handle string
Name Type Description result object
Code Message Description 1001 Request not accepted because of wrong parameters
WrongParams 1004 LISA is performing initialization, wait for operationStatus event
Initializing 1007 The handle is not correct, e.g. the operation has finished.
WrongHandle
{
"jsonrpc": "2.0",
"id": 1234567890,
"method": "Lisa.1.unlock",
"params": {
"handle": "a76a9ad56769634dbbc9c54bac15ddb9"
}
}
{
"jsonrpc": "2.0",
"id": 1234567890,
"result": {}
}
<a name="method.getLockInfo"></a>
Get lock details.
Returns info about lock owner and lock reason
Name Type Description params object params.type string Application type (mime-type) params.id string id of the application, assumed reverse domain name notation, the id should match the ASMS application id params.version string version of the application
Name Type Description result object result?.owner string <sup>(optional) </sup> Owner of the lock result?.reason string <sup>(optional) </sup> Reason for the lock (must be one of the following: active , installing , uninstalling )
Code Message Description 1001 Request not accepted because of wrong parameters
WrongParams 1004 LISA is performing initialization, wait for operationStatus event
Initializing 1007 The handle is not correct, e.g. the operation has finished.
WrongHandle
{
"jsonrpc": "2.0",
"id": 1234567890,
"method": "Lisa.1.getLockInfo",
"params": {
"id": "com.libertyglobal.app.awesome",
"version": "1.0.0"
}
}
{
"jsonrpc": "2.0",
"id": 1234567890,
"result": {
"owner": "awc",
"reason": "active"
}
}
<a name="head.Notifications"></a>
Notifications are autonomous events, triggered by the internals of the implementation, and broadcasted via JSON-RPC to all registered observers.
<a name="event.operationStatus"></a>
Completion of asynchronous operation.
Notification sent on the completion of asynchronous operation.
Name Type Description params object params.handle string params.operation string (Installing , Uninstalling ) params.type string Application type (mime-type) params.id string id of the application, assumed reverse domain name notation, the id should match the ASMS application id params.version string version of the application params.status string (Success , Failed , Progress , Cancelled ) params?.details string <sup>(optional) </sup>
{
"jsonrpc": "2.0",
"method": "client.events.1.operationStatus",
"params": {
"handle": "4c4712a4141d261ec0ca8f9037950685",
"operation": "Installing",
"type": "dac",
"id": "com.libertyglobal.app.awesome",
"version": "1.0.0",
"status": "Success",
"details": "Downloaded 2342 KB, unpacked 3233 KB"
}
}
Activity Diagram Client initiated uninstallation process Uninstall Uninstall error: Application locked true Lock? false Uninstall
AWC Start/Stop process Start DAC Start error: Application not found false Application in Registry? true Lock success fail Start Application error: Application locked process Stop DAC Stop error: Application not found false Application in Registry? true Stop Application Unlock
Sequence Diagram AWC DAC registry Initialization and Update AWC LISA Container Configuration Configuration Application Controller Application Controller AppRegistry AppRegistry Thunder Runner Thunder Runner LISA Plugin LISA Plugin Initialisation 1 Construct/Initialize with defaults 2 "register 'operationStatus' notification listener" { "jsonrpc": "2.0", "id": 0, "method": "LISA.1.register", "params": { "event": "operationStatus", "id": "events.awc.lisa.1" } } 3 read configuration 4 config loop [App list from conf] 5 AWC::ApplicationRegistry.addEntry(appId) loop [list of properties] 6 AWC::ApplicationRegistry.setProperty(appId,key,value) 7 getList 8 result <app_list> loop [App list from LISA] 9 AWC::ApplicationRegistry.addEntry(appId) loop [list of properties] 10 AWC::ApplicationRegistry.setProperty(appId,key,value) 5 minutes later 11 install 12 operationStatus { "id": "1223", "method": "events.awc.lisa.1.operationStatus", "params": { "handle": "4c4712a4141d261ec0ca8f9037950685", "operation": "Installed", "id": "com.libertyglobal.app.extra", "version": "1.0.0", "status": "Success", "details": "Downloaded 2342 KB, unpacked 3233 KB" } } 13 getList 14 result <app_list> loop [App list from LISA] 15 AWC::ApplicationRegistry.addEntry(appId) loop [list of properties] 16 AWC::ApplicationRegistry.setProperty(appId,key,value)
DAC Background Manager installation sequence Application Services AWC LISA Operator Operator Application Services Application Services DAC Background Manager DAC Background Manager Application Controller Application Controller AppRegistry AppRegistry LISA LISA Operator Triggered Installation "register 'operationStatus' notification listener" { "jsonrpc": "2.0", "id": 0, "method": "LISA.1.register", "params": { "event": "operationStatus", "id": "events.dacbg.lisa.1" } } update configuration update configuration Request metadata Metadata getList { "jsonrpc": "2.0", "id": "1223", "method": "LISA.1.getList", "params": { "category": "application" } } result <apps> check if installed loop [all appIds to be installed] Installation Procedure install { ... "method": "LISA.1.install", "params": { "type": "application/vnd.rdk-app.dac.native", "id": "com.libertyglobal.awesine", "version": "1.0.0", "appName": "Awesome Application", ... } } loop [periodically check progress] getProgress ' { "jsonrpc": "2.0", "id": "1223", "method": "LISA.1.getProgress", "params": { "handle": "a76a9ad56769634dbbc9c54bac15ddb9" } } result { "jsonrpc": "2.0", "id": "1223", "result": { "progress": 75 } } 5 minutes later operationStatus { "id": "1223", "method": "events.dacbg.lisa.1.operationStatus", "params": { "handle": "4c4712a4141d261ec0ca8f9037950685", "operation": "Installed", "id": "com.libertyglobal.app.awesome", "version": "1.0.0", "status": "Success", "details": "Downloaded 2342 KB, unpacked 3233 KB" } } operationStatus { "id": "62", "method": "events.awc.lisa.1.operationStatus", "params": { "handle": "4c4712a4141d261ec0ca8f9037950685", "operation": "Installed", "id": "com.libertyglobal.app.awesome", "version": "1.0.0", "status": "Success", "details": "Downloaded 2342 KB, unpacked 3233 KB" } } getList { "jsonrpc": "2.0", "id": "1223", "method": "LISA.1.getList", "params": { "category": "application" } } result <app_list> loop [iterate through getList result] checkIfEntryExists(appId) true AWC::ApplicationRegistry.addEntry(appId) loop [list of properties] AWC::ApplicationRegistry.setProperty(appId,key,value) finished
DAC Background Manager uninstallation sequence Application Services AWC LISA Operator Operator Application Services Application Services DAC Background Manager DAC Background Manager Application Controller Application Controller AppRegistry AppRegistry LISA LISA Operator Triggered Uninstallation "register 'operationStatus' notification listener" { "jsonrpc": "2.0", "id": 0, "method": "LISA.1.register", "params": { "event": "operationStatus", "id": "events.dacbg.lisa.1" } } update configuration update configuration getList { "jsonrpc": "2.0", "id": "1223", "method": "LISA.1.getList", "params": { "category": "application" } } result <apps> check if installed Uninstallation Procedure uninstall { ... "method": "LISA.1.uninstall", "params": { "type": "application/vnd.rdk-app.dac.native", "id": "com.libertyglobal.awesome", "version": "1.0.0", "appName": "Awesome Application", ... } } alt [application not active] result { "jsonrpc": "2.0", "id": "1223", "result": { "handle": "a76a9ad56769634dbbc9c54bac15ddb9" } } [application active (locked by AWC)] error { "code": 1009, "message": "ERROR_APP_ACTIVE" } loop [periodically check progress] getProgress ' { "jsonrpc": "2.0", "id": "1223", "method": "LISA.1.getProgress", "params": { "handle": "a76a9ad56769634dbbc9c54bac15ddb9" } } result { "jsonrpc": "2.0", "id": "1223", "result": { "progress": 75 } } Start checkIfEntryExists(appId) true lock { "method": "LISA.1.lock", "params": { "id": "com.libertyglobal.app.awesome", "version": "1.0.0" } } "Uninstall in progress" error { "code": 1009, "message": "ERROR_APP_UNINSTALLING" } 5 minutes later operationStatus { "id": "1223", "method": "events.dacbg.lisa.1.operationStatus", "params": { "handle": "4c4712a4141d261ec0ca8f9037950685", "operation": "Installed", "id": "com.libertyglobal.app.awesome", "version": "1.0.0", "status": "Success", "details": "Downloaded 2342 KB, unpacked 3233 KB" } } operationStatus { "id": "62", "method": "events.awc.lisa.1.operationStatus", "params": { "handle": "4c4712a4141d261ec0ca8f9037950685", "operation": "Installed", "id": "com.libertyglobal.app.awesome", "version": "1.0.0", "status": "Success", "details": "Downloaded 2342 KB, unpacked 3233 KB" } } getList { "jsonrpc": "2.0", "id": "1223", "method": "LISA.1.getList", "params": { "category": "application" } } result <apps> loop [iterate through getList result] checkIfEntryExists(appId) true AWC::ApplicationRegistry.addEntry(appId) loop [list of properties] AWC::ApplicationRegistry.setProperty(appId,key,value) finished
AWC Start DAC Application Main UI AWC LISA Container Thunder MainUI MainUI Application Controller Application Controller AppRegistry AppRegistry LISA Plugin LISA Plugin OCIContainer OCIContainer 1 Start 2 checkIfEntryExists(appId) 3 true 4 lock { "method": "LISA.1.lock", "params": { "id": "com.libertyglobal.app.awesome", "version": "1.0.0" } } alt [lock succesfull] 5 result { "jsonrpc": "2.0", "id": "1223", "result": { "handle": "a76a9ad56769634dbbc9c54bac15ddb9" } } [application uninstallation in progress] 6 error { "code": 1009, "message": "ERROR_APP_UNINSTALLING" } 7 onStateChange(appId,starting) 8 Parse MIME Type Select AppRunner 9 getStorageDetails(id) 10 Result 11 startContainerFromCryptedBundle 5 seconds later 12 onContainerStarted 13 onStateChange(appId,started)
AWC Stop DAC Application Main UI AWC LISA Container Thunder MainUI MainUI Application Controller Application Controller AppRegistry AppRegistry LISA Plugin LISA Plugin OCIContainer OCIContainer 1 Stop 2 checkIfEntryExists(appId) 3 true 4 onStateChange(appId,stopping) 5 Parse MIME Type Select AppRunner 6 stopContainer 5 seconds later 7 onContainerStopped 8 unlock 9 result <ok> 10 onStateChange(appId,stopped)