package org.onap.sdc.dcae.composition.controller; import org.json.JSONArray; import org.json.JSONException; import org.onap.sdc.common.onaplog.Enums.LogLevel; import org.onap.sdc.dcae.composition.impl.CompositionBusinessLogic; import org.onap.sdc.dcae.composition.restmodels.MessageResponse; import org.onap.sdc.dcae.composition.restmodels.ReferenceUUID; import org.onap.sdc.dcae.composition.restmodels.sdc.Artifact; import org.onap.sdc.dcae.composition.restmodels.sdc.Asset; import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceDetailed; import org.onap.sdc.dcae.catalog.Catalog; import org.onap.sdc.dcae.catalog.Catalog.*; import org.onap.sdc.dcae.catalog.engine.*; import org.onap.sdc.dcae.composition.util.DcaeBeConstants; import org.onap.sdc.dcae.enums.LifecycleOperationType; import org.onap.sdc.dcae.errormng.ActionStatus; import org.onap.sdc.dcae.errormng.ErrConfMgr; import org.onap.sdc.dcae.errormng.ErrConfMgr.ApiType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.context.request.async.DeferredResult; import javax.annotation.PostConstruct; import java.net.URI; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; @RestController @EnableAutoConfiguration @CrossOrigin public class CompositionController extends BaseController { @Autowired private CatalogController catalogController; @Autowired private CompositionBusinessLogic compositionBusinessLogic; @PostConstruct public void init() { catalogController.setDefaultCatalog(URI.create(systemProperties.getProperties().getProperty(DcaeBeConstants.Config.ASDC_CATALOG_URL))); } @RequestMapping(value = { "/utils/clone/{assetType}/{sourceId}/{targetId}" }, method = { RequestMethod.GET }, produces = { "application/json" }) public ResponseEntity clone(@RequestHeader("USER_ID") String userId, @PathVariable("assetType") String theAssetType, @PathVariable("sourceId") String theSourceId, @PathVariable("targetId") String theTargetId, @ModelAttribute("requestId") String requestId) { MessageResponse response = new MessageResponse(); try { // fetch the source and assert it is a vfcmt containing clone worthy artifacts (composition + rules) ResourceDetailed sourceVfcmt = baseBusinessLogic.getSdcRestClient().getResource(theSourceId, requestId); checkVfcmtType(sourceVfcmt); List artifactsToClone = CollectionUtils.isEmpty(sourceVfcmt.getArtifacts()) ? null : sourceVfcmt.getArtifacts().stream().filter(p -> DcaeBeConstants.Composition.fileNames.COMPOSITION_YML.equals(p.getArtifactName()) || p.getArtifactName().endsWith(DcaeBeConstants.Composition.fileNames.MAPPING_RULE_POSTFIX)) .collect(Collectors.toList()); if (CollectionUtils.isEmpty(artifactsToClone)) { response.setSuccessResponse("Nothing to clone"); return new ResponseEntity<>(response, HttpStatus.NO_CONTENT); } // fetch the target ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(theTargetId, requestId); debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), vfcmt.toString()); checkVfcmtType(vfcmt); checkUserIfResourceCheckedOut(userId, vfcmt); boolean isTargetNeed2Checkout = isNeedToCheckOut(vfcmt.getLifecycleState()); if (isTargetNeed2Checkout) { ResourceDetailed targetVfcmt = baseBusinessLogic.getSdcRestClient().changeResourceLifecycleState(userId, theTargetId, LifecycleOperationType.CHECKOUT.name(), "checking out VFCMT before clone", requestId); if (null == targetVfcmt) { return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.GENERAL_ERROR); } theTargetId = targetVfcmt.getUuid(); debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "New targetVfcmt (for artifact clone) after checkoutVfcmt is: {}", theTargetId); } Map currentArtifacts = CollectionUtils.isEmpty(vfcmt.getArtifacts()) ? new HashMap<>() : vfcmt.getArtifacts().stream().collect(Collectors.toMap(Artifact::getArtifactName, Function.identity())); //TODO target VFCMT rule artifacts should be removed for (Artifact artifactToClone : artifactsToClone) { String payload = baseBusinessLogic.getSdcRestClient().getResourceArtifact(theSourceId, artifactToClone.getArtifactUUID(), requestId); baseBusinessLogic.cloneArtifactToTarget(userId, theTargetId, payload, artifactToClone, currentArtifacts.get(artifactToClone.getArtifactName()), requestId); } baseBusinessLogic.getSdcRestClient().changeResourceLifecycleState(userId, theTargetId, LifecycleOperationType.CHECKIN.name(), "check in VFCMT after clone", requestId); debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Cloning {} from {} has finished successfully", theSourceId, theTargetId); response.setSuccessResponse("Clone VFCMT complete"); return new ResponseEntity<>(response, HttpStatus.OK); } catch (Exception e) { return handleException(e, ApiType.CLONE_VFCMT); } } @RequestMapping(value = "/elements", method = { RequestMethod.POST, RequestMethod.GET }, produces = "application/json") public DeferredResult items(@RequestBody(required = false) ItemsRequest theRequest) { final ItemsRequest request = (theRequest == null) ? ItemsRequest.EMPTY_REQUEST : theRequest; Catalog catalog = catalogController.getCatalog(request.getCatalog()); DeferredResult result = new DeferredResult(request.getTimeout()); catalog.rootsByLabel(request.getStartingLabel()).setHandler(catalogController.new CatalogHandler(request, result) { public CatalogResponse handleData(Folders theFolders) { JSONArray ja = new JSONArray(); if (theFolders != null) { for (Folder folder : theFolders) { ja.put(catalogController.patchData(catalog, folder.data())); } } CatalogResponse response = new CatalogResponse(this.request); try { response.data().put("elements", ja); } catch (JSONException e) { errLogger.log(LogLevel.ERROR, this.getClass().getName(), "JSONException putting json elements to response {}", e); } return response; } }); return result; } @RequestMapping(value = "/{theItemId}/elements", method = { RequestMethod.POST, RequestMethod.GET }, produces = "application/json") public DeferredResult items(@RequestBody(required = false) ItemsRequest theRequest, @PathVariable String theItemId) { final ItemsRequest request = (theRequest == null) ? ItemsRequest.EMPTY_REQUEST : theRequest; Catalog catalog = catalogController.getCatalog(request.getCatalog()); DeferredResult result = new DeferredResult(request.getTimeout()); catalog // .fetchFolderByItemId(theItemId) .folder(theItemId).withParts().withPartAnnotations().withItems().withItemAnnotations().withItemModels().execute().setHandler(catalogController.new CatalogHandler(request, result) { public CatalogResponse handleData(Folder theFolder) { CatalogResponse response = new CatalogResponse(this.request); if (theFolder == null) { return response; } try { Elements folders = theFolder.elements("parts", Folders.class); if (folders != null) { for (Object folder : folders) { catalogController.patchData(catalog, ((Element) folder).data()); // lots of ephemere proxies created here .. Elements annotations = ((Element) folder).elements("annotations", Annotations.class); if (annotations != null) { for (Object a : annotations) { catalogController.patchData(catalog, ((Annotation) a).data()); } } } } Elements items = theFolder.elements("items", Items.class); if (items != null) { for (Object i : items) { catalogController.patchData(catalog, ((Element) i).data()); // lots of ephemere proxies created here .. Elements annotations = ((Element) i).elements("annotations", Annotations.class); if (annotations != null) { for (Object a : annotations) { catalogController.patchData(catalog, ((Annotation) a).data()); } } } } } catch (Exception x) { errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Exception processing catalog {}", x); return new CatalogError(this.request, "", x); } try { response.data().put("element", theFolder.data()); } catch (JSONException e) { errLogger.log(LogLevel.ERROR, this.getClass().getName(), "JSONException putting element to response {}", e); } return response; } }); return result; } @RequestMapping(value = "/{theItemId}/model", method = { RequestMethod.POST, RequestMethod.GET }, produces = "application/json") public DeferredResult model(@RequestBody(required = false) ElementRequest theRequest, @PathVariable String theItemId) { final ElementRequest request = (theRequest == null) ? ElementRequest.EMPTY_REQUEST : theRequest; Catalog catalog = catalogController.getCatalog(request.getCatalog()); DeferredResult result = new DeferredResult<>(request.getTimeout()); catalog.item(theItemId).withModels().execute().setHandler(catalogController.new CatalogHandler(request, result) { public CatalogResponse handleData(Item theItem) { if (theItem == null) { return new CatalogError(this.request, "No such item"); } Templates models = null; try { models = (Templates) theItem.elements("models", Templates.class); if (models == null || models.isEmpty()) { return new CatalogError(this.request, "Item has no models"); } if (models.size() > 1) { return new CatalogError(this.request, "Item has more than one model !?"); } catalog.template(models.get(0).id()).withInputs().withOutputs().withNodes().withNodeProperties().withNodePropertiesAssignments().withNodeRequirements().withNodeCapabilities().withNodeCapabilityProperties() .withNodeCapabilityPropertyAssignments().withPolicies().withPolicyProperties().withPolicyPropertiesAssignments().execute().setHandler(catalogController.new CatalogHandler