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.workflow.service;
26 import java.io.FileOutputStream;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.OutputStream;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.HashMap;
33 import java.util.List;
35 import java.util.Map.Entry;
37 import javax.activation.DataHandler;
38 import javax.ws.rs.Consumes;
39 import javax.ws.rs.DELETE;
40 import javax.ws.rs.GET;
41 import javax.ws.rs.POST;
42 import javax.ws.rs.Path;
43 import javax.ws.rs.PathParam;
44 import javax.ws.rs.Produces;
45 import javax.ws.rs.core.Response;
46 import javax.ws.rs.ext.Provider;
48 import org.apache.cxf.jaxrs.ext.multipart.Attachment;
49 import org.apache.cxf.jaxrs.ext.multipart.Multipart;
50 import org.onap.so.db.catalog.beans.NetworkRecipe;
51 import org.onap.so.db.catalog.beans.NetworkResource;
52 import org.onap.so.db.catalog.beans.ServiceRecipe;
53 import org.onap.so.db.catalog.client.CatalogDbClient;
54 import org.onap.so.rest.catalog.beans.Service;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57 import org.springframework.beans.factory.annotation.Autowired;
58 import org.springframework.stereotype.Component;
59 import org.springframework.web.bind.annotation.CrossOrigin;
61 import com.fasterxml.jackson.databind.ObjectMapper;
63 import io.swagger.annotations.Api;
64 import io.swagger.annotations.ApiOperation;
65 import net.minidev.json.JSONObject;
66 import org.onap.so.db.catalog.beans.VnfRecipe;
67 import org.onap.so.db.catalog.beans.VnfResource;
71 * @version 1.0 Support SO workflow/script onboarding and recipe update
73 @Path("/hotmanagement")
74 @Api(value = "/hotmanage", description = "Provides support for the workflow hot onboarding and recipe update")
77 public class WorkflowOnboardingSupport extends ProcessEngineAwareService {
79 protected static final Logger logger = LoggerFactory.getLogger(WorkflowOnboardingSupport.class);
80 protected static final long DEFAULT_WAIT_TIME = 60000; // default wait time
81 private static final String SERVICE = "SERVICE";
82 private static final String NETWORK = "NETWORK";
83 private static final String VNF = "VNF";
86 private CatalogDbClient catalogDbClient;
89 * Get all service recipes.
94 @ApiOperation(value = "Get all service recipes", notes = "Get all service recipes")
95 @Path("/serviceRecipes")
96 public Response getServiceRecipes() {
97 List<ServiceRecipe> serviceRecipes = catalogDbClient.getServiceRecipes();
98 List<Service> services = catalogDbClient.getServices();
99 Map<String, String> idToName = new HashMap<String, String>();
100 for (Service service : services) {
101 idToName.put(service.getModelVersionId(), service.getModelName());
103 Map<String, String> flowToName = new HashMap<String, String>();
104 Map<String, List<String>> packages = getPackages();
105 for (Entry<String, List<String>> entry : packages.entrySet()) {
106 for (String flow : entry.getValue()) {
107 flowToName.put(flow, entry.getKey());
110 Map<String, List<Map<String, String>>> mapServiceRecipes = new HashMap<String, List<Map<String, String>>>();
111 List<Map<String, String>> recipeList = new ArrayList<Map<String, String>>();
112 for (ServiceRecipe serviceRecipe : serviceRecipes) {
113 Map<String, String> recipeObj = new HashMap<String, String>();
114 recipeObj.put("id", String.valueOf(serviceRecipe.getId()));
115 recipeObj.put("modelVersionId", serviceRecipe.getServiceModelUUID());
116 recipeObj.put("modelName", idToName.get(serviceRecipe.getServiceModelUUID()));
117 recipeObj.put("operation", serviceRecipe.getAction());
118 recipeObj.put("orchestrationPackageName", flowToName.get(serviceRecipe.getOrchestrationUri()));
119 recipeObj.put("orchestrationFlow", serviceRecipe.getOrchestrationUri());
120 recipeList.add(recipeObj);
122 mapServiceRecipes.put("serviceRecipes", recipeList);
123 String resp = JSONObject.toJSONString(mapServiceRecipes);
125 return Response.status(200).header("Access-Control-Allow-Origin", "*").entity(resp).build();
129 * Add new recipe for service
134 @SuppressWarnings("unchecked")
136 @Path("/serviceRecipes")
137 @ApiOperation(value = "Add a new service recipe", notes = "Add a new service recipe")
138 @Produces("application/json")
139 @Consumes("application/json")
140 public Response addServiceRecipDese(String request) {
141 Map<String, String> mapRecipeInfo;
142 ObjectMapper mapper = new ObjectMapper();
147 mapRecipeInfo = mapper.readValue(request, Map.class);
149 } catch (Exception e) {
150 logger.debug("Mapping of request to JSON object failed : ", e);
151 return Response.status(200).header("Access-Control-Allow-Origin", "*").build();
153 String nfRole = mapRecipeInfo.get("nfRole");
154 String type = mapRecipeInfo.get("modelType");
155 String modelVersionId = mapRecipeInfo.get("modelVersionId");
156 String action = mapRecipeInfo.get("operation");
157 String orchestrationFlow = "/mso/async/services/" + mapRecipeInfo.get("orchestrationFlow");
158 String modelName = mapRecipeInfo.get("modelName");
159 String description = action + " orchestration flow for template " + mapRecipeInfo.get("modelName");
161 String[] validTypes = { SERVICE, NETWORK, VNF };
163 if (org.springframework.util.StringUtils.isEmpty(type)
164 || !Arrays.asList(validTypes).contains(type.toUpperCase())) {
165 return Response.status(200).header("Access-Control-Allow-Origin", "*")
166 .entity("{\"errMsg\":\"type is invalid.\"}").build();
170 boolean isModelVersionExists = false;
171 Object[] conflictAndIdCheck;
173 if (type.equalsIgnoreCase(SERVICE)) {
174 isModelVersionExists = isServiceModelVersionIdExists(modelVersionId);
175 if (!isModelVersionExists) {
176 return Response.status(200).header("Access-Control-Allow-Origin", "*")
177 .entity("{\"errMsg\":\"The service template does not exist.\"}").build();
180 conflictAndIdCheck = isServiceActionConflict(modelVersionId, action);
181 if ((boolean) conflictAndIdCheck[0]) {
182 return Response.status(200).header("Access-Control-Allow-Origin", "*").entity(
183 "{\"errMsg\":\"The recipe for this action of the service template already exists.\"}")
186 assignedId = (int) conflictAndIdCheck[1] + 1;
187 ServiceRecipe serviceRecipe = new ServiceRecipe();
188 serviceRecipe.setId(assignedId);
189 serviceRecipe.setServiceModelUUID(modelVersionId);
190 serviceRecipe.setAction(action);
191 serviceRecipe.setOrchestrationUri(orchestrationFlow);
192 serviceRecipe.setRecipeTimeout(180);
193 serviceRecipe.setDescription(description);
194 catalogDbClient.postServiceRecipe(serviceRecipe);
195 } else if (type.equalsIgnoreCase(NETWORK)) {
197 isModelVersionExists = isNetworkVersionIdValid(modelVersionId);
198 if (!isModelVersionExists) {
199 return Response.status(200).header("Access-Control-Allow-Origin", "*")
200 .entity("{\"errMsg\":\"The network template does not exist.\"}").build();
203 conflictAndIdCheck = isNetworkActionConflict(modelVersionId, action);
204 if ((boolean) conflictAndIdCheck[0]) {
205 return Response.status(200).header("Access-Control-Allow-Origin", "*").entity(
206 "{\"errMsg\":\"The recipe for this action of the network template already exists.\"}")
210 assignedId = (int) conflictAndIdCheck[1] + 1;
211 NetworkRecipe nwrecipe = new NetworkRecipe();
212 nwrecipe.setId(assignedId);
213 nwrecipe.setModelName(modelName);
214 nwrecipe.setAction(action);
215 nwrecipe.setOrchestrationUri(orchestrationFlow);
216 nwrecipe.setDescription(description);
217 nwrecipe.setRecipeTimeout(180);
218 nwrecipe.setVersionStr(modelVersionId);
219 catalogDbClient.postNetworkRecipe(nwrecipe);
221 } else if (type.equalsIgnoreCase(VNF)) {
223 isModelVersionExists = isVnfVersionIdValid(modelVersionId);
224 if (!isModelVersionExists) {
225 return Response.status(200).header("Access-Control-Allow-Origin", "*")
226 .entity("{\"errMsg\":\"The Vnf template does not exist.\"}").build();
230 conflictAndIdCheck = isVfActionConflict(modelVersionId, action);
231 if ((boolean) conflictAndIdCheck[0]) {
232 return Response.status(200).header("Access-Control-Allow-Origin", "*")
233 .entity("{\"errMsg\":\"The recipe for this action of the vnf template already exists.\"}")
237 assignedId = (int) conflictAndIdCheck[1] + 1;
238 VnfRecipe vnfRecipe = new VnfRecipe();
239 vnfRecipe.setNfRole(nfRole);
240 vnfRecipe.setId(assignedId);
241 vnfRecipe.setAction(action);
242 vnfRecipe.setDescription(description);
243 vnfRecipe.setVersionStr(modelVersionId);
244 vnfRecipe.setOrchestrationUri(orchestrationFlow);
245 vnfRecipe.setRecipeTimeout(180);
246 catalogDbClient.postVnfRecipe(vnfRecipe);
250 mapRecipeInfo.put("id", String.valueOf(assignedId));
251 } catch (Exception e) {
252 logger.debug("WorkflowOnboardingSupport addServiceRecipDese error {} : ", e);
253 return Response.status(200).header("Access-Control-Allow-Origin", "*")
254 .entity("{\"errMsg\":\"Unable to process.\"}").build();
256 String resp = JSONObject.toJSONString(mapRecipeInfo);
257 return Response.status(201).header("Access-Control-Allow-Origin", "*").entity(resp).build();
260 private boolean isServiceModelVersionIdExists(String modelVersionId) {
261 List<Service> services = catalogDbClient.getServices();
262 boolean isExists = false;
263 for(Service service: services) {
264 if(service.getModelVersionId().equals(modelVersionId)){
272 private Object[] isServiceActionConflict(String modelVersionId,String action) {
273 List<ServiceRecipe> serviceRecipes = catalogDbClient.getServiceRecipes();
274 boolean isConflict = false;
275 Object[] data= new Object[2];
276 int maxId = serviceRecipes.get(0)!=null? serviceRecipes.get(0).getId(): 1;
277 for (ServiceRecipe recipe : serviceRecipes) {
278 maxId = recipe.getId() > maxId ? recipe.getId() : maxId;
279 if (recipe.getServiceModelUUID().equals(modelVersionId)
280 && recipe.getAction().equals(action)) {
289 private Object[] isNetworkActionConflict(String modelVersionId,String action) {
290 List<NetworkRecipe> recipes = catalogDbClient.getNetworkRecipes();
291 boolean isConflict = false;
292 Object[] data= new Object[2];
293 int maxId = recipes.get(0)!=null ? recipes.get(0).getId() : 1;
294 for (NetworkRecipe recipe : recipes) {
295 maxId = recipe.getId() > maxId ? recipe.getId() : maxId;
296 if (recipe.getVersionStr().equals(modelVersionId)
297 && recipe.getAction().equals(action)) {
308 private Object[] isVfActionConflict(String modelVersionId,String action) {
309 List<VnfRecipe> vnfRecipes = catalogDbClient.getVnfRecipes();
310 boolean isConflict = false;
311 Object[] data= new Object[2];
312 int maxId = vnfRecipes.get(0) !=null ? vnfRecipes.get(0).getId() : 1;
313 for (VnfRecipe recipe : vnfRecipes) {
314 maxId = recipe.getId() > maxId ? recipe.getId() : maxId;
315 if (recipe.getVersionStr().equals(modelVersionId)
316 && recipe.getAction().equals(action)) {
327 private boolean isNetworkVersionIdValid(String modelVersionId) {
328 List<NetworkResource> networkResources = catalogDbClient.getNetworkResources();
329 boolean isExists = false;
330 for(NetworkResource networkResource: networkResources) {
331 if(networkResource.getModelVersion().equals(modelVersionId)){
339 private boolean isVnfVersionIdValid(String modelVersionId) {
340 List<VnfResource> vnfResources = catalogDbClient.getVnfResources();
341 boolean isExists = false;
342 for(VnfResource vnfResource: vnfResources) {
343 if(vnfResource.getModelVersion().equals(modelVersionId)){
352 * delete service recipe
354 * @param request the body of the request
358 @Path("/serviceRecipes/{id}")
359 @ApiOperation(value = "delete a service recipe", notes = "delete a service recipe")
360 @Produces("application/json")
361 @Consumes("application/json")
362 public Response delServiceRecipe(String request, @PathParam("id") String id) {
363 catalogDbClient.deleteServiceRecipe(id);
364 return Response.status(200).header("Access-Control-Allow-Origin", "*").build();
368 * Get service templates
373 @ApiOperation(value = "query all service templates", notes = "query all service templates")
374 @Path("/serviceTemplates")
375 public Response getServices() {
376 List<Service> services = catalogDbClient.getServices();
377 Map<String, List<Map<String, String>>> mapServices = new HashMap<String, List<Map<String, String>>>();
378 List<Map<String, String>> serviceList = new ArrayList<Map<String, String>>();
379 for (Service service : services) {
380 Map<String, String> serviceObj = new HashMap<String, String>();
381 serviceObj.put("modelInvariantId", service.getModelInvariantId());
382 serviceObj.put("modelVersionId", service.getModelVersionId());
383 serviceObj.put("modelName", service.getModelName());
384 serviceList.add(serviceObj);
386 mapServices.put("services", serviceList);
387 String resp = JSONObject.toJSONString(mapServices);
388 return Response.status(200).header("Access-Control-Allow-Origin", "*").entity(resp).build();
392 * Get all workflow packages including all bpmn infos.
397 @ApiOperation(value = "Get all workflow packages", notes = "Get all workflow packages")
398 @Path("/workflowPackages")
399 public Response getWorkflowPackages() {
400 Map<String, List<String>> packages = getPackages();
401 List<Map<String, Object>> packageList = new ArrayList<Map<String, Object>>();
402 for (Entry<String, List<String>> entry : packages.entrySet()) {
403 Map<String, Object> packageInfo = new HashMap<String, Object>();
404 packageInfo.put("packageName", entry.getKey());
405 packageInfo.put("orchestrationFlows", entry.getValue());
406 packageList.add(packageInfo);
408 Map<String, List<Map<String, Object>>> mapPackages = new HashMap<String, List<Map<String, Object>>>();
409 mapPackages.put("workflowPackages", packageList);
410 String resp = JSONObject.toJSONString(mapPackages);
411 return Response.status(200).header("Access-Control-Allow-Origin", "*").entity(resp).build();
415 * Get the package info from the local system.
419 private Map<String, List<String>> getPackages() {
420 String pkgDir = "/camunda/webapps/";
421 File packageFile = new File(pkgDir);
422 String[] packageList = packageFile.list();
423 Map<String, List<String>> mapPackage = new HashMap<String, List<String>>();
424 for (String strPkgFileName : packageList) {
425 if (strPkgFileName.endsWith(".war")) {
426 String fileName = strPkgFileName.substring(0, strPkgFileName.length() - ".war".length());
427 String flowsDir = pkgDir + fileName + "/WEB-INF/classes/";
428 if ("mso".equals(fileName)) {
429 flowsDir = pkgDir + fileName + "/WEB-INF/classes/process/";
431 File flowFile = new File(flowsDir);
432 if (!flowFile.isDirectory()) {
435 String[] flowFileNames = flowFile.list();
436 List<String> orchestrationFlows = new ArrayList<String>();
437 for (String flowFileName : flowFileNames) {
438 if (flowFileName.endsWith(".bpmn")) {
439 orchestrationFlows.add(flowFileName.substring(0, flowFileName.length() - ".bpmn".length()));
442 mapPackage.put(fileName, orchestrationFlows);
449 * delete workflow package
451 * @param request the body of the request
455 @Path("/workflowPackages/{packageName}")
456 @ApiOperation(value = "delete a service recipe", notes = "delete a service recipe")
457 @Produces("application/json")
458 @Consumes("application/json")
459 public Response deleteWorkflowPackage(@PathParam("packageName") String packageName) {
460 String pkgDir = "/camunda/webapps/";
461 File packageFile = new File(pkgDir + packageName + ".war");
462 if (packageFile.isFile()) {
463 packageFile.delete();
465 return Response.status(200).header("Access-Control-Allow-Origin", "*").build();
469 * upload a workflow package to the server
471 * @param uploadInputStream upload stream
476 @Path("/workflowPackages/onboard")
477 @Consumes("multipart/form-data")
478 @Produces("application/json")
479 @ApiOperation(value = "Add a new service recipe", notes = "Add a new service recipe")
480 public Response onboardWorkflowPackage(@Multipart(value = "file") Attachment file) {
481 String msg = "Upload package finished.";
482 boolean isSuccess = false;
483 DataHandler dh = file.getDataHandler();
484 String fileName = "/camunda/webapps/" + dh.getName();
485 File saveFile = new File(fileName);
486 if (saveFile.isFile()) {
487 msg = "Upload package failed: The Package already exist";
490 isSuccess = saveFile(dh.getInputStream(), fileName);
492 msg = "Upload package failed: write file failed.";
494 } catch (IOException e) {
495 msg = "Upload package failed: Onboard File Exception!";
498 Map<String, String> result = new HashMap<String, String>();
499 result.put("result", String.valueOf(isSuccess));
500 result.put("message", msg);
501 String resp = JSONObject.toJSONString(result);
502 return Response.status(200).header("Access-Control-Allow-Origin", "*").entity(resp).build();
506 * Write the stream to file
508 * @param uploadStream the stream need to writh
509 * @param file the destination file
511 private boolean saveFile(InputStream uploadStream, String file) {
513 OutputStream outStream = new FileOutputStream(new File(file));
515 byte[] bytes = new byte[1024];
516 while ((read = uploadStream.read(bytes)) != -1) {
517 outStream.write(bytes, 0, read);
521 } catch (IOException e) {
522 logger.info("write stream to file failed");
528 * Get all network recipes.
533 @ApiOperation(value = "Get all network recipes", notes = "Get all network recipes")
534 @Path("/networkRecipes")
535 public Response getNetworkRecipes() {
536 List<NetworkRecipe> networkRecipes = catalogDbClient.getNetworkRecipes();
537 Map<String, List<Map<String, String>>> mapNetworkRecipes = new HashMap<String, List<Map<String, String>>>();
538 List<Map<String, String>> recipeList = new ArrayList<Map<String, String>>();
539 for (NetworkRecipe networkRecipe : networkRecipes) {
540 Map<String, String> recipeObj = new HashMap<String, String>();
541 recipeObj.put("id", String.valueOf(networkRecipe.getId()));
542 recipeObj.put("paramXsd", String.valueOf(networkRecipe.getParamXsd()));
543 recipeObj.put("modelName", String.valueOf(networkRecipe.getModelName()));
544 recipeObj.put("description", String.valueOf(networkRecipe.getDescription()));
545 recipeObj.put("action", String.valueOf(networkRecipe.getAction()));
546 recipeObj.put("orchestrationUri", String.valueOf(networkRecipe.getOrchestrationUri()));
547 recipeObj.put("recipeTimeout", String.valueOf(networkRecipe.getRecipeTimeout()));
548 recipeObj.put("versionStr", String.valueOf(networkRecipe.getVersionStr()));
549 recipeObj.put("serviceType", String.valueOf(networkRecipe.getServiceType()));
550 recipeObj.put("created", String.valueOf(networkRecipe.getCreated()));
551 recipeList.add(recipeObj);
553 mapNetworkRecipes.put("networkRecipes", recipeList);
554 String resp = JSONObject.toJSONString(mapNetworkRecipes);
556 return Response.status(200).header("Access-Control-Allow-Origin", "*").entity(resp).build();
560 * Get all network recipes.
565 @ApiOperation(value = "Get all network recipes", notes = "Get all network recipes")
566 @Path("/getServiceRecipes")
567 public Response getServiceRecipesList() {
568 List<ServiceRecipe> serviceRecipes = catalogDbClient.getServiceRecipes();
569 Map<String, List<Map<String, String>>> mapNetworkRecipes = new HashMap<String, List<Map<String, String>>>();
570 List<Map<String, String>> recipeList = new ArrayList<Map<String, String>>();
571 for (ServiceRecipe serviceRecipe : serviceRecipes) {
572 Map<String, String> recipeObj = new HashMap<String, String>();
573 recipeObj.put("id", String.valueOf(serviceRecipe.getId()));
574 recipeObj.put("paramXsd", String.valueOf(serviceRecipe.getParamXsd()));
575 recipeObj.put("serviceModelUUID", String.valueOf(serviceRecipe.getServiceModelUUID()));
576 recipeObj.put("description", String.valueOf(serviceRecipe.getDescription()));
577 recipeObj.put("action", String.valueOf(serviceRecipe.getAction()));
578 recipeObj.put("orchestrationUri", String.valueOf(serviceRecipe.getOrchestrationUri()));
579 recipeObj.put("recipeTimeout", String.valueOf(serviceRecipe.getRecipeTimeout()));
580 recipeObj.put("serviceTimeoutInterim", String.valueOf(serviceRecipe.getServiceTimeoutInterim()));
581 recipeObj.put("created", String.valueOf(serviceRecipe.getCreated()));
582 recipeList.add(recipeObj);
584 mapNetworkRecipes.put("serviceRecipes", recipeList);
585 String resp = JSONObject.toJSONString(mapNetworkRecipes);
587 return Response.status(200).header("Access-Control-Allow-Origin", "*").entity(resp).build();
591 * Get all vnf recipes.
596 @ApiOperation(value = "Get all vnf recipes", notes = "Get all vnf recipes")
598 public Response getVNFRecipes() {
599 List<VnfRecipe> vnfRecipes = catalogDbClient.getVnfRecipes();
600 Map<String, List<Map<String, String>>> mapVnfRecipes = new HashMap<String, List<Map<String, String>>>();
601 List<Map<String, String>> recipeList = new ArrayList<Map<String, String>>();
602 for (VnfRecipe vnfRecipe : vnfRecipes) {
603 Map<String, String> recipeObj = new HashMap<String, String>();
604 recipeObj.put("id", String.valueOf(vnfRecipe.getId()));
605 recipeObj.put("nfRole", String.valueOf(vnfRecipe.getNfRole()));
606 recipeObj.put("paramXsd", String.valueOf(vnfRecipe.getParamXsd()));
607 recipeObj.put("vfModuleId", String.valueOf(vnfRecipe.getVfModuleId()));
608 recipeObj.put("description", String.valueOf(vnfRecipe.getDescription()));
609 recipeObj.put("action", String.valueOf(vnfRecipe.getAction()));
610 recipeObj.put("orchestrationUri", String.valueOf(vnfRecipe.getOrchestrationUri()));
611 recipeObj.put("recipeTimeout", String.valueOf(vnfRecipe.getRecipeTimeout()));
612 recipeObj.put("versionStr", String.valueOf(vnfRecipe.getVersionStr()));
613 recipeObj.put("serviceType", String.valueOf(vnfRecipe.getServiceType()));
614 recipeObj.put("created", String.valueOf(vnfRecipe.getCreated()));
615 recipeList.add(recipeObj);
617 mapVnfRecipes.put("vnfRecipes", recipeList);
618 String resp = JSONObject.toJSONString(mapVnfRecipes);
620 return Response.status(200).header("Access-Control-Allow-Origin", "*").entity(resp).build();