aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Timoney <dtimoney@att.com>2019-10-31 12:59:33 +0000
committerGerrit Code Review <gerrit@onap.org>2019-10-31 12:59:33 +0000
commitdeeaa0a6df8f266c10130833f06dec0ca9773b78 (patch)
tree643f3d7489cb3254d4349696483cdb76071b2fe7
parent7170f91ff015b15ff600d9a8a4ad9fdc1ec3915d (diff)
parentf0ad7cdc6f99b03cba9dcbb38e9116128a1f6d81 (diff)
Merge "Add remote service function execution."
-rw-r--r--ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/ExecutionServiceHandler.kt41
-rw-r--r--ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/ExecutionServiceHandlerTest.kt84
-rw-r--r--ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/AbstractServiceFunction.kt112
3 files changed, 227 insertions, 10 deletions
diff --git a/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/ExecutionServiceHandler.kt b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/ExecutionServiceHandler.kt
index 20af589a1..ade47cf3f 100644
--- a/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/ExecutionServiceHandler.kt
+++ b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/ExecutionServiceHandler.kt
@@ -23,11 +23,13 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.*
import org.onap.ccsdk.cds.blueprintsprocessor.selfservice.api.utils.toProto
+import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractServiceFunction
import org.onap.ccsdk.cds.controllerblueprints.common.api.EventType
import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants
import org.onap.ccsdk.cds.controllerblueprints.core.config.BluePrintLoadConfiguration
import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintCatalogService
import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintWorkflowExecutionService
+import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintDependencyService
import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
@@ -70,26 +72,45 @@ class ExecutionServiceHandler(private val bluePrintLoadConfiguration: BluePrintL
val blueprintName = actionIdentifiers.blueprintName
val blueprintVersion = actionIdentifiers.blueprintVersion
try {
- val basePath = blueprintsProcessorCatalogService.getFromDatabase(blueprintName, blueprintVersion)
- log.info("blueprint base path $basePath")
+ /** Check Blueprint is needed for this request */
+ if (checkServiceFunction(executionServiceInput)) {
+ return executeServiceFunction(executionServiceInput)
+ } else {
+ val basePath = blueprintsProcessorCatalogService.getFromDatabase(blueprintName, blueprintVersion)
+ log.info("blueprint base path $basePath")
- val blueprintRuntimeService = BluePrintMetadataUtils.getBluePrintRuntime(requestId, basePath.toString())
+ val blueprintRuntimeService = BluePrintMetadataUtils.getBluePrintRuntime(requestId, basePath.toString())
- val output = bluePrintWorkflowExecutionService.executeBluePrintWorkflow(blueprintRuntimeService,
- executionServiceInput, hashMapOf())
+ val output = bluePrintWorkflowExecutionService.executeBluePrintWorkflow(blueprintRuntimeService,
+ executionServiceInput, hashMapOf())
- val errors = blueprintRuntimeService.getBluePrintError().errors
- if (errors.isNotEmpty()) {
- val errorMessage = errors.stream().map { it.toString() }.collect(Collectors.joining(", "))
- setErrorStatus(errorMessage, output.status)
+ val errors = blueprintRuntimeService.getBluePrintError().errors
+ if (errors.isNotEmpty()) {
+ val errorMessage = errors.stream().map { it.toString() }.collect(Collectors.joining(", "))
+ setErrorStatus(errorMessage, output.status)
+ }
+ return output
}
- return output
} catch (e: Exception) {
log.error("fail processing request id $requestId", e)
return response(executionServiceInput, e.localizedMessage ?: e.message ?: e.toString(), true)
}
}
+ /** If the blueprint name is default, It means no blueprint is needed for the execution */
+ fun checkServiceFunction(executionServiceInput: ExecutionServiceInput): Boolean {
+ return executionServiceInput.actionIdentifiers.blueprintName == "default"
+ }
+
+ /** If no blueprint is needed, then get the Service function instance mapping to the action name and execute it */
+ suspend fun executeServiceFunction(executionServiceInput: ExecutionServiceInput): ExecutionServiceOutput {
+ val actionName = executionServiceInput.actionIdentifiers.actionName
+ val instance = BluePrintDependencyService.instance<AbstractServiceFunction>(actionName)
+ checkNotNull(instance) { "failed to initialize service function($actionName)" }
+ instance.actionName = actionName
+ return instance.applyNB(executionServiceInput)
+ }
+
private fun setErrorStatus(errorMessage: String, status: Status) {
status.errorMessage = errorMessage
status.eventType = EventType.EVENT_COMPONENT_FAILURE.name
diff --git a/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/ExecutionServiceHandlerTest.kt b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/ExecutionServiceHandlerTest.kt
new file mode 100644
index 000000000..293da0da6
--- /dev/null
+++ b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/ExecutionServiceHandlerTest.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright © 2018-2019 AT&T Intellectual Property.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onap.ccsdk.cds.blueprintsprocessor.selfservice.api
+
+import io.mockk.mockk
+import kotlinx.coroutines.runBlocking
+import org.junit.Before
+import org.junit.runner.RunWith
+import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ActionIdentifiers
+import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.CommonHeader
+import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput
+import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractServiceFunction
+import org.onap.ccsdk.cds.controllerblueprints.core.jsonAsJsonType
+import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintDependencyService
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.context.ApplicationContext
+import org.springframework.stereotype.Service
+import org.springframework.test.context.ContextConfiguration
+import org.springframework.test.context.junit4.SpringRunner
+import kotlin.test.Test
+import kotlin.test.assertNotNull
+import kotlin.test.assertTrue
+
+@RunWith(SpringRunner::class)
+@ContextConfiguration(classes = [MockServiceAction::class])
+class ExecutionServiceHandlerTest {
+
+ @Autowired
+ lateinit var applicationContext: ApplicationContext
+
+ @Before
+ fun init() {
+ BluePrintDependencyService.inject(applicationContext)
+ }
+
+ @Test
+ fun testExecuteServiceFunction() {
+ val executionServiceInput = ExecutionServiceInput().apply {
+ commonHeader = CommonHeader().apply {
+ requestId = "1234"
+ subRequestId = "1234-12"
+ originatorId = "cds-test"
+ }
+ actionIdentifiers = ActionIdentifiers().apply {
+ blueprintName = "default"
+ blueprintVersion = "1.0.0"
+ actionName = "mock-service-action"
+ }
+ }
+ runBlocking {
+ val executionServiceHandler = ExecutionServiceHandler(mockk(), mockk(), mockk())
+ val isServiceFunction = executionServiceHandler.checkServiceFunction(executionServiceInput)
+ assertTrue(isServiceFunction, "failed to checkServiceFunction")
+ val executionServiceOutput = executionServiceHandler.executeServiceFunction(executionServiceInput)
+ assertNotNull(executionServiceOutput, "failed to get executionServiceOutput")
+ }
+ }
+}
+
+@Service("mock-service-action")
+class MockServiceAction : AbstractServiceFunction() {
+ override suspend fun processNB(executionRequest: ExecutionServiceInput) {
+ val responsePayload = """{"answer" : "correct"}""".jsonAsJsonType()
+ setResponsePayloadForAction(responsePayload)
+ }
+
+ override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) {
+
+ }
+} \ No newline at end of file
diff --git a/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/AbstractServiceFunction.kt b/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/AbstractServiceFunction.kt
new file mode 100644
index 000000000..67ab9c4de
--- /dev/null
+++ b/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/AbstractServiceFunction.kt
@@ -0,0 +1,112 @@
+/*
+ * Copyright © 2018-2019 AT&T Intellectual Property.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onap.ccsdk.cds.blueprintsprocessor.services.execution
+
+import com.fasterxml.jackson.databind.JsonNode
+import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput
+import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceOutput
+import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.Status
+import org.onap.ccsdk.cds.controllerblueprints.common.api.EventType
+import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants
+import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BlueprintFunctionNode
+import org.onap.ccsdk.cds.controllerblueprints.core.jsonPathParse
+import org.onap.ccsdk.cds.controllerblueprints.core.logger
+import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
+
+/** This implementation is used to build services, which doesn't need blueprints */
+abstract class AbstractServiceFunction : BlueprintFunctionNode<ExecutionServiceInput, ExecutionServiceOutput> {
+
+ @Transient
+ private val log = logger(AbstractServiceFunction::class)
+
+ lateinit var executionServiceInput: ExecutionServiceInput
+ var executionServiceOutput = ExecutionServiceOutput()
+ lateinit var processId: String
+ lateinit var actionName: String
+ lateinit var responseActionPayload: JsonNode
+
+ override fun getName(): String {
+ return actionName
+ }
+
+ override suspend fun prepareRequestNB(executionRequest: ExecutionServiceInput): ExecutionServiceInput {
+
+ this.executionServiceInput = executionRequest
+
+ actionName = executionRequest.actionIdentifiers.actionName
+ check(actionName.isNotEmpty()) { "couldn't get action name" }
+
+ processId = executionRequest.commonHeader.requestId
+ check(processId.isNotEmpty()) { "couldn't get process id for service action($actionName)" }
+
+ return executionRequest
+ }
+
+ override suspend fun applyNB(executionServiceInput: ExecutionServiceInput): ExecutionServiceOutput {
+ try {
+ prepareRequestNB(executionServiceInput)
+ processNB(executionServiceInput)
+ } catch (runtimeException: RuntimeException) {
+ log.error("failed in ${getName()} : ${runtimeException.message}", runtimeException)
+ recoverNB(runtimeException, executionServiceInput)
+ }
+ return prepareResponseNB()
+ }
+
+ override suspend fun prepareResponseNB(): ExecutionServiceOutput {
+ log.debug("Preparing Response...")
+ executionServiceOutput.commonHeader = executionServiceInput.commonHeader
+ executionServiceOutput.actionIdentifiers = executionServiceInput.actionIdentifiers
+ var status = Status()
+ try {
+ // Set the Response Payload
+ executionServiceOutput.payload = JacksonUtils.objectMapper.createObjectNode()
+ executionServiceOutput.payload.set("$actionName-response", responseActionPayload)
+ // Set the Default Step Status
+ status.eventType = EventType.EVENT_COMPONENT_EXECUTED.name
+ } catch (e: Exception) {
+ status.message = BluePrintConstants.STATUS_FAILURE
+ status.eventType = EventType.EVENT_COMPONENT_FAILURE.name
+ }
+ executionServiceOutput.status = status
+ return this.executionServiceOutput
+ }
+
+ fun setResponsePayloadForAction(actionPayload: JsonNode) {
+ this.responseActionPayload = actionPayload
+ }
+
+ /**
+ * Get Execution Input Payload data
+ */
+ fun requestPayload(): JsonNode? {
+ return executionServiceInput.payload
+ }
+
+ /**
+ * Get Execution Input payload action property with [expression]
+ * ex: requestPayloadActionProperty("data") will look for path "payload/<action-name>-request/data"
+ */
+ fun requestPayloadActionProperty(expression: String?): JsonNode? {
+ val requestExpression = if (expression.isNullOrBlank()) {
+ "$actionName-request"
+ } else {
+ "$actionName-request.$expression"
+ }
+ return executionServiceInput.payload.jsonPathParse(".$requestExpression")
+ }
+} \ No newline at end of file