DCAE-D be initial commit
[sdc/dcae-d/dt-be-main.git] / dcaedt_be / src / main / java / org / onap / sdc / dcae / composition / controller / CompositionController.java
1 package org.onap.sdc.dcae.composition.controller;
2
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;
28
29 import javax.annotation.PostConstruct;
30 import java.net.URI;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.function.Function;
35 import java.util.stream.Collectors;
36
37 @RestController
38 @EnableAutoConfiguration
39 @CrossOrigin
40 public class CompositionController extends BaseController{
41
42     @Autowired
43     private CatalogController catalogController;
44
45     @PostConstruct
46     public void init() {
47         catalogController.setDefaultCatalog(URI.create(systemProperties.getProperties().getProperty(DcaeBeConstants.Config.ASDC_CATALOG_URL)));
48     }
49
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();
54
55         try {
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);
65             }
66
67             // fetch the target
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);
77                 }
78                 theTargetId = targetVfcmt.getUuid();
79                 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "New targetVfcmt (for artifact clone) after checkout is: {}", theTargetId);
80             }
81
82             Map<String, Artifact> currentArtifacts = CollectionUtils.isEmpty(vfcmt.getArtifacts()) ? new HashMap<>() : vfcmt.getArtifacts().stream()
83                     .collect(Collectors.toMap(Artifact::getArtifactName, Function.identity()));
84
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);
89             }
90
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);
97         }
98     }
99
100     @RequestMapping(value = "/elements", method = { RequestMethod.POST, RequestMethod.GET }, produces = "application/json")
101     public DeferredResult<CatalogResponse> items(@RequestBody(required = false) ItemsRequest theRequest) {
102
103         final ItemsRequest request = (theRequest == null) ? ItemsRequest.EMPTY_REQUEST : theRequest;
104
105         Catalog catalog = catalogController.getCatalog(request.getCatalog());
106         DeferredResult<CatalogResponse> result = new DeferredResult<CatalogResponse>(request.getTimeout());
107
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()));
115                             }
116                         }
117                         CatalogResponse response = new CatalogResponse(this.request);
118                         try {
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);
122                         }
123                         return response;
124                     }
125                 });
126         return result;
127     }
128
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) {
131
132         final ItemsRequest request = (theRequest == null) ? ItemsRequest.EMPTY_REQUEST : theRequest;
133
134         Catalog catalog = catalogController.getCatalog(request.getCatalog());
135         DeferredResult<CatalogResponse> result = new DeferredResult<CatalogResponse>(request.getTimeout());
136
137         catalog
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) {
144                             return response;
145                         }
146
147                         try {
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",
154                                             Annotations.class);
155                                     if (annotations != null) {
156                                         for (Object a : annotations) {
157                                             catalogController.patchData(catalog, ((Annotation) a).data());
158                                         }
159                                     }
160                                 }
161                             }
162                             Elements items = theFolder.elements("items", Items.class);
163                             if (items != null) {
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());
171                                         }
172                                     }
173                                 }
174                             }
175                         } catch (Exception x) {
176                             errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Exception processing catalog {}", x);
177                             return new CatalogError(this.request, "", x);
178                         }
179
180                         try {
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);
184                         }
185                         return response;
186                     }
187                 });
188
189         return result;
190     }
191
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;
196
197         Catalog catalog = catalogController.getCatalog(request.getCatalog());
198         DeferredResult<CatalogResponse> result = new DeferredResult<>(request.getTimeout());
199
200         catalog
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");
206                         }
207                         Templates models = null;
208                         try {
209                             models = (Templates) theItem.elements("models", Templates.class);
210                             if (models == null || models.isEmpty()) {
211                                 return new CatalogError(this.request, "Item has no models");
212                             }
213                             if (models.size() > 1) {
214                                 return new CatalogError(this.request, "Item has more than one model !?");
215                             }
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) {
225                                                         try {
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);
230                                                         }
231                                                     }
232                                                     return response;
233                                                 }
234                                             });
235                         } catch (Exception e) {
236                             handleException(e, ApiType.GET_MODEL, models.get(0).name());
237                         }
238                         return null;
239                     }
240                 });
241
242         return result;
243     }
244
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;
248
249         Catalog catalog = catalogController.getCatalog(request.getCatalog());
250         DeferredResult<CatalogResponse> result = new DeferredResult<CatalogResponse>(request.getTimeout());
251
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) {
257                             try {
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);
261                             }
262                         }
263                         return response;
264                     }
265                 });
266
267         return result;
268     }
269
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();
273         try {
274             ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(vfcmtUuid, requestId);
275             debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), vfcmt.toString());
276             checkVfcmtType(vfcmt);
277
278             Artifact compositionArtifact = CollectionUtils.isEmpty(vfcmt.getArtifacts()) ? null : vfcmt.getArtifacts().stream().filter(a -> DcaeBeConstants.Composition.fileNames.COMPOSITION_YML.equals(a.getArtifactName())).findAny().orElse(null);
279
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);
284             }
285
286             String artifact = baseBusinessLogic.getSdcRestClient().getResourceArtifact(vfcmtUuid, compositionArtifact.getArtifactUUID(), requestId);
287
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);
293         }
294     }
295
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) {
298
299         debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "ARTIFACT CDUMP: {}", theCdump);
300
301         try {
302
303             ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(vfcmtUuid, requestId);
304             debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "VFCMT: {}", vfcmt);
305
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);
313                 if (vfcmt != null) {
314                     resourceUuid = vfcmt.getUuid();
315                     debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "New resource after checkout is: {}", resourceUuid);
316                 }
317             }
318             boolean isUpdateMode = null != compositionArtifact;
319             if (isUpdateMode) {
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);
324
325             } else {
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);
329             }
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);
332
333             return new ResponseEntity<>(result, HttpStatus.OK);
334         } catch (Exception e) {
335             return handleException(e, ApiType.SAVE_CDUMP);
336         }
337     }
338 }