1 package org.onap.sdc.dcae.composition.controller;
3 import org.json.JSONArray;
4 import org.json.JSONException;
5 import org.onap.sdc.common.onaplog.Enums.LogLevel;
6 import org.onap.sdc.dcae.composition.restmodels.MessageResponse;
7 import org.onap.sdc.dcae.composition.restmodels.sdc.Artifact;
8 import org.onap.sdc.dcae.composition.restmodels.sdc.Asset;
9 import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceDetailed;
10 import org.onap.sdc.dcae.catalog.Catalog;
11 import org.onap.sdc.dcae.catalog.Catalog.*;
12 import org.onap.sdc.dcae.catalog.engine.*;
13 import org.onap.sdc.dcae.composition.util.DcaeBeConstants;
14 import org.onap.sdc.dcae.enums.ArtifactType;
15 import org.onap.sdc.dcae.enums.LifecycleOperationType;
16 import org.onap.sdc.dcae.errormng.ActionStatus;
17 import org.onap.sdc.dcae.errormng.ErrConfMgr;
18 import org.onap.sdc.dcae.errormng.ErrConfMgr.ApiType;
19 import org.onap.sdc.dcae.utils.SdcRestClientUtils;
20 import org.springframework.beans.factory.annotation.Autowired;
21 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
22 import org.springframework.http.HttpStatus;
23 import org.springframework.http.ResponseEntity;
24 import org.springframework.util.Base64Utils;
25 import org.springframework.util.CollectionUtils;
26 import org.springframework.web.bind.annotation.*;
27 import org.springframework.web.context.request.async.DeferredResult;
29 import javax.annotation.PostConstruct;
31 import java.util.HashMap;
32 import java.util.List;
34 import java.util.function.Function;
35 import java.util.stream.Collectors;
38 @EnableAutoConfiguration
40 public class CompositionController extends BaseController{
43 private CatalogController catalogController;
47 catalogController.setDefaultCatalog(URI.create(systemProperties.getProperties().getProperty(DcaeBeConstants.Config.ASDC_CATALOG_URL)));
50 @RequestMapping(value = { "/utils/clone/{assetType}/{sourceId}/{targetId}" }, method = {RequestMethod.GET }, produces = { "application/json" })
51 public ResponseEntity clone(@RequestHeader("USER_ID") String userId, @PathVariable("assetType") String theAssetType, @PathVariable("sourceId") String theSourceId, @PathVariable("targetId") String theTargetId,
52 @ModelAttribute("requestId") String requestId) {
53 MessageResponse response = new MessageResponse();
56 // fetch the source and assert it is a vfcmt containing clone worthy artifacts (composition + rules)
57 ResourceDetailed sourceVfcmt = baseBusinessLogic.getSdcRestClient().getResource(theSourceId, requestId);
58 checkVfcmtType(sourceVfcmt);
59 List<Artifact> artifactsToClone = CollectionUtils.isEmpty(sourceVfcmt.getArtifacts()) ? null : sourceVfcmt.getArtifacts().stream()
60 .filter(p -> DcaeBeConstants.Composition.fileNames.COMPOSITION_YML.equals(p.getArtifactName()) || p.getArtifactName().endsWith(DcaeBeConstants.Composition.fileNames.MAPPING_RULE_POSTFIX))
61 .collect(Collectors.toList());
62 if(CollectionUtils.isEmpty(artifactsToClone)) {
63 response.setSuccessResponse("Nothing to clone");
64 return new ResponseEntity<>(response ,HttpStatus.NO_CONTENT);
68 ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(theTargetId, requestId);
69 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), vfcmt.toString());
70 checkVfcmtType(vfcmt);
71 checkUserIfResourceCheckedOut(userId, vfcmt);
72 boolean isTargetNeed2Checkout = isNeedToCheckOut(vfcmt.getLifecycleState());
73 if (isTargetNeed2Checkout) {
74 ResourceDetailed targetVfcmt = baseBusinessLogic.getSdcRestClient().changeResourceLifecycleState(userId, theTargetId, LifecycleOperationType.CHECKOUT.name(), "checking out VFCMT before clone", requestId);
75 if(null == targetVfcmt){
76 return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.GENERAL_ERROR);
78 theTargetId = targetVfcmt.getUuid();
79 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "New targetVfcmt (for artifact clone) after checkout is: {}", theTargetId);
82 Map<String, Artifact> currentArtifacts = CollectionUtils.isEmpty(vfcmt.getArtifacts()) ? new HashMap<>() : vfcmt.getArtifacts().stream()
83 .collect(Collectors.toMap(Artifact::getArtifactName, Function.identity()));
85 //TODO target VFCMT rule artifacts should be removed
86 for(Artifact artifactToClone : artifactsToClone) {
87 String payload = baseBusinessLogic.getSdcRestClient().getResourceArtifact(theSourceId, artifactToClone.getArtifactUUID(), requestId);
88 baseBusinessLogic.cloneArtifactToTarget(userId, theTargetId, payload, artifactToClone, currentArtifacts.get(artifactToClone.getArtifactName()), requestId);
91 baseBusinessLogic.getSdcRestClient().changeResourceLifecycleState(userId, theTargetId, LifecycleOperationType.CHECKIN.name(), "check in VFCMT after clone", requestId);
92 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Cloning {} from {} has finished successfully", theSourceId, theTargetId);
93 response.setSuccessResponse("Clone VFCMT complete");
94 return new ResponseEntity<>(response, HttpStatus.OK);
95 } catch (Exception e) {
96 return handleException(e, ApiType.CLONE_VFCMT);
100 @RequestMapping(value = "/elements", method = { RequestMethod.POST, RequestMethod.GET }, produces = "application/json")
101 public DeferredResult<CatalogResponse> items(@RequestBody(required = false) ItemsRequest theRequest) {
103 final ItemsRequest request = (theRequest == null) ? ItemsRequest.EMPTY_REQUEST : theRequest;
105 Catalog catalog = catalogController.getCatalog(request.getCatalog());
106 DeferredResult<CatalogResponse> result = new DeferredResult<CatalogResponse>(request.getTimeout());
108 catalog.rootsByLabel(request.getStartingLabel())
109 .setHandler(catalogController.new CatalogHandler<Folders>(request, result) {
110 public CatalogResponse handleData(Folders theFolders) {
111 JSONArray ja = new JSONArray();
112 if (theFolders != null) {
113 for (Folder folder : theFolders) {
114 ja.put(catalogController.patchData(catalog, folder.data()));
117 CatalogResponse response = new CatalogResponse(this.request);
119 response.data().put("elements", ja);
120 } catch (JSONException e) {
121 errLogger.log(LogLevel.ERROR, this.getClass().getName(), "JSONException putting json elements to response {}", e);
129 @RequestMapping(value = "/{theItemId}/elements", method = { RequestMethod.POST, RequestMethod.GET }, produces = "application/json")
130 public DeferredResult<CatalogResponse> items(@RequestBody(required = false) ItemsRequest theRequest, @PathVariable String theItemId) {
132 final ItemsRequest request = (theRequest == null) ? ItemsRequest.EMPTY_REQUEST : theRequest;
134 Catalog catalog = catalogController.getCatalog(request.getCatalog());
135 DeferredResult<CatalogResponse> result = new DeferredResult<CatalogResponse>(request.getTimeout());
138 // .fetchFolderByItemId(theItemId)
139 .folder(theItemId).withParts().withPartAnnotations().withItems().withItemAnnotations().withItemModels()
140 .execute().setHandler(catalogController.new CatalogHandler<Folder>(request, result) {
141 public CatalogResponse handleData(Folder theFolder) {
142 CatalogResponse response = new CatalogResponse(this.request);
143 if (theFolder == null) {
148 Elements folders = theFolder.elements("parts", Folders.class);
149 if (folders != null) {
150 for (Object folder : folders) {
151 catalogController.patchData(catalog, ((Element) folder).data());
152 // lots of ephemere proxies created here ..
153 Elements annotations = ((Element) folder).elements("annotations",
155 if (annotations != null) {
156 for (Object a : annotations) {
157 catalogController.patchData(catalog, ((Annotation) a).data());
162 Elements items = theFolder.elements("items", Items.class);
164 for (Object i : items) {
165 catalogController.patchData(catalog, ((Element) i).data());
166 // lots of ephemere proxies created here ..
167 Elements annotations = ((Element) i).elements("annotations", Annotations.class);
168 if (annotations != null) {
169 for (Object a : annotations) {
170 catalogController.patchData(catalog, ((Annotation) a).data());
175 } catch (Exception x) {
176 errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Exception processing catalog {}", x);
177 return new CatalogError(this.request, "", x);
181 response.data().put("element", theFolder.data());
182 } catch (JSONException e) {
183 errLogger.log(LogLevel.ERROR, this.getClass().getName(), "JSONException putting element to response {}", e);
192 @RequestMapping(value = "/{theItemId}/model", method = { RequestMethod.POST,RequestMethod.GET }, produces = "application/json")
193 public DeferredResult model(@RequestBody(required = false) ElementRequest theRequest,
194 @PathVariable String theItemId) {
195 final ElementRequest request = (theRequest == null) ? ElementRequest.EMPTY_REQUEST : theRequest;
197 Catalog catalog = catalogController.getCatalog(request.getCatalog());
198 DeferredResult<CatalogResponse> result = new DeferredResult<>(request.getTimeout());
201 .item(theItemId).withModels().execute()
202 .setHandler(catalogController.new CatalogHandler<Item>(request, result) {
203 public CatalogResponse handleData(Item theItem) {
204 if (theItem == null) {
205 return new CatalogError(this.request, "No such item");
207 Templates models = null;
209 models = (Templates) theItem.elements("models", Templates.class);
210 if (models == null || models.isEmpty()) {
211 return new CatalogError(this.request, "Item has no models");
213 if (models.size() > 1) {
214 return new CatalogError(this.request, "Item has more than one model !?");
216 catalog.template(models.get(0).id()).withInputs().withOutputs().withNodes()
217 .withNodeProperties().withNodePropertiesAssignments().withNodeRequirements()
218 .withNodeCapabilities().withNodeCapabilityProperties()
219 .withNodeCapabilityPropertyAssignments().withPolicies().withPolicyProperties()
220 .withPolicyPropertiesAssignments().execute().setHandler(
221 catalogController.new CatalogHandler<Template>(this.request, this.result) {
222 public CatalogResponse handleData(Template theTemplate) {
223 CatalogResponse response = new CatalogResponse(this.request);
224 if (theTemplate != null) {
226 response.data().put("model", catalogController
227 .patchData(catalog, theTemplate.data()));
228 } catch (JSONException e) {
229 errLogger.log(LogLevel.ERROR, this.getClass().getName(), "JSONException putting model to response {}", e);
235 } catch (Exception e) {
236 handleException(e, ApiType.GET_MODEL, models.get(0).name());
245 @RequestMapping(value = "/{theItemId}/type/{theTypeName}", method = { RequestMethod.POST, RequestMethod.GET }, produces = "application/json")
246 public DeferredResult<CatalogResponse> model(@RequestBody(required = false) ElementRequest theRequest, @PathVariable String theItemId, @PathVariable String theTypeName) {
247 final ElementRequest request = (theRequest == null) ? ElementRequest.EMPTY_REQUEST : theRequest;
249 Catalog catalog = catalogController.getCatalog(request.getCatalog());
250 DeferredResult<CatalogResponse> result = new DeferredResult<CatalogResponse>(request.getTimeout());
252 catalog.type(theItemId, theTypeName).withHierarchy().withCapabilities().withRequirements().execute()
253 .setHandler(catalogController.new CatalogHandler<Type>(request, result) {
254 public CatalogResponse handleData(Type theType) {
255 CatalogResponse response = new CatalogResponse(this.request);
256 if (theType != null) {
258 response.data().put("type", catalogController.patchData(catalog, theType.data()));
259 } catch (JSONException e) {
260 errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Exception processing catalog {}", e);
270 @RequestMapping(value = { "/getComposition/{vfcmtUuid}" }, method = { RequestMethod.GET }, produces = {"application/json" })
271 public ResponseEntity getComposition(@PathVariable("vfcmtUuid") String vfcmtUuid, @ModelAttribute("requestId") String requestId) {
272 MessageResponse response = new MessageResponse();
274 ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(vfcmtUuid, requestId);
275 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), vfcmt.toString());
276 checkVfcmtType(vfcmt);
278 Artifact compositionArtifact = CollectionUtils.isEmpty(vfcmt.getArtifacts()) ? null : vfcmt.getArtifacts().stream().filter(a -> DcaeBeConstants.Composition.fileNames.COMPOSITION_YML.equals(a.getArtifactName())).findAny().orElse(null);
280 if(null == compositionArtifact){
281 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Couldn't find {} in VFCMT artifacts", DcaeBeConstants.Composition.fileNames.COMPOSITION_YML);
282 response.setErrorResponse("No Artifacts");
283 return new ResponseEntity<>(response, HttpStatus.NO_CONTENT);
286 String artifact = baseBusinessLogic.getSdcRestClient().getResourceArtifact(vfcmtUuid, compositionArtifact.getArtifactUUID(), requestId);
288 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "ARTIFACT: {}", artifact);
289 response.setSuccessResponse(artifact);
290 return new ResponseEntity<>(response, HttpStatus.OK);
291 } catch (Exception e) {
292 return handleException(e, ApiType.GET_CDUMP);
296 @RequestMapping(value = "/saveComposition/{vfcmtUuid}", method = RequestMethod.POST)
297 public ResponseEntity saveComposition(@RequestHeader("USER_ID") String userId, @RequestBody String theCdump, @PathVariable("vfcmtUuid") String vfcmtUuid, @ModelAttribute("requestId") String requestId) {
299 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "ARTIFACT CDUMP: {}", theCdump);
303 ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(vfcmtUuid, requestId);
304 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "VFCMT: {}", vfcmt);
306 checkVfcmtType(vfcmt);
307 checkUserIfResourceCheckedOut(userId, vfcmt);
308 boolean isNeed2Checkout = isNeedToCheckOut(vfcmt.getLifecycleState());
309 Artifact compositionArtifact = CollectionUtils.isEmpty(vfcmt.getArtifacts()) ? null : vfcmt.getArtifacts().stream().filter(a -> DcaeBeConstants.Composition.fileNames.COMPOSITION_YML.equals(a.getArtifactName())).findAny().orElse(null);
310 String resourceUuid = vfcmtUuid; // by default the resource is the original vfcmtId unless a checkout will be done
311 if (isNeed2Checkout) {
312 vfcmt = baseBusinessLogic.getSdcRestClient().changeResourceLifecycleState(userId, resourceUuid, LifecycleOperationType.CHECKOUT.name(), null, requestId);
314 resourceUuid = vfcmt.getUuid();
315 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "New resource after checkout is: {}", resourceUuid);
318 boolean isUpdateMode = null != compositionArtifact;
320 compositionArtifact.setDescription("updating composition file");
321 compositionArtifact.setPayloadData(Base64Utils.encodeToString(theCdump.getBytes()));
322 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "VFCMT {} does consist {} ----> updateMode", resourceUuid, DcaeBeConstants.Composition.fileNames.COMPOSITION_YML);
323 baseBusinessLogic.getSdcRestClient().updateResourceArtifact(userId, resourceUuid, compositionArtifact, requestId);
326 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "VFCMT {} does not consist {} ----> createMode", resourceUuid, DcaeBeConstants.Composition.fileNames.COMPOSITION_YML);
327 compositionArtifact = SdcRestClientUtils.generateDeploymentArtifact("creating composition file", DcaeBeConstants.Composition.fileNames.COMPOSITION_YML, ArtifactType.DCAE_TOSCA.name(), "composition", theCdump.getBytes());
328 baseBusinessLogic.getSdcRestClient().createResourceArtifact(userId, resourceUuid, compositionArtifact, requestId);
330 Asset result = checkin(userId, resourceUuid, org.onap.sdc.dcae.enums.AssetType.RESOURCE, requestId);
331 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "vfcmt check-in result: {}", result);
333 return new ResponseEntity<>(result, HttpStatus.OK);
334 } catch (Exception e) {
335 return handleException(e, ApiType.SAVE_CDUMP);