2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Modifications Copyright (c) 2019 Samsung
8 * ================================================================================
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 * ============LICENSE_END=========================================================
23 package org.onap.so.bpmn.common.scripts
25 import org.onap.so.client.HttpClientFactory
27 import java.text.SimpleDateFormat
28 import javax.ws.rs.core.Response
29 import java.net.URLEncoder
31 import org.apache.commons.codec.binary.Base64
32 import org.apache.commons.lang3.*
33 import org.camunda.bpm.engine.delegate.BpmnError
34 import org.camunda.bpm.engine.delegate.DelegateExecution
38 import org.json.JSONObject
40 import org.onap.so.bpmn.core.UrnPropertiesReader
41 import org.onap.so.bpmn.core.WorkflowException
42 import org.onap.so.bpmn.core.domain.RollbackData
43 import org.onap.so.bpmn.core.json.JsonUtils
44 import org.onap.so.client.HttpClient
45 import org.onap.so.logger.MessageEnum
46 import org.onap.so.logger.MsoLogger
47 import org.slf4j.Logger
48 import org.slf4j.LoggerFactory
49 import org.onap.so.utils.TargetEntity
54 class SDNCAdapterRestV1 extends AbstractServiceTaskProcessor {
55 private static final Logger logger = LoggerFactory.getLogger( SDNCAdapterRestV1.class);
58 ExceptionUtil exceptionUtil = new ExceptionUtil()
59 JsonUtils jsonUtil = new JsonUtils()
62 * Processes the incoming request.
64 public void preProcessRequest (DelegateExecution execution) {
65 def method = getClass().getSimpleName() + '.preProcessRequest(' +
66 'execution=' + execution.getId() +
68 logger.trace('Entered ' + method)
70 def prefix="SDNCREST_"
71 execution.setVariable("prefix", prefix)
72 setSuccessIndicator(execution, false)
75 // Determine the request type and log the request
77 String request = validateRequest(execution, "mso-request-id")
78 String requestType = jsonUtil.getJsonRootProperty(request)
79 execution.setVariable(prefix + 'requestType', requestType)
80 logger.debug(getProcessKey(execution) + ': ' + prefix + 'requestType = ' + requestType)
82 // Determine the SDNCAdapter endpoint
84 String sdncAdapterEndpoint = UrnPropertiesReader.getVariable("mso.adapters.sdnc.rest.endpoint", execution)
86 if (sdncAdapterEndpoint == null || sdncAdapterEndpoint.isEmpty()) {
87 String msg = getProcessKey(execution) + ': mso:adapters:sdnc:rest:endpoint URN mapping is not defined'
89 logger.error("{} {} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
90 MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError.getValue());
91 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
94 while (sdncAdapterEndpoint.endsWith('/')) {
95 sdncAdapterEndpoint = sdncAdapterEndpoint.substring(0, sdncAdapterEndpoint.length()-1)
98 String sdncAdapterMethod = null
99 String sdncAdapterUrl = null
100 String sdncAdapterRequest = request
102 if ('SDNCServiceRequest'.equals(requestType)) {
103 // Get the sdncRequestId from the request
105 String sdncRequestId = jsonUtil.getJsonValue(request, requestType + ".sdncRequestId")
107 if (sdncRequestId == null || sdncRequestId.isEmpty()) {
108 String msg = getProcessKey(execution) + ': no sdncRequestId in ' + requestType
110 logger.error("{} {} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
111 MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError.getValue());
112 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
115 execution.setVariable('SDNCAResponse_CORRELATOR', sdncRequestId)
116 logger.debug(getProcessKey(execution) + ': SDNCAResponse_CORRELATOR = ' + sdncRequestId)
118 // Get the bpNotificationUrl from the request (just to make sure it's there)
120 String bpNotificationUrl = jsonUtil.getJsonValue(request, requestType + ".bpNotificationUrl")
122 if (bpNotificationUrl == null || bpNotificationUrl.isEmpty()) {
123 String msg = getProcessKey(execution) + ': no bpNotificationUrl in ' + requestType
125 logger.error("{} {} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
126 MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError.getValue());
127 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
130 sdncAdapterMethod = 'POST'
131 sdncAdapterUrl = sdncAdapterEndpoint
133 RollbackData rollbackData = new RollbackData()
134 rollbackData.setRequestId(sdncRequestId)
135 rollbackData.getAdditionalData().put("service", jsonUtil.getJsonValue(request, requestType + ".sdncService"))
136 rollbackData.getAdditionalData().put("operation", jsonUtil.getJsonValue(request, requestType + ".sdncOperation"))
137 execution.setVariable("RollbackData", rollbackData)
140 String msg = getProcessKey(execution) + ': Unsupported request type: ' + requestType
142 logger.error("{} {} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
143 MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError.getValue());
144 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
147 execution.setVariable(prefix + 'sdncAdapterMethod', sdncAdapterMethod)
148 execution.setVariable(prefix + 'sdncAdapterUrl', sdncAdapterUrl)
149 execution.setVariable(prefix + 'sdncAdapterRequest', sdncAdapterRequest)
151 // Get the Basic Auth credentials for the SDNCAdapter (yes... we ARE using the PO adapters credentials)
153 String basicAuthValue = UrnPropertiesReader.getVariable("mso.adapters.po.auth", execution)
155 if (basicAuthValue == null || basicAuthValue.isEmpty()) {
156 logger.debug(getProcessKey(execution) + ": mso:adapters:po:auth URN mapping is not defined")
157 logger.error("{} {} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(),
158 getProcessKey(execution) + ": mso:adapters:po:auth URN mapping is not defined", "BPMN",
159 MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError.getValue());
162 def encodedString = utils.getBasicAuth(basicAuthValue, UrnPropertiesReader.getVariable("mso.msoKey", execution))
163 execution.setVariable(prefix + 'basicAuthHeaderValue', encodedString)
164 } catch (IOException ex) {
165 logger.debug(getProcessKey(execution) + ": Unable to encode BasicAuth credentials for SDNCAdapter")
166 logger.error("{} {} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(),
167 getProcessKey(execution) + ": Unable to encode BasicAuth credentials for SDNCAdapter",
168 "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError.getValue());
172 // Set the timeout value, e.g. PT5M. It may be specified in the request as the
173 // bpTimeout value. If it's not in the request, use the URN mapping value.
175 String timeout = jsonUtil.getJsonValue(request, requestType + ".bpTimeout")
177 // in addition to null/empty, also need to verify that the timer value is a valid duration "P[n]T[n]H|M|S"
178 String timerRegex = "PT[0-9]+[HMS]";
179 if (timeout == null || timeout.isEmpty() || !timeout.matches(timerRegex)) {
180 logger.debug(getProcessKey(execution) + ': preProcessRequest(): null/empty/invalid bpTimeout value. Using "mso.adapters.sdnc.timeout"')
181 timeout = UrnPropertiesReader.getVariable("mso.adapters.sdnc.timeout", execution)
184 // the timeout could still be null at this point if the config parm is missing/undefined
185 // forced to log (so OPs can fix the config) and temporarily use a hard coded value of 10 seconds
186 if (timeout == null) {
187 msoLogger.warnSimple('preProcessRequest()', 'property "mso.adapters.sdnc.timeout" is missing/undefined. Using "PT10S"')
191 execution.setVariable(prefix + 'timeout', timeout)
192 logger.debug(getProcessKey(execution) + ': ' + prefix + 'timeout = ' + timeout)
193 } catch (BpmnError e) {
195 } catch (Exception e) {
196 String msg = 'Caught exception in ' + method + ": " + e
198 logger.error("{} {} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
199 MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError.getValue());
200 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
205 * Sends the request to the SDNC adapter.
207 public void sendRequestToSDNCAdapter(DelegateExecution execution) {
208 def method = getClass().getSimpleName() + '.sendRequestToSDNCAdapter(' +
209 'execution=' + execution.getId() +
211 logger.trace('Entered ' + method)
213 String prefix = execution.getVariable('prefix')
216 String sdncAdapterMethod = execution.getVariable(prefix + 'sdncAdapterMethod')
217 logger.debug("SDNC Method is: " + sdncAdapterMethod)
218 String sdncAdapterUrl = execution.getVariable(prefix + 'sdncAdapterUrl')
219 logger.debug("SDNC Url is: " + sdncAdapterUrl)
220 String sdncAdapterRequest = execution.getVariable(prefix + 'sdncAdapterRequest')
221 logger.debug("SDNC Rest Request is: " + sdncAdapterRequest)
223 URL url = new URL(sdncAdapterUrl);
225 HttpClient httpClient = new HttpClientFactory().newJsonClient(url, TargetEntity.SDNC_ADAPTER)
226 httpClient.addAdditionalHeader("X-ONAP-RequestID", execution.getVariable("mso-request-id"))
227 httpClient.addAdditionalHeader("X-ONAP-InvocationID", UUID.randomUUID().toString())
228 httpClient.addAdditionalHeader("X-ONAP-PartnerName", "SO-SDNCAdapter")
229 httpClient.addAdditionalHeader("mso-request-id", execution.getVariable("mso-request-id"))
230 httpClient.addAdditionalHeader("mso-service-instance-id", execution.getVariable("mso-service-instance-id"))
231 httpClient.addAdditionalHeader("Authorization", execution.getVariable(prefix + "basicAuthHeaderValue"))
235 if ("GET".equals(sdncAdapterMethod)) {
236 response = httpClient.get()
237 } else if ("PUT".equals(sdncAdapterMethod)) {
238 response = httpClient.put(sdncAdapterRequest)
239 } else if ("POST".equals(sdncAdapterMethod)) {
240 response = httpClient.post(sdncAdapterRequest)
241 } else if ("DELETE".equals(sdncAdapterMethod)) {
242 response = httpClient.delete(sdncAdapterRequest)
244 String msg = 'Unsupported HTTP method "' + sdncAdapterMethod + '" in ' + method + ": " + e
246 logger.error("{} {} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
247 MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError.getValue());
248 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
251 execution.setVariable(prefix + "sdncAdapterStatusCode", response.getStatus())
252 if(response.hasEntity()){
253 execution.setVariable(prefix + "sdncAdapterResponse", response.readEntity(String.class))
255 } catch (BpmnError e) {
257 } catch (Exception e) {
258 String msg = 'Caught exception in ' + method + ": " + e
260 logger.error("{} {} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
261 MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError.getValue());
262 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
267 * Processes a callback.
269 public void processCallback(DelegateExecution execution){
270 def method = getClass().getSimpleName() + '.processCallback(' +
271 'execution=' + execution.getId() +
273 logger.trace('Entered ' + method)
275 String prefix = execution.getVariable('prefix')
276 String callback = execution.getVariable('SDNCAResponse_MESSAGE')
277 String requestId = execution.getVariable("mso-request-id");
278 String serviceInstanceId = execution.getVariable("mso-service-instance-id")
279 utils.logContext(requestId, serviceInstanceId)
280 logger.debug("Incoming SDNC Rest Callback is: " + callback)
283 int callbackNumber = 1
284 while (execution.getVariable(prefix + 'callback' + callbackNumber) != null) {
288 execution.setVariable(prefix + 'callback' + callbackNumber, callback)
289 execution.removeVariable('SDNCAResponse_MESSAGE')
291 String responseType = jsonUtil.getJsonRootProperty(callback)
293 // Get the ackFinalIndicator and make sure it's either Y or N. Default to Y.
294 String ackFinalIndicator = jsonUtil.getJsonValue(callback, responseType + ".ackFinalIndicator")
296 if (!'N'.equals(ackFinalIndicator)) {
297 ackFinalIndicator = 'Y'
300 execution.setVariable(prefix + "ackFinalIndicator", ackFinalIndicator)
302 if (responseType.endsWith('Error')) {
303 sdncAdapterBuildWorkflowException(execution, callback)
305 } catch (Exception e) {
306 callback = callback == null || String.valueOf(callback).isEmpty() ? "NONE" : callback
307 String msg = "Received error from SDNCAdapter: " + callback
308 logger.debug(getProcessKey(execution) + ': ' + msg)
309 exceptionUtil.buildWorkflowException(execution, 5300, msg)
314 * Tries to parse the response as XML to extract the information to create
315 * a WorkflowException. If the response cannot be parsed, a more generic
316 * WorkflowException is created.
318 public void sdncAdapterBuildWorkflowException(DelegateExecution execution, String response) {
320 String responseType = jsonUtil.getJsonRootProperty(response)
321 String responseCode = jsonUtil.getJsonValue(response, responseType + ".responseCode")
322 String responseMessage = jsonUtil.getJsonValue(response, responseType + ".responseMessage")
326 if (responseCode != null && !responseCode.isEmpty()) {
327 info += " responseCode='" + responseCode + "'"
330 if (responseMessage != null && !responseMessage.isEmpty()) {
331 info += " responseMessage='" + responseMessage + "'"
334 // Note: the mapping function handles a null or empty responseCode
335 int mappedResponseCode = Integer.parseInt(exceptionUtil.MapSDNCResponseCodeToErrorCode(responseCode));
336 exceptionUtil.buildWorkflowException(execution, mappedResponseCode, "Received " + responseType +
337 " from SDNCAdapter:" + info)
338 } catch (Exception e) {
339 response = response == null || String.valueOf(response).isEmpty() ? "NONE" : response
340 exceptionUtil.buildWorkflowException(execution, 5300, "Received error from SDNCAdapter: " + response)
345 * Gets the last callback request from the execution, or null if there was no callback.
347 public String getLastCallback(DelegateExecution execution) {
348 def method = getClass().getSimpleName() + '.getLastCallback(' +
349 'execution=' + execution.getId() +
351 logger.trace('Entered ' + method)
353 String prefix = execution.getVariable('prefix')
356 int callbackNumber = 1
357 String callback = null
360 String thisCallback = (String) execution.getVariable(prefix + 'callback' + callbackNumber)
362 if (thisCallback == null) {
366 callback = thisCallback
371 } catch (Exception e) {
372 String msg = 'Caught exception in ' + method + ": " + e
374 logger.error("{} {} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
375 MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError.getValue());
376 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
381 * Sets the timeout value to wait for the next notification.
383 public void setTimeoutValue(DelegateExecution execution) {
384 def method = getClass().getSimpleName() + '.setTimeoutValue(' +
385 'execution=' + execution.getId() +
387 logger.trace('Entered ' + method)
389 String prefix = execution.getVariable('prefix')
392 def timeoutValue = UrnPropertiesReader.getVariable("mso.adapters.sdnc.timeout", execution)
394 if (execution.getVariable(prefix + 'callback1') != null) {
395 // Waiting for subsequent notifications
397 } catch (Exception e) {
398 String msg = 'Caught exception in ' + method + ": " + e
400 logger.error("{} {} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
401 MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError.getValue());
402 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)