Merge "added test case to ResponseHandlerTest.java"
[so.git] / bpmn / MSOCommonBPMN / src / main / groovy / org / onap / so / bpmn / common / scripts / OofUtils.groovy
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
4  * ================================================================================
5  * Copyright (C) 2018 Intel Corp. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.so.bpmn.common.scripts
22
23 import org.camunda.bpm.engine.delegate.DelegateExecution
24 import org.onap.so.bpmn.common.scripts.AbstractServiceTaskProcessor
25 import org.onap.so.bpmn.common.scripts.ExceptionUtil
26 import org.onap.so.bpmn.core.UrnPropertiesReader
27 import org.onap.so.bpmn.core.domain.HomingSolution
28 import org.onap.so.bpmn.core.domain.ModelInfo
29 import org.onap.so.bpmn.core.domain.Resource
30 import org.onap.so.bpmn.core.domain.AllottedResource
31 import org.onap.so.bpmn.core.domain.ServiceDecomposition
32 import org.onap.so.bpmn.core.domain.ServiceInstance
33 import org.onap.so.bpmn.core.domain.Subscriber
34 import org.onap.so.bpmn.core.domain.VnfResource
35 import org.onap.so.bpmn.core.json.JsonUtils
36 import org.onap.so.db.catalog.beans.CloudSite
37 import org.onap.so.rest.APIResponse
38 import org.onap.so.rest.RESTClient
39 import org.onap.so.rest.RESTConfig
40 import org.springframework.http.HttpEntity
41 import org.springframework.http.HttpHeaders
42 import org.springframework.http.HttpMethod
43 import org.springframework.http.ResponseEntity
44 import org.springframework.http.client.BufferingClientHttpRequestFactory
45 import org.springframework.http.client.HttpComponentsClientHttpRequestFactory
46 import org.springframework.web.client.RestTemplate
47 import org.springframework.web.util.UriComponentsBuilder
48
49 import javax.ws.rs.core.MediaType
50 import javax.ws.rs.core.Response
51 import javax.xml.ws.http.HTTPException
52
53 import static org.onap.so.bpmn.common.scripts.GenericUtils.*
54
55 class OofUtils {
56     ExceptionUtil exceptionUtil = new ExceptionUtil()
57     JsonUtils jsonUtil = new JsonUtils()
58
59     private AbstractServiceTaskProcessor utils
60
61     OofUtils(AbstractServiceTaskProcessor taskProcessor) {
62         this.utils = taskProcessor
63     }
64
65     /**
66      * This method builds the service-agnostic
67      * OOF json request to get a homing solution
68      * and license solution
69      *
70      * @param execution
71      * @param requestId
72      * @param decomposition - ServiceDecomposition object
73      * @param customerLocation -
74      * @param existingCandidates -
75      * @param excludedCandidates -
76      * @param requiredCandidates -
77      *
78      * @return request - OOF v1 payload - https://wiki.onap.org/pages/viewpage.action?pageId=25435066
79      */
80     String buildRequest(DelegateExecution execution,
81                         String requestId,
82                         ServiceDecomposition decomposition,
83                         Subscriber subscriber = null,
84                         Map customerLocation,
85                         ArrayList existingCandidates = null,
86                         ArrayList excludedCandidates = null,
87                         ArrayList requiredCandidates = null) {
88         def isDebugEnabled = execution.getVariable("isDebugLogEnabled")
89         utils.log("DEBUG", "Started Building OOF Request", isDebugEnabled)
90         def callbackUrl = utils.createWorkflowMessageAdapterCallbackURL(execution, "oofResponse", requestId)
91         def transactionId = requestId
92         //ServiceInstance Info
93         ServiceInstance serviceInstance = decomposition.getServiceInstance()
94         def serviceInstanceId = ""
95         def serviceName = ""
96
97         serviceInstanceId = execution.getVariable("serviceInstanceId")
98         serviceName = execution.getVariable("subscriptionServiceType")
99
100         if (serviceInstanceId == null || serviceInstanceId == "null") {
101             utils.log("DEBUG", "Unable to obtain Service Instance Id", isDebugEnabled)
102             exceptionUtil.buildAndThrowWorkflowException(execution, 400, "Internal Error - Unable to " +
103                     "obtain Service Instance Id, execution.getVariable(\"serviceInstanceId\") is null")
104         }
105         if (serviceName == null || serviceName == "null") {
106             utils.log("DEBUG", "Unable to obtain Service Name", isDebugEnabled)
107             exceptionUtil.buildAndThrowWorkflowException(execution, 400, "Internal Error - Unable to " +
108                     "obtain Service Name, execution.getVariable(\"subscriptionServiceType\") is null")
109         }
110         //Model Info
111         ModelInfo model = decomposition.getModelInfo()
112         String modelType = model.getModelType()
113         String modelInvariantId = model.getModelInvariantUuid()
114         String modelVersionId = model.getModelUuid()
115         String modelName = model.getModelName()
116         String modelVersion = model.getModelVersion()
117         //Subscriber Info
118         String subscriberId = ""
119         String subscriberName = ""
120         String commonSiteId = ""
121         if (subscriber != null){
122             subscriberId = subscriber.getGlobalId()
123             subscriberName = subscriber.getName()
124             commonSiteId = subscriber.getCommonSiteId()
125         }
126
127         //Determine RequestType
128         //TODO Figure out better way to determine this
129         String requestType = "create"
130         List<Resource> resources = decomposition.getServiceResources()
131         for(Resource r:resources){
132             HomingSolution currentSolution = (HomingSolution) r.getCurrentHomingSolution()
133             if(currentSolution != null){
134                 requestType = "speed changed"
135             }
136         }
137
138         //Demands
139         String placementDemands = ""
140         StringBuilder sb = new StringBuilder()
141         List<AllottedResource> allottedResourceList = decomposition.getAllottedResources()
142         List<VnfResource> vnfResourceList = decomposition.getVnfResources()
143
144         if (allottedResourceList == null || allottedResourceList.isEmpty() ) {
145             utils.log("DEBUG", "Allotted Resources List is empty - will try to get service VNFs instead.",
146                     isDebugEnabled)
147             allottedResourceList = decomposition.getVnfResources()
148         }
149
150         if (allottedResourceList == null || allottedResourceList.isEmpty()) {
151             utils.log("DEBUG", "Resources List is Empty", isDebugEnabled)
152         } else {
153             for (AllottedResource resource : allottedResourceList) {
154                 utils.log("DEBUG", "Allotted Resource: " + resource.toString(),
155                         isDebugEnabled)
156                 def serviceResourceId = resource.getResourceId()
157                 def resourceModelInvariantId = resource.getModelInfo().getModelInvariantUuid()
158                 def resourceModelVersionId = resource.getModelInfo().getModelUuid()
159                 def resourceModelName = resource.getModelInfo().getModelName()
160                 def resourceModelVersion = resource.getModelInfo().getModelVersion()
161                 def resourceModelType = resource.getModelInfo().getModelType()
162                 def tenantId = execution.getVariable("tenantId")
163                 def requiredCandidatesJson = ""
164
165                 requiredCandidatesJson = createCandidateJson(
166                         existingCandidates,
167                         excludedCandidates,
168                         requiredCandidates)
169
170                 String demand =
171                         "      {\n" +
172                         "      \"resourceModuleName\": \"${resourceModelName}\",\n" +
173                         "      \"serviceResourceId\": \"${serviceResourceId}\",\n" +
174                         "      \"tenantId\": \"${tenantId}\",\n" +
175                         "      \"resourceModelInfo\": {\n" +
176                         "        \"modelInvariantId\": \"${resourceModelInvariantId}\",\n" +
177                         "        \"modelVersionId\": \"${resourceModelVersionId}\",\n" +
178                         "        \"modelName\": \"${resourceModelName}\",\n" +
179                         "        \"modelType\": \"${resourceModelType}\",\n" +
180                         "        \"modelVersion\": \"${resourceModelVersion}\",\n" +
181                         "        \"modelCustomizationName\": \"\"\n" +
182                         "        }" + requiredCandidatesJson + "\n" +
183                         "      },"
184
185                 placementDemands = sb.append(demand)
186             }
187             for (VnfResource vnfResource : vnfResourceList) {
188                 utils.log("DEBUG", "VNF Resource: " + vnfResource.toString(),
189                         isDebugEnabled)
190                 ModelInfo vnfResourceModelInfo = vnfResource.getModelInfo()
191                 def serviceResourceId = vnfResource.getResourceId()
192                 def resourceModelInvariantId = vnfResourceModelInfo.getModelInvariantUuid()
193                 def resourceModelName = vnfResourceModelInfo.getModelName()
194                 def resourceModelVersion = vnfResourceModelInfo.getModelVersion()
195                 def resourceModelVersionId = vnfResourceModelInfo.getModelUuid()
196                 def resourceModelType = vnfResourceModelInfo.getModelType()
197                 def tenantId = execution.getVariable("tenantId")
198                 def requiredCandidatesJson = ""
199
200
201                 String placementDemand =
202                         "      {\n" +
203                         "      \"resourceModuleName\": \"${resourceModelName}\",\n" +
204                         "      \"serviceResourceId\": \"${serviceResourceId}\",\n" +
205                         "      \"tenantId\": \"${tenantId}\",\n" +
206                         "      \"resourceModelInfo\": {\n" +
207                         "        \"modelInvariantId\": \"${resourceModelInvariantId}\",\n" +
208                         "        \"modelVersionId\": \"${resourceModelVersionId}\",\n" +
209                         "        \"modelName\": \"${resourceModelName}\",\n" +
210                         "        \"modelType\": \"${resourceModelType}\",\n" +
211                         "        \"modelVersion\": \"${resourceModelVersion}\",\n" +
212                         "        \"modelCustomizationName\": \"\"\n" +
213                         "        }" + requiredCandidatesJson + "\n" +
214                         "      },"
215
216                 placementDemands = sb.append(placementDemand)
217             }
218             placementDemands = placementDemands.substring(0, placementDemands.length() - 1)
219         }
220
221         /* Commenting Out Licensing as OOF doesn't support for Beijing
222         String licenseDemands = ""
223         sb = new StringBuilder()
224         if (vnfResourceList.isEmpty() || vnfResourceList == null) {
225             utils.log("DEBUG", "Vnf Resources List is Empty", isDebugEnabled)
226         } else {
227             for (VnfResource vnfResource : vnfResourceList) {
228                 ModelInfo vnfResourceModelInfo = vnfResource.getModelInfo()
229                 def resourceInstanceType = vnfResource.getResourceType()
230                 def serviceResourceId = vnfResource.getResourceId()
231                 def resourceModuleName = vnfResource.getResourceType()
232                 def resouceModelInvariantId = vnfResourceModelInfo.getModelInvariantUuid()
233                 def resouceModelName = vnfResourceModelInfo.getModelName()
234                 def resouceModelVersion = vnfResourceModelInfo.getModelVersion()
235                 def resouceModelVersionId = vnfResourceModelInfo.getModelUuid()
236                 def resouceModelType = vnfResourceModelInfo.getModelType()
237
238                 // TODO Add Existing Licenses to demand
239                 //"existingLicenses": {
240                 //"entitlementPoolUUID": ["87257b49-9602-4ca1-9817-094e52bc873b",
241                 // "43257b49-9602-4fe5-9337-094e52bc9435"],
242                 //"licenseKeyGroupUUID": ["87257b49-9602-4ca1-9817-094e52bc873b",
243                 // "43257b49-9602-4fe5-9337-094e52bc9435"]
244                 //}
245
246                     String licenseDemand =
247                         "{\n" +
248                         "\"resourceModuleName\": \"${resourceModuleName}\",\n" +
249                         "\"serviceResourceId\": \"${serviceResourceId}\",\n" +
250                         "\"resourceInstanceType\": \"${resourceInstanceType}\",\n" +
251                         "\"resourceModelInfo\": {\n" +
252                         "  \"modelInvariantId\": \"${resouceModelInvariantId}\",\n" +
253                         "  \"modelVersionId\": \"${resouceModelVersionId}\",\n" +
254                         "  \"modelName\": \"${resouceModelName}\",\n" +
255                         "  \"modelType\": \"${resouceModelType}\",\n" +
256                         "  \"modelVersion\": \"${resouceModelVersion}\",\n" +
257                         "  \"modelCustomizationName\": \"\"\n" +
258                         "  }\n"
259                         "},"
260
261                 licenseDemands = sb.append(licenseDemand)
262             }
263             licenseDemands = licenseDemands.substring(0, licenseDemands.length() - 1)
264         }*/
265
266         String request =
267                 "{\n" +
268                 "  \"requestInfo\": {\n" +
269                 "    \"transactionId\": \"${transactionId}\",\n" +
270                 "    \"requestId\": \"${requestId}\",\n" +
271                 "    \"callbackUrl\": \"${callbackUrl}\",\n" +
272                 "    \"sourceId\": \"so\",\n" +
273                 "    \"requestType\": \"${requestType}\"," +
274                 "    \"numSolutions\": 1,\n" +
275                 "    \"optimizers\": [\"placement\"],\n" +
276                 "    \"timeout\": 600\n" +
277                 "    },\n" +
278                 "  \"placementInfo\": {\n" +
279                 "    \"requestParameters\": {\n" +
280                 "      \"customerLatitude\": \"${customerLocation.customerLatitude}\",\n" +
281                 "      \"customerLongitude\": \"${customerLocation.customerLongitude}\",\n" +
282                 "      \"customerName\": \"${customerLocation.customerName}\"\n" +
283                 "    }," +
284                 "    \"subscriberInfo\": { \n" +
285                 "      \"globalSubscriberId\": \"${subscriberId}\",\n" +
286                 "      \"subscriberName\": \"${subscriberName}\",\n" +
287                 "      \"subscriberCommonSiteId\": \"${commonSiteId}\"\n" +
288                 "    },\n" +
289                 "    \"placementDemands\": [\n" +
290                 "      ${placementDemands}\n" +
291                 "      ]\n" +
292                 "    },\n" +
293                 "  \"serviceInfo\": {\n" +
294                 "    \"serviceInstanceId\": \"${serviceInstanceId}\",\n" +
295                 "    \"serviceName\": \"${serviceName}\",\n" +
296                 "    \"modelInfo\": {\n" +
297                 "      \"modelType\": \"${modelType}\",\n" +
298                 "      \"modelInvariantId\": \"${modelInvariantId}\",\n" +
299                 "      \"modelVersionId\": \"${modelVersionId}\",\n" +
300                 "      \"modelName\": \"${modelName}\",\n" +
301                 "      \"modelVersion\": \"${modelVersion}\",\n" +
302                 "      \"modelCustomizationName\": \"\"\n" +
303                 "    }\n" +
304                 "  }\n" +
305                 "}"
306
307
308         utils.log("DEBUG", "Completed Building OOF Request", isDebugEnabled)
309         return request
310     }
311
312     /**
313      * This method validates the callback response
314      * from OOF. If the response contains an
315      * exception the method will build and throw
316      * a workflow exception.
317      *
318      * @param execution
319      * @param response - the async callback response from oof
320      */
321     Void validateCallbackResponse(DelegateExecution execution, String response) {
322         def isDebugEnabled = execution.getVariable("isDebugLogEnabled")
323         String placements = ""
324         if (isBlank(response)) {
325             exceptionUtil.buildAndThrowWorkflowException(execution, 5000, "OOF Async Callback Response is Empty")
326         } else {
327             if (JsonUtils.jsonElementExist(response, "solutions.placementSolutions")) {
328                 placements = jsonUtil.getJsonValue(response, "solutions.placementSolutions")
329                 if (isBlank(placements) || placements.equalsIgnoreCase("[]")) {
330                     String statusMessage = jsonUtil.getJsonValue(response, "statusMessage")
331                     if (isBlank(statusMessage)) {
332                         utils.log("DEBUG", "Error Occurred in Homing: OOF Async Callback Response does " +
333                                 "not contain placement solution.", isDebugEnabled)
334                         exceptionUtil.buildAndThrowWorkflowException(execution, 400,
335                                 "OOF Async Callback Response does not contain placement solution.")
336                     } else {
337                         utils.log("DEBUG", "Error Occurred in Homing: " + statusMessage, isDebugEnabled)
338                         exceptionUtil.buildAndThrowWorkflowException(execution, 400, statusMessage)
339                     }
340                 } else {
341                     return
342                 }
343             } else if (response.contains("error") || response.contains("Error") ) {
344                 String errorMessage = ""
345                 if (response.contains("policyException")) {
346                     String text = jsonUtil.getJsonValue(response, "requestError.policyException.text")
347                     errorMessage = "OOF Async Callback Response contains a Request Error Policy Exception: " + text
348                 } else if (response.contains("Unable to find any candidate for demand")) {
349                     errorMessage = "OOF Async Callback Response contains error: Unable to find any candidate for " +
350                             "demand *** Response: " + response.toString()
351                 } else if (response.contains("serviceException")) {
352                     String text = jsonUtil.getJsonValue(response, "requestError.serviceException.text")
353                     errorMessage = "OOF Async Callback Response contains a Request Error Service Exception: " + text
354                 } else {
355                     errorMessage = "OOF Async Callback Response contains a Request Error. Unable to determine the Request Error Exception."
356                 }
357                 utils.log("DEBUG", "Error Occurred in Homing: " + errorMessage, isDebugEnabled)
358                 exceptionUtil.buildAndThrowWorkflowException(execution, 400, errorMessage)
359
360             } else {
361                 utils.log("DEBUG", "Error Occurred in Homing: Received an Unknown Async Callback Response from OOF.", isDebugEnabled)
362                 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Received an Unknown Async Callback Response from OOF.")
363             }
364         }
365
366     }
367
368     /**
369      * This method creates candidates json for placement Demands.
370      *
371      * @param execution
372      * @param existingCandidates -
373      * @param excludedCandidates -
374      * @param requiredCandidates -
375      *
376      * @return candidatesJson - a JSON string with candidates
377      */
378     String createCandidateJson(ArrayList existingCandidates = null,
379                                ArrayList excludedCandidates = null,
380                                ArrayList requiredCandidates = null) {
381         def candidatesJson = ""
382         def type = ""
383         if (existingCandidates != null && existingCandidates != {}) {
384             sb = new StringBuilder()
385             sb.append(",\n" +
386                     "  \"existingCandidates\": [\n")
387             def existingCandidateJson = ""
388             existingCandidates.each { existingCandidate ->
389                 type = existingCandidate.get('identifierType')
390                 if (type == 'vimId') {
391                     def cloudOwner = existingCandidate.get('cloudOwner')
392                     def cloudRegionId = existingCandidate.get('identifiers')
393                     existingCandidateJson = "{\n" +
394                             "    \"identifierType\": \"vimId\",\n" +
395                             "    \"cloudOwner\": \"${cloudOwner}\",\n" +
396                             "    \"identifiers\": [\"${cloudRegionId}\"]\n" +
397                             "    },"
398                     sb.append(existingCandidateJson)
399                 }
400                 if (type == 'serviceInstanceId') {
401                     def serviceInstanceId = existingCandidate.get('identifiers')
402                     existingCandidateJson += "{\n" +
403                             "    \"identifierType\": \"serviceInstanceId\",\n" +
404                             "    \"identifiers\": [\"${serviceInstanceId}\"]\n" +
405                             "    },"
406                     sb.append(existingCandidateJson)
407                 }
408             }
409             if (existingCandidateJson != "") {
410                 sb.setLength(sb.length() - 1)
411                 candidatesJson = sb.append(",\n],")
412             }
413         }
414         if (excludedCandidates != null && excludedCandidates != {}) {
415             sb = new StringBuilder()
416             sb.append(",\n" +
417                     "  \"excludedCandidates\": [\n")
418             def excludedCandidateJson = ""
419             excludedCandidates.each { excludedCandidate ->
420                 type = excludedCandidate.get('identifierType')
421                 if (type == 'vimId') {
422                     def cloudOwner = excludedCandidate.get('cloudOwner')
423                     def cloudRegionId = excludedCandidate.get('identifiers')
424                     excludedCandidateJson = "{\n" +
425                             "    \"identifierType\": \"vimId\",\n" +
426                             "    \"cloudOwner\": \"${cloudOwner}\",\n" +
427                             "    \"identifiers\": [\"${cloudRegionId}\"]\n" +
428                             "    },"
429                     sb.append(excludedCandidateJson)
430                 }
431                 if (type == 'serviceInstanceId') {
432                     def serviceInstanceId = excludedCandidate.get('identifiers')
433                     excludedCandidateJson += "{\n" +
434                             "    \"identifierType\": \"serviceInstanceId\",\n" +
435                             "    \"identifiers\": [\"${serviceInstanceId}\"]\n" +
436                             "    },"
437                     sb.append(excludedCandidateJson)
438                 }
439             }
440             if (excludedCandidateJson != "") {
441                 sb.setLength(sb.length() - 1)
442                 candidatesJson = sb.append(",\n],")
443             }
444         }
445         if (requiredCandidates != null && requiredCandidates != {}) {
446             sb = new StringBuilder()
447             sb.append(",\n" +
448                     "  \"requiredCandidates\": [\n")
449             def requiredCandidatesJson = ""
450             requiredCandidates.each { requiredCandidate ->
451                 type = requiredCandidate.get('identifierType')
452                 if (type == 'vimId') {
453                     def cloudOwner = requiredCandidate.get('cloudOwner')
454                     def cloudRegionId = requiredCandidate.get('identifiers')
455                     requiredCandidatesJson = "{\n" +
456                             "    \"identifierType\": \"vimId\",\n" +
457                             "    \"cloudOwner\": \"${cloudOwner}\",\n" +
458                             "    \"identifiers\": [\"${cloudRegionId}\"]\n" +
459                             "    },"
460                     sb.append(requiredCandidatesJson)
461                 }
462                 if (type == 'serviceInstanceId') {
463                     def serviceInstanceId = requiredCandidate.get('identifiers')
464                     requiredCandidatesJson += "{\n" +
465                             "    \"identifierType\": \"serviceInstanceId\",\n" +
466                             "    \"identifiers\": [\"${serviceInstanceId}\"]\n" +
467                             "    },"
468                     sb.append(requiredCandidatesJson)
469                 }
470             }
471             if (requiredCandidatesJson != "") {
472                 sb.setLength(sb.length() - 1)
473                 candidatesJson = sb.append(",\n],")
474             }
475         }
476         if (candidatesJson != "") {candidatesJson = candidatesJson.substring(0, candidatesJson.length() - 1)}
477         return candidatesJson
478     }
479     /**
480      * This method creates a cloudsite in catalog database.
481      *
482      * @param CloudSite cloudSite
483      *
484      * @return void
485      */
486     Void createCloudSiteCatalogDb(CloudSite cloudSite, DelegateExecution execution) {
487
488         String endpoint = UrnPropertiesReader.getVariable("mso.catalog.db.spring.endpoint", execution)
489         String auth = UrnPropertiesReader.getVariable("mso.db.auth", execution)
490         String uri = "/cloudSite"
491
492         HttpHeaders headers = new HttpHeaders()
493
494         headers.set(HttpHeaders.AUTHORIZATION, auth)
495         headers.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON)
496         headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
497
498         UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(endpoint + uri)
499         HttpEntity<CloudSite> request = new HttpEntity<CloudSite>(cloudSite, headers)
500         RESTConfig config = new RESTConfig(endpoint + uri)
501         RESTClient client = new RESTClient(config).addAuthorizationHeader(auth).
502                 addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON).addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
503         APIResponse response = client.httpPost(request.getBody().toString())
504
505         int responseCode = response.getStatusCode()
506         logDebug("CatalogDB response code is: " + responseCode, isDebugEnabled)
507         String syncResponse = response.getResponseBodyAsString()
508         logDebug("CatalogDB response is: " + syncResponse, isDebugEnabled)
509
510         if(responseCode != 202){
511             exceptionUtil.buildAndThrowWorkflowException(execution, responseCode, "Received a Bad Sync Response from CatalogDB.")
512         }
513     }
514 }