Migrate "ms/controllerblueprints" from ccsdk/apps
[ccsdk/cds.git] / ms / blueprintsprocessor / modules / inbounds / selfservice-api / src / main / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / selfservice / api / ExecutionServiceHandler.kt
1 /*
2  * Copyright © 2017-2018 AT&T Intellectual Property.
3  * Modifications Copyright © 2019 IBM.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 package org.onap.ccsdk.cds.blueprintsprocessor.selfservice.api
19
20 import com.fasterxml.jackson.databind.node.JsonNodeFactory
21 import io.grpc.stub.StreamObserver
22 import kotlinx.coroutines.Dispatchers
23 import kotlinx.coroutines.GlobalScope
24 import kotlinx.coroutines.launch
25 import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintCoreConfiguration
26 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ACTION_MODE_ASYNC
27 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ACTION_MODE_SYNC
28 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput
29 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceOutput
30 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.Status
31 import org.onap.ccsdk.cds.blueprintsprocessor.selfservice.api.utils.saveCBAFile
32 import org.onap.ccsdk.cds.blueprintsprocessor.selfservice.api.utils.toProto
33 import org.onap.ccsdk.cds.controllerblueprints.common.api.EventType
34 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants
35 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException
36 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintCatalogService
37 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintWorkflowExecutionService
38 import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintFileUtils
39 import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils
40 import org.slf4j.LoggerFactory
41 import org.springframework.http.codec.multipart.FilePart
42 import org.springframework.stereotype.Service
43 import reactor.core.publisher.Mono
44 import java.util.stream.Collectors
45
46 @Service
47 class ExecutionServiceHandler(private val bluePrintCoreConfiguration: BluePrintCoreConfiguration,
48                               private val bluePrintCatalogService: BluePrintCatalogService,
49                               private val bluePrintWorkflowExecutionService
50                               : BluePrintWorkflowExecutionService<ExecutionServiceInput, ExecutionServiceOutput>) {
51
52     private val log = LoggerFactory.getLogger(ExecutionServiceHandler::class.toString())
53
54     fun upload(filePart: FilePart): Mono<String> {
55         try {
56             val archivedPath = BluePrintFileUtils.getCbaStorageDirectory(bluePrintCoreConfiguration.archivePath)
57             val cbaPath = saveCBAFile(filePart, archivedPath)
58             bluePrintCatalogService.saveToDatabase(cbaPath.toFile()).let {
59                 return Mono.just("{\"status\": \"Successfully uploaded blueprint with id($it)\"}")
60             }
61         } catch (e: Exception) {
62             return Mono.error<String>(BluePrintException("Error uploading the CBA file.", e))
63         }
64     }
65
66     suspend fun process(executionServiceInput: ExecutionServiceInput,
67                         responseObserver: StreamObserver<org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceOutput>) {
68         when {
69             executionServiceInput.actionIdentifiers.mode == ACTION_MODE_ASYNC -> {
70                 GlobalScope.launch(Dispatchers.Default) {
71                     val executionServiceOutput = doProcess(executionServiceInput)
72                     responseObserver.onNext(executionServiceOutput.toProto())
73                     responseObserver.onCompleted()
74                 }
75                 responseObserver.onNext(response(executionServiceInput).toProto())
76             }
77             executionServiceInput.actionIdentifiers.mode == ACTION_MODE_SYNC -> {
78                 val executionServiceOutput = doProcess(executionServiceInput)
79                 responseObserver.onNext(executionServiceOutput.toProto())
80                 responseObserver.onCompleted()
81             }
82             else -> responseObserver.onNext(response(executionServiceInput,
83                 "Failed to process request, 'actionIdentifiers.mode' not specified. Valid value are: 'sync' or 'async'.",
84                 true).toProto());
85         }
86     }
87
88     suspend fun doProcess(executionServiceInput: ExecutionServiceInput): ExecutionServiceOutput {
89         val requestId = executionServiceInput.commonHeader.requestId
90         log.info("processing request id $requestId")
91
92         val actionIdentifiers = executionServiceInput.actionIdentifiers
93
94         val blueprintName = actionIdentifiers.blueprintName
95         val blueprintVersion = actionIdentifiers.blueprintVersion
96
97         val basePath = bluePrintCatalogService.getFromDatabase(blueprintName, blueprintVersion)
98         log.info("blueprint base path $basePath")
99
100         val blueprintRuntimeService = BluePrintMetadataUtils.getBluePrintRuntime(requestId, basePath.toString())
101
102         val output = bluePrintWorkflowExecutionService.executeBluePrintWorkflow(blueprintRuntimeService,
103             executionServiceInput, hashMapOf())
104
105         val errors = blueprintRuntimeService.getBluePrintError().errors
106         if (errors.isNotEmpty()) {
107             val errorMessage = errors.stream().map { it.toString() }.collect(Collectors.joining(", "))
108             setErrorStatus(errorMessage, output.status)
109         }
110
111         return output
112     }
113
114     private fun setErrorStatus(errorMessage: String, status: Status) {
115         status.errorMessage = errorMessage
116         status.eventType = EventType.EVENT_COMPONENT_FAILURE.name
117         status.code = 500
118         status.message = BluePrintConstants.STATUS_FAILURE
119     }
120
121     private fun response(executionServiceInput: ExecutionServiceInput, errorMessage: String = "",
122                          failure: Boolean = false): ExecutionServiceOutput {
123         val executionServiceOutput = ExecutionServiceOutput()
124         executionServiceOutput.commonHeader = executionServiceInput.commonHeader
125         executionServiceOutput.actionIdentifiers = executionServiceInput.actionIdentifiers
126         executionServiceOutput.payload = JsonNodeFactory.instance.objectNode()
127
128         val status = Status()
129         if (failure) {
130             setErrorStatus(errorMessage, status)
131         } else {
132             status.eventType = EventType.EVENT_COMPONENT_PROCESSING.name
133             status.code = 200
134             status.message = BluePrintConstants.STATUS_PROCESSING
135         }
136
137         executionServiceOutput.status = status
138
139         return executionServiceOutput
140     }
141
142 }