Catalog alignment
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / impl / CommonImportManager.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. 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  * Modifications copyright (c) 2019 Nokia
20  * ================================================================================
21  */
22
23 package org.openecomp.sdc.be.components.impl;
24
25 import fj.data.Either;
26 import org.apache.commons.lang3.tuple.ImmutablePair;
27 import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum;
28 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
29 import org.openecomp.sdc.be.components.impl.model.ToscaTypeImportData;
30 import org.openecomp.sdc.be.config.BeEcompErrorManager;
31 import org.openecomp.sdc.be.dao.api.ActionStatus;
32 import org.openecomp.sdc.be.datatypes.elements.ToscaTypeDataDefinition;
33 import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition;
34 import org.openecomp.sdc.be.impl.ComponentsUtils;
35 import org.openecomp.sdc.be.model.CapabilityTypeDefinition;
36 import org.openecomp.sdc.be.model.DataTypeDefinition;
37 import org.openecomp.sdc.be.model.GroupTypeDefinition;
38 import org.openecomp.sdc.be.model.PolicyTypeDefinition;
39 import org.openecomp.sdc.be.model.PropertyDefinition;
40 import org.openecomp.sdc.be.model.normatives.ToscaTypeMetadata;
41 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
42 import org.openecomp.sdc.be.model.operations.api.TypeOperations;
43 import org.openecomp.sdc.be.model.operations.impl.PropertyOperation;
44 import org.openecomp.sdc.common.log.wrappers.Logger;
45 import org.openecomp.sdc.exception.ResponseFormat;
46 import org.springframework.beans.factory.annotation.Autowired;
47 import org.springframework.stereotype.Component;
48 import org.yaml.snakeyaml.Yaml;
49
50 import java.util.ArrayList;
51 import java.util.HashMap;
52 import java.util.Iterator;
53 import java.util.List;
54 import java.util.Map;
55 import java.util.Map.Entry;
56 import java.util.function.BiFunction;
57 import java.util.function.Consumer;
58 import java.util.function.Function;
59 import java.util.stream.Collectors;
60
61 import static java.util.stream.Collectors.toList;
62
63 @Component("commonImportManager")
64 public class CommonImportManager {
65
66     private static final Logger log = Logger.getLogger(CommonImportManager.class.getName());
67
68     private final ComponentsUtils componentsUtils;
69     private final PropertyOperation propertyOperation;
70
71     @Autowired
72     public CommonImportManager(ComponentsUtils componentsUtils, PropertyOperation propertyOperation) {
73         this.componentsUtils = componentsUtils;
74         this.propertyOperation = propertyOperation;
75     }
76
77     public static void setProperties(Map<String, Object> toscaJson, Consumer<List<PropertyDefinition>> consumer) {
78         consumer.accept(getProperties(toscaJson));
79     }
80
81     private static List<PropertyDefinition> getProperties(Map<String, Object> toscaJson) {
82         List<PropertyDefinition> values = null;
83         Either<Map<String, PropertyDefinition>, ResultStatusEnum> properties = ImportUtils.getProperties(toscaJson);
84
85         if (properties.isLeft()) {
86             values = new ArrayList<>();
87             Map<String, PropertyDefinition> propertiesMap = properties.left().value();
88             if (propertiesMap != null && !propertiesMap.isEmpty()) {
89
90                 for (Entry<String, PropertyDefinition> entry : propertiesMap.entrySet()) {
91                     String propName = entry.getKey();
92                     PropertyDefinition propertyDefinition = entry.getValue();
93                     PropertyDefinition newPropertyDefinition = new PropertyDefinition(propertyDefinition);
94                     newPropertyDefinition.setName(propName);
95                     values.add(newPropertyDefinition);
96                 }
97             }
98         }
99
100         return values;
101     }
102
103     protected void setPropertiesMap(Map<String, Object> toscaJson, Consumer<Map<String, PropertyDefinition>> consumer) {
104         final List<PropertyDefinition> properties = getProperties(toscaJson);
105         if (properties != null) {
106             Map<String, PropertyDefinition> collect = properties.stream()
107                                                         .collect(Collectors.toMap(PropertyDefinition::getName, Function.identity()));
108             consumer.accept(collect);
109         }
110     }
111
112     public interface ICreateElementType<T1, T2, T3> {
113         T3 createElement(T1 firstArg, T2 secondArg);
114     }
115
116     protected <T> Either<List<T>, ActionStatus> createElementTypesFromYml(String elementTypesYml, ICreateElementType<String, Map<String, Object>, T> createApi) {
117
118         List<T> elementTypes;
119         Map<String, Object> toscaJson = convertToFieldMap(elementTypesYml);
120         if (toscaJson==null) {
121             return Either.right(ActionStatus.INVALID_YAML_FILE);
122         }
123         elementTypes = createElementTypesFromToscaJsonMap(createApi, toscaJson);
124         return Either.left(elementTypes);
125     }
126
127     @SuppressWarnings("unchecked")
128     private Map<String, Object> convertToFieldMap(String elementTypesYml) {
129         Map<String, Object> toscaJson = null;
130         try {
131             toscaJson = (Map<String, Object>) new Yaml().load(elementTypesYml);
132         } catch (Exception e) {
133             log.debug("Failed to yaml file {}", elementTypesYml, e);
134         }
135         return toscaJson;
136     }
137
138
139     protected <T extends ToscaDataDefinition> List<T> createTypesFromToscaJsonMap(
140             BiFunction<String, Map<String, Object>, T> createApi, Map<String, Object> toscaJson) {
141         List<T> elementTypes = new ArrayList<>();
142
143         for (Entry<String, Object> elementTypeNameDataEntry : toscaJson.entrySet()) {
144             String elementTypeName = elementTypeNameDataEntry.getKey();
145             Map<String, Object> elementTypeJsonData = (Map<String, Object>) elementTypeNameDataEntry.getValue();
146             T elementDefinition = createApi.apply(elementTypeName, elementTypeJsonData);
147             elementTypes.add(elementDefinition);
148         }
149         return elementTypes;
150     }
151
152     protected <T> List<T> createElementTypesFromToscaJsonMap(
153                 ICreateElementType<String, Map<String, Object>, T> createApi, Map<String, Object> toscaJson) {
154         List<T> elementTypes = new ArrayList<>();
155
156         for (Entry<String, Object> elementTypeNameDataEntry : toscaJson.entrySet()) {
157             String elementTypeName = elementTypeNameDataEntry.getKey();
158             Map<String, Object> elementTypeJsonData = (Map<String, Object>) elementTypeNameDataEntry.getValue();
159             T elementDefinition = createApi.createElement(elementTypeName, elementTypeJsonData);
160             elementTypes.add(elementDefinition);
161         }
162         return elementTypes;
163     }
164
165     protected <T> Map<String, T> createElementTypesMapFromToscaJsonMap(
166                 ICreateElementType<String, Map<String, Object>, T> createApi, Map<String, Object> toscaJson) {
167         Map<String, T> elementTypesMap = new HashMap<>();
168         
169         Iterator<Entry<String, Object>> elementTypesEntryItr = toscaJson.entrySet().iterator();
170         while (elementTypesEntryItr.hasNext()) {
171             Entry<String, Object> elementTypeNameDataEntry = elementTypesEntryItr.next();
172             String elementTypeName = elementTypeNameDataEntry.getKey();
173             Map<String, Object> elementTypeJsonData = (Map<String, Object>) elementTypeNameDataEntry.getValue();
174             T elementDefinition = createApi.createElement(elementTypeName, elementTypeJsonData);
175             elementTypesMap.put(elementTypeName, elementDefinition);
176         }
177         return elementTypesMap;
178     }
179
180     protected <F> void setField(Map<String, Object> toscaJson, String fieldName, Consumer<F> setter) {
181         if (toscaJson.containsKey(fieldName)) {
182             F fieldValue = (F) toscaJson.get(fieldName);
183             setter.accept(fieldValue);
184         }
185     }
186
187     public enum ElementTypeEnum {
188         POLICY_TYPE, GROUP_TYPE, DATA_TYPE, CAPABILITY_TYPE, INTERFACE_LIFECYCLE_TYPE, RELATIONSHIP_TYPE
189     }
190
191     private ActionStatus convertFromStorageResponseForElementType(StorageOperationStatus status, ElementTypeEnum elementTypeEnum) {
192         ActionStatus ret;
193         switch (elementTypeEnum) {
194         case GROUP_TYPE:
195             ret = componentsUtils.convertFromStorageResponseForGroupType(status);
196             break;
197         case DATA_TYPE:
198             ret = componentsUtils.convertFromStorageResponseForDataType(status);
199             break;
200         case CAPABILITY_TYPE:
201             ret = componentsUtils.convertFromStorageResponseForCapabilityType(status);
202             break;
203         case INTERFACE_LIFECYCLE_TYPE:
204             ret = componentsUtils.convertFromStorageResponseForLifecycleType(status);
205             break;
206         case RELATIONSHIP_TYPE:
207             ret = componentsUtils.convertFromStorageResponseForRelationshipType(status);
208             break;
209         default:
210             ret = componentsUtils.convertFromStorageResponse(status);
211             break;
212         }
213         return ret;
214     }
215
216     private <T> ResponseFormat getResponseFormatForElementType(ActionStatus actionStatus, ElementTypeEnum elementTypeEnum, T elementTypeDefinition) {
217         ResponseFormat ret;
218         switch (elementTypeEnum) {
219         case GROUP_TYPE:
220             ret = componentsUtils.getResponseFormatByGroupType(actionStatus, (GroupTypeDefinition) elementTypeDefinition);
221             break;
222         case POLICY_TYPE:
223             ret = componentsUtils.getResponseFormatByPolicyType(actionStatus, (PolicyTypeDefinition) elementTypeDefinition);
224             break;
225         case DATA_TYPE:
226             ret = componentsUtils.getResponseFormatByDataType(actionStatus, (DataTypeDefinition) elementTypeDefinition, null);
227             break;
228         case CAPABILITY_TYPE:
229             ret = componentsUtils.getResponseFormatByCapabilityType(actionStatus, (CapabilityTypeDefinition) elementTypeDefinition);
230             break;
231
232         default:
233             ret = componentsUtils.getResponseFormat(actionStatus);
234             break;
235         }
236         return ret;
237     }
238
239     private <T extends ToscaDataDefinition> List<ImmutablePair<T, Boolean>> createTypesByDao(List<T> elementTypesToCreate,
240                                                                                              TypeOperations<T> typeOperations) {
241         List<ImmutablePair<T, Boolean>> createdElementTypes = new ArrayList<>();
242         for (T newTypeDefinition : elementTypesToCreate) {
243             try {
244                 String typeName = newTypeDefinition.getType();
245                 T existingDefinition = typeOperations.getLatestType(typeName);
246                 if (existingDefinition == null /*new type*/) {
247                     typeOperations.addType(newTypeDefinition);
248                 } else {
249                     if (typeOperations.isSameType(newTypeDefinition, existingDefinition)) {
250                         propertyOperation.getJanusGraphGenericDao().rollback();
251                         createdElementTypes.add(new ImmutablePair<>(newTypeDefinition, null));
252                         continue;
253                     } else {
254                         typeOperations.updateType(existingDefinition, newTypeDefinition);
255                     }
256                 }
257                 propertyOperation.getJanusGraphGenericDao().commit();
258                 createdElementTypes.add(new ImmutablePair<>(newTypeDefinition, true));
259             } catch (Exception e) {
260                 propertyOperation.getJanusGraphGenericDao().rollback();
261                 createdElementTypes.add(new ImmutablePair<>(newTypeDefinition, false));
262             }
263
264         }
265         return createdElementTypes;
266     }
267     
268     protected <T> Either<List<ImmutablePair<T, Boolean>>, ResponseFormat> createElementTypesByDao(List<T> elementTypesToCreate,
269             Function<T, Either<ActionStatus, ResponseFormat>> validator, Function<T, ImmutablePair<ElementTypeEnum, String>> elementInfoGetter,
270             Function<String, Either<T, StorageOperationStatus>> elementFetcher, Function<T, Either<T, StorageOperationStatus>> elementAdder,
271             BiFunction<T, T, Either<T, StorageOperationStatus>> elementUpgrader) {
272
273         List<ImmutablePair<T, Boolean>> createdElementTypes = new ArrayList<>();
274
275         Either<List<ImmutablePair<T, Boolean>>, ResponseFormat> eitherResult = Either.left(createdElementTypes);
276         Iterator<T> elementTypeItr = elementTypesToCreate.iterator();
277
278         try {
279             while (elementTypeItr.hasNext()) {
280                 T elementType = elementTypeItr.next();
281                 eitherResult = handleType(elementType, validator, elementInfoGetter, elementFetcher, elementAdder, elementUpgrader)
282                                             .left()
283                                             .map(elem -> append(createdElementTypes, elem));
284                 
285                 if (eitherResult.isRight()) {
286                     break;
287                 }
288                 
289                 if(!elementTypeItr.hasNext()) {
290                     log.info("all {} were created successfully!!!", elementType);
291                 }
292             }
293         }
294         catch(Exception e) {
295             eitherResult = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
296             throw e;
297         } 
298         finally {
299             if (eitherResult.isLeft()) {
300                 propertyOperation.getJanusGraphGenericDao().commit();
301             }
302             else {
303                 propertyOperation.getJanusGraphGenericDao().rollback();
304             }
305         }
306
307         return eitherResult;
308     }
309     
310     private static <T> List<T> append(List<T> list, T value) {
311         list.add(value);
312         return list;
313     }
314     
315     
316     private <T> Either<ImmutablePair<T, Boolean>, ResponseFormat> handleType(T elementType, 
317             Function<T, Either<ActionStatus, ResponseFormat>> validator, Function<T, ImmutablePair<ElementTypeEnum, String>> elementInfoGetter,
318             Function<String, Either<T, StorageOperationStatus>> elementFetcher, Function<T, Either<T, StorageOperationStatus>> elementAdder,
319             BiFunction<T, T, Either<T, StorageOperationStatus>> elementUpgrader) {
320         
321         final ImmutablePair<ElementTypeEnum, String> elementInfo = elementInfoGetter.apply(elementType);
322         ElementTypeEnum elementTypeEnum = elementInfo.left;
323         String elementName = elementInfo.right;
324         
325         Either<ActionStatus, ResponseFormat> validateElementType = validator.apply(elementType);
326         if (validateElementType.isRight()) {
327             ResponseFormat responseFormat = validateElementType.right().value();
328             log.debug("Failed in validation of element type: {}. Response is {}", elementType, responseFormat.getFormattedMessage());
329             return Either.right(responseFormat);
330         }
331
332         log.info("send {} : {} to dao for create", elementTypeEnum, elementName);
333
334         Either<T, StorageOperationStatus> findElementType = elementFetcher.apply(elementName);
335         if (findElementType.isRight()) {
336             StorageOperationStatus status = findElementType.right().value();
337             log.debug("searched {} finished with result:{}", elementTypeEnum, status);
338             if (status != StorageOperationStatus.NOT_FOUND) {
339                 ResponseFormat responseFormat = getResponseFormatForElementType(convertFromStorageResponseForElementType(status, elementTypeEnum), elementTypeEnum, elementType);
340                 return Either.right(responseFormat);
341             } else {
342                 return addElementType(elementType, elementAdder, elementTypeEnum, elementName);
343             }
344         } else {
345
346             if (elementUpgrader != null) {
347                 return updateElementType(elementType, elementUpgrader, elementTypeEnum, elementName, findElementType.left().value());
348
349             } else {
350                 // mshitrit Once GroupType Versions are supported add
351                 // code here
352                 log.debug("{} : {} already exists.", elementTypeEnum, elementName);
353                 return Either.left(new ImmutablePair<>(elementType, false));
354             }
355
356         }
357     }
358
359     private <T> Either<ImmutablePair<T, Boolean>, ResponseFormat> addElementType(T elementType, Function<T, Either<T, StorageOperationStatus>> elementAdder, ElementTypeEnum elementTypeEnum, String elementName) {
360         Either<T, StorageOperationStatus> dataModelResponse = elementAdder.apply(elementType);
361         
362         if (dataModelResponse.isRight()) {
363             BeEcompErrorManager.getInstance().logBeFailedAddingNodeTypeError("Create {}", elementTypeEnum.name());
364             log.debug("failed to create {}: {}", elementTypeEnum, elementName);
365             if (dataModelResponse.right().value() != StorageOperationStatus.OK) {
366                 ResponseFormat responseFormat = getResponseFormatForElementType(convertFromStorageResponseForElementType(dataModelResponse.right().value(), elementTypeEnum), elementTypeEnum, elementType);
367                 
368                 return Either.right(responseFormat);
369             } else {
370                 return Either.left(new ImmutablePair<>(elementType, false));
371             }
372         } else {
373             log.debug("{} : {}  was created successfully.", elementTypeEnum, elementName);
374             return Either.left(new ImmutablePair<>(elementType, true));
375         }
376     }
377     
378     
379     private <T> Either<ImmutablePair<T, Boolean>, ResponseFormat> updateElementType(T elementType, BiFunction<T, T, Either<T, StorageOperationStatus>> elementUpgrader, 
380                                                         ElementTypeEnum elementTypeEnum, String elementName, T existingElementType) {
381         Either<T, StorageOperationStatus> upgradeResponse = elementUpgrader.apply(elementType, existingElementType);
382         if (upgradeResponse.isRight()) {
383             StorageOperationStatus status = upgradeResponse.right().value();
384             if (status == StorageOperationStatus.OK) {
385                 return Either.left(new ImmutablePair<>(elementType, false));
386             } else {
387                 ResponseFormat responseFormat = getResponseFormatForElementType(convertFromStorageResponseForElementType(upgradeResponse.right().value(), elementTypeEnum), elementTypeEnum, elementType);
388                 return Either.right(responseFormat);
389             }
390         } else {
391             log.debug("{} : {}  was upgraded successfully.", elementTypeEnum, elementName);
392             return Either.left(new ImmutablePair<>(elementType, true));
393         }
394     }
395
396     
397     public <T extends ToscaTypeDataDefinition> Either<List<ImmutablePair<T, Boolean>>, ResponseFormat> createElementTypes(ToscaTypeImportData toscaTypeImportData, Function<String, Either<List<T>, ActionStatus>> elementTypeFromYmlCreater,
398                                                                                                                           Function<List<T>, Either<List<ImmutablePair<T, Boolean>>, ResponseFormat>> elementTypeDaoCreater) {
399         Either<List<T>, ActionStatus> elementTypes = elementTypeFromYmlCreater.apply(toscaTypeImportData.getToscaTypesYml());
400         return elementTypes
401                 .right()
402                 .map(err -> componentsUtils.getResponseFormat(err, ""))
403                 .left()
404                 .map(toscaTypes -> enrichTypesWithNonToscaMetadata(toscaTypes, toscaTypeImportData.getToscaTypeMetadata()))
405                 .left()
406                 .bind(elementTypeDaoCreater::apply);
407     }
408
409     public <T extends ToscaDataDefinition> List<ImmutablePair<T, Boolean>> createElementTypes(String toscaTypesYml,
410                                                                                               BiFunction<String, Map<String, Object>, T> createApi,
411                                                                                               TypeOperations<T> typeOperations) {
412         Map<String, Object> fieldMap = convertToFieldMap(toscaTypesYml);
413         if (fieldMap==null) {
414             throw new ByActionStatusComponentException(ActionStatus.INVALID_YAML_FILE);
415         }
416         List<T> elementTypes = createTypesFromToscaJsonMap(createApi, fieldMap);
417         return createTypesByDao(elementTypes, typeOperations);
418     }
419
420     private <T extends ToscaTypeDataDefinition> List<T> enrichTypesWithNonToscaMetadata(List<T> toscaTypes, Map<String, ToscaTypeMetadata> toscaTypeMetadata) {
421         return toscaTypes.stream()
422                   .map(toscaType -> setNonToscaMetaDataOnType(toscaTypeMetadata, toscaType))
423                   .collect(toList());
424     }
425
426     private <T extends ToscaTypeDataDefinition> T setNonToscaMetaDataOnType(Map<String, ToscaTypeMetadata> toscaTypeMetadata, T toscaTypeDefinition) {
427         String toscaType = toscaTypeDefinition.getType();
428         ToscaTypeMetadata typeMetaData = toscaTypeMetadata.get(toscaType);
429         if (typeMetaData == null) {
430             log.debug("failing while trying to associate metadata for type {}. type not exist", toscaType);
431             throw new ByActionStatusComponentException(ActionStatus.GENERAL_ERROR);
432         }
433         toscaTypeDefinition.setIcon(typeMetaData.getIcon());
434         toscaTypeDefinition.setName(typeMetaData.getDisplayName());
435         return toscaTypeDefinition;
436     }
437
438     public <T> Either<List<ImmutablePair<T, Boolean>>, ResponseFormat> createElementTypes(String elementTypesYml, Function<String, Either<List<T>, ActionStatus>> elementTypeFromYmlCreater,
439             Function<List<T>, Either<List<ImmutablePair<T, Boolean>>, ResponseFormat>> elementTypeDaoCreater, ElementTypeEnum elementTypeEnum) {
440
441         Either<List<T>, ActionStatus> elementTypes = elementTypeFromYmlCreater.apply(elementTypesYml);
442         if (elementTypes.isRight()) {
443             ActionStatus status = elementTypes.right().value();
444             ResponseFormat responseFormat = getResponseFormatForElementType(status, elementTypeEnum, null);
445             return Either.right(responseFormat);
446         }
447         return elementTypeDaoCreater.apply(elementTypes.left().value());
448
449     }
450 }