2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.openecomp.sdc.be.model.jsontitan.operations;
23 import fj.data.Either;
24 import org.apache.commons.collections.MapUtils;
25 import org.openecomp.sdc.be.dao.jsongraph.GraphVertex;
26 import org.openecomp.sdc.be.dao.jsongraph.types.EdgeLabelEnum;
27 import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum;
28 import org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum;
29 import org.openecomp.sdc.be.dao.titan.TitanOperationStatus;
30 import org.openecomp.sdc.be.datatypes.elements.*;
31 import org.openecomp.sdc.be.datatypes.elements.MapCapabilityProperty;
32 import org.openecomp.sdc.be.datatypes.elements.MapListCapabilityDataDefinition;
33 import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
34 import org.openecomp.sdc.be.model.*;
35 import org.openecomp.sdc.be.model.jsontitan.utils.ModelConverter;
36 import org.openecomp.sdc.be.model.operations.StorageException;
37 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
38 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
39 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
40 import org.openecomp.sdc.common.jsongraph.util.CommonUtility;
41 import org.openecomp.sdc.common.jsongraph.util.CommonUtility.LogLevelEnum;
42 import org.openecomp.sdc.common.log.wrappers.Logger;
44 import java.util.ArrayList;
45 import java.util.List;
47 import java.util.Map.Entry;
48 import java.util.Optional;
49 import java.util.stream.Collectors;
51 @org.springframework.stereotype.Component("groups-operation")
52 public class GroupsOperation extends BaseOperation {
54 private static final Logger log = Logger.getLogger(GroupsOperation.class.getName());
56 public StorageOperationStatus deleteCalculatedCapabilitiesWithProperties(String componentId, List<GroupDefinition> groupDefinitions) {
57 Optional<StorageOperationStatus> error = groupDefinitions.stream().map(g->removeCalculatedCapabilityFromComponent(componentId, g.getUniqueId())).filter(status-> status!=StorageOperationStatus.OK).findFirst();
58 if(!error.isPresent()){
59 Map<String, MapCapabilityProperty> extractCapabilityPropertiesFromGroups = ModelConverter.extractCapabilityPropertiesFromGroups(groupDefinitions, false);
60 error = extractCapabilityPropertiesFromGroups.keySet().stream().map(k->removeCalculatedCapabilityPropertiesFromComponent(componentId, k)).filter(status-> status!=StorageOperationStatus.OK).findFirst();
62 if(error.isPresent()){
65 return StorageOperationStatus.OK;
69 * Adds the map of the calculated capabilities and the map of the calculated capabilities properties the the component on the graph
71 * @param calculatedCapabilities
72 * @param calculatedCapabilitiesProperties
73 * @return status of the result the operation
75 public StorageOperationStatus addCalculatedCapabilitiesWithProperties(String componentId, Map<String, MapListCapabilityDataDefinition> calculatedCapabilities, Map<String, MapCapabilityProperty> calculatedCapabilitiesProperties) {
77 Optional<StorageOperationStatus> error = calculatedCapabilities.entrySet().stream().map(e-> addElementToComponent(componentId, VertexTypeEnum.CALCULATED_CAPABILITIES, EdgeLabelEnum.CALCULATED_CAPABILITIES, e)).filter(status-> status!=StorageOperationStatus.OK).findFirst();
78 if(!error.isPresent()){
79 error = calculatedCapabilitiesProperties.entrySet().stream().map(e->addCalculatedCapabilityPropertiesToComponent(componentId, e)).filter(status-> status!=StorageOperationStatus.OK).findFirst();
81 if(error.isPresent()){
84 return StorageOperationStatus.OK;
87 public StorageOperationStatus updateCalculatedCapabilitiesWithProperties(String componentId, Map<String, MapListCapabilityDataDefinition> calculatedCapabilities, Map<String, MapCapabilityProperty> calculatedCapabilitiesProperties) {
89 Optional<StorageOperationStatus> error = calculatedCapabilities.entrySet().stream().map(e->updateCalculatedCapabilityOfComponent(componentId, e)).filter(status-> status!=StorageOperationStatus.OK).findFirst();
90 if(!error.isPresent()){
91 error = calculatedCapabilitiesProperties.entrySet().stream().map(e->updateCalculatedCapabilityPropertiesOnComponent(componentId, e)).filter(status-> status!=StorageOperationStatus.OK).findFirst();
93 if(error.isPresent()){
96 return StorageOperationStatus.OK;
99 private StorageOperationStatus updateCalculatedCapabilityOfComponent(String componentId, Entry<String, MapListCapabilityDataDefinition> capabilities){
100 if(MapUtils.isNotEmpty(capabilities.getValue().getMapToscaDataDefinition()))
101 return updateToscaDataDeepElementsBlockToToscaElement(componentId, EdgeLabelEnum.CALCULATED_CAPABILITIES, capabilities.getValue(), capabilities.getKey());
102 return StorageOperationStatus.OK;
105 private StorageOperationStatus addCalculatedCapabilityPropertiesToComponent(String componentId, Entry<String, MapCapabilityProperty> properties){
106 if(MapUtils.isNotEmpty(properties.getValue().getMapToscaDataDefinition()))
107 return addToscaDataDeepElementsBlockToToscaElement(componentId, EdgeLabelEnum.CALCULATED_CAP_PROPERTIES, VertexTypeEnum.CALCULATED_CAP_PROPERTIES, properties.getValue(), properties.getKey());
108 return StorageOperationStatus.OK;
111 private StorageOperationStatus updateCalculatedCapabilityPropertiesOnComponent(String componentId, Entry<String, MapCapabilityProperty> properties){
112 if(MapUtils.isNotEmpty(properties.getValue().getMapToscaDataDefinition()))
113 return updateToscaDataDeepElementsBlockToToscaElement(componentId, EdgeLabelEnum.CALCULATED_CAP_PROPERTIES, properties.getValue(), properties.getKey());
114 return StorageOperationStatus.OK;
117 private StorageOperationStatus removeCalculatedCapabilityFromComponent(String componentId, String groupId){
118 return deleteToscaDataDeepElementsBlockOfToscaElement(componentId, EdgeLabelEnum.CALCULATED_CAPABILITIES, VertexTypeEnum.CALCULATED_CAPABILITIES, groupId);
121 private StorageOperationStatus removeCalculatedCapabilityPropertiesFromComponent(String componentId, String groupId){
122 return deleteToscaDataDeepElementsBlockOfToscaElement(componentId, EdgeLabelEnum.CALCULATED_CAP_PROPERTIES, VertexTypeEnum.CALCULATED_CAP_PROPERTIES, groupId);
126 public Either<List<GroupDefinition>, StorageOperationStatus> createGroups(Component component, Map<String, GroupDataDefinition> groups) {
128 Either<List<GroupDefinition>, StorageOperationStatus> result = null;
129 Either<GraphVertex, TitanOperationStatus> getComponentVertex = null;
130 StorageOperationStatus status = null;
132 getComponentVertex = titanDao.getVertexById(component.getUniqueId(), JsonParseFlagEnum.NoParse);
133 if (getComponentVertex.isRight()) {
134 result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(getComponentVertex.right().value()));
136 if (result == null) {
137 status = topologyTemplateOperation.associateGroupsToComponent(getComponentVertex.left().value(), groups);
138 if (status != StorageOperationStatus.OK) {
139 result = Either.right(status);
142 if (result == null) {
143 result = Either.left(ModelConverter.convertToGroupDefinitions(groups));
148 public <T extends GroupDataDefinition> Either<List<GroupDefinition>, StorageOperationStatus> addGroups(Component component, List<T> groups) {
149 Either<List<GroupDefinition>, StorageOperationStatus> result = null;
150 Either<GraphVertex, TitanOperationStatus> getComponentVertex;
151 StorageOperationStatus status;
153 getComponentVertex = titanDao.getVertexById(component.getUniqueId(), JsonParseFlagEnum.NoParse);
154 if (getComponentVertex.isRight()) {
155 result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(getComponentVertex.right().value()));
157 if (result == null) {
158 status = addToscaDataToToscaElement(component.getUniqueId(), EdgeLabelEnum.GROUPS, VertexTypeEnum.GROUPS, groups, JsonPresentationFields.NAME);
160 if (status != StorageOperationStatus.OK) {
161 result = Either.right(status);
165 if (result == null) {
166 Map<String, GroupDataDefinition> mapGroup = groups.stream().collect(Collectors.toMap(GroupDataDefinition::getName, x->x));
167 result = Either.left(ModelConverter.convertToGroupDefinitions(mapGroup));
172 public Either<List<GroupDefinition>, StorageOperationStatus> deleteGroups(Component component, List<GroupDataDefinition> groups) {
173 Either<List<GroupDefinition>, StorageOperationStatus> result = null;
174 Either<GraphVertex, TitanOperationStatus> getComponentVertex = null;
175 StorageOperationStatus status = null;
177 getComponentVertex = titanDao.getVertexById(component.getUniqueId(), JsonParseFlagEnum.NoParse);
178 if (getComponentVertex.isRight()) {
179 result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(getComponentVertex.right().value()));
181 if (result == null) {
182 List<String> groupName = groups.stream().map(GroupDataDefinition::getName).collect(Collectors.toList());
183 status = deleteToscaDataElements(component.getUniqueId(), EdgeLabelEnum.GROUPS, groupName);
185 if (status != StorageOperationStatus.OK) {
186 result = Either.right(status);
190 if (result == null) {
191 Map<String, GroupDataDefinition> mapGroup = groups.stream().collect(Collectors.toMap( GroupDataDefinition::getName, x->x));
192 result = Either.left(ModelConverter.convertToGroupDefinitions(mapGroup));
197 public <T extends GroupDataDefinition> Either<List<GroupDefinition>, StorageOperationStatus> updateGroups(Component component, List<T> groups, boolean promoteVersion) {
198 Either<List<GroupDefinition>, StorageOperationStatus> result = null;
199 Either<GraphVertex, TitanOperationStatus> getComponentVertex = null;
200 StorageOperationStatus status = null;
202 getComponentVertex = titanDao.getVertexById(component.getUniqueId(), JsonParseFlagEnum.NoParse);
203 if (getComponentVertex.isRight()) {
204 result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(getComponentVertex.right().value()));
206 if (result == null) {
207 groups.forEach(gr -> {
208 updateVersion(promoteVersion, gr);
209 String groupUUID = UniqueIdBuilder.generateUUID();
210 gr.setGroupUUID(groupUUID);
213 status = updateToscaDataOfToscaElement(component.getUniqueId(), EdgeLabelEnum.GROUPS, VertexTypeEnum.GROUPS, groups, JsonPresentationFields.NAME);
215 if (status != StorageOperationStatus.OK) {
216 result = Either.right(status);
220 if (result == null) {
221 Map<String, GroupDataDefinition> mapGroup = groups.stream().collect(Collectors.toMap( GroupDataDefinition::getName, x->x));
222 result = Either.left(ModelConverter.convertToGroupDefinitions(mapGroup));
227 private <T extends GroupDataDefinition> void updateVersion(boolean promoteVersion, T group) {
229 String version = group.getVersion();
230 String newVersion = increaseMajorVersion(version);
231 group.setVersion(newVersion);
235 public void updateGroupOnComponent(String componentId, GroupDefinition groupDefinition) {
236 GraphVertex componentVertex = titanDao.getVertexById(componentId, JsonParseFlagEnum.ParseMetadata)
238 .on(this::onTitanError);
240 StorageOperationStatus updateToscaResult = updateToscaDataOfToscaElement(componentVertex, EdgeLabelEnum.GROUPS, VertexTypeEnum.GROUPS, groupDefinition,
241 JsonPresentationFields.NAME);
243 if (StorageOperationStatus.OK != updateToscaResult) {
244 throw new StorageException(updateToscaResult, groupDefinition.getUniqueId());
247 updateLastUpdateDate(componentVertex);
250 private void updateLastUpdateDate(GraphVertex componentVertex) {
251 componentVertex.setJsonMetadataField(JsonPresentationFields.LAST_UPDATE_DATE, System.currentTimeMillis());
252 titanDao.updateVertex(componentVertex)
254 .on(this::onTitanError);
257 GraphVertex onTitanError(TitanOperationStatus titanOperationStatus) {
258 throw new StorageException(
259 DaoStatusConverter.convertTitanStatusToStorageStatus(titanOperationStatus));
262 public Either<List<GroupProperty>, StorageOperationStatus> updateGroupPropertiesOnComponent(String componentId, GroupDefinition group, List<GroupProperty> newGroupProperties) {
264 Either<List<GroupProperty>, StorageOperationStatus> result = null;
265 Either<GraphVertex, TitanOperationStatus> getComponentVertex = null;
266 GraphVertex componentVertex = null;
268 getComponentVertex = titanDao.getVertexById(componentId, JsonParseFlagEnum.ParseMetadata);
269 if (getComponentVertex.isRight()) {
270 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to fetch component {}. Status is {} ", componentId);
271 result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(getComponentVertex.right().value()));
273 if (result == null) {
274 componentVertex = getComponentVertex.left().value();
276 List<PropertyDataDefinition> properties = group.getProperties();
277 newGroupProperties.forEach(np -> {
278 Optional<PropertyDataDefinition> currentProp = properties.stream().filter(p -> p.getName().equals(np.getName())).findAny();
279 if (currentProp.isPresent()) {
280 currentProp.get().setValue(np.getValue());
284 StorageOperationStatus updateDataRes = updateToscaDataOfToscaElement(componentVertex, EdgeLabelEnum.GROUPS, VertexTypeEnum.GROUPS, group, JsonPresentationFields.NAME);
285 if (updateDataRes != StorageOperationStatus.OK) {
286 log.debug("Failed to update properties for group {} error {}", group.getName(), updateDataRes);
287 result = Either.right(updateDataRes);
290 if (result == null) {
291 componentVertex.setJsonMetadataField(JsonPresentationFields.LAST_UPDATE_DATE, System.currentTimeMillis());
292 Either<GraphVertex, TitanOperationStatus> updateRes = titanDao.updateVertex(componentVertex);
293 if (updateRes.isRight()) {
294 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to update the component {}. Status is {} ", componentId, updateRes.right().value());
295 result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(updateRes.right().value()));
298 if (result == null) {
299 result = Either.left(newGroupProperties);
305 * The version of the group is an integer. In order to support BC, we might get a version in a float format.
310 private String increaseMajorVersion(String version) {
312 String[] versionParts = version.split(ToscaElementLifecycleOperation.VERSION_DELIMITER_REGEXP);
313 Integer majorVersion = Integer.parseInt(versionParts[0]);
317 return String.valueOf(majorVersion);
321 public Either<List<GroupInstance>, StorageOperationStatus> updateGroupInstances(Component component, String instanceId, List<GroupInstance> updatedGroupInstances) {
323 Either<List<GroupInstance>, StorageOperationStatus> result = null;
324 StorageOperationStatus status = null;
326 Either<GraphVertex, TitanOperationStatus> getComponentVertex = titanDao.getVertexById(component.getUniqueId(), JsonParseFlagEnum.NoParse);
327 if (getComponentVertex.isRight()) {
328 result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(getComponentVertex.right().value()));
330 if (result == null) {
331 List<String> pathKeys = new ArrayList<>();
332 pathKeys.add(instanceId);
333 status = updateToscaDataDeepElementsOfToscaElement(component.getUniqueId(), EdgeLabelEnum.INST_GROUPS, VertexTypeEnum.INST_GROUPS, updatedGroupInstances, pathKeys, JsonPresentationFields.NAME);
334 if (status != StorageOperationStatus.OK) {
335 result = Either.right(status);
338 if (result == null) {
339 result = Either.left(updatedGroupInstances);
344 public Either<GroupDefinition, StorageOperationStatus> updateGroup(Component component, GroupDefinition currentGroup) {
345 StorageOperationStatus status = updateToscaDataOfToscaElement(component.getUniqueId(), EdgeLabelEnum.GROUPS, VertexTypeEnum.GROUPS, currentGroup, JsonPresentationFields.NAME);
346 if (status != StorageOperationStatus.OK) {
347 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to update group {} of component {}. The status is}. ", currentGroup.getName(), component.getName(), status);
348 return Either.right(status);
350 return Either.left(currentGroup);
353 public StorageOperationStatus deleteGroup(Component component, String currentGroupName) {
354 StorageOperationStatus status = deleteToscaDataElement(component.getUniqueId(), EdgeLabelEnum.GROUPS, VertexTypeEnum.GROUPS, currentGroupName, JsonPresentationFields.NAME);
355 if (status != StorageOperationStatus.OK) {
356 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to delete group {} of component {}. The status is}. ", currentGroupName, component.getName(), status);
361 public Either<GroupDefinition, StorageOperationStatus> addGroup(Component component, GroupDefinition currentGroup) {
362 StorageOperationStatus status = addToscaDataToToscaElement(component.getUniqueId(), EdgeLabelEnum.GROUPS, VertexTypeEnum.GROUPS, currentGroup, JsonPresentationFields.NAME);
363 if (status != StorageOperationStatus.OK) {
364 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to update group {} of component {}. The status is}. ", currentGroup.getName(), component.getName(), status);
365 return Either.right(status);
367 return Either.left(currentGroup);
370 public Either<GroupInstance, StorageOperationStatus> updateGroupInstancePropertyValuesOnGraph(String componentId, String instanceId, GroupInstance oldGroupInstance, List<GroupInstanceProperty> newProperties) {
372 Either<GraphVertex, TitanOperationStatus> getComponentVertex = titanDao.getVertexById(componentId, JsonParseFlagEnum.ParseMetadata);
373 if (getComponentVertex.isRight()) {
374 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to fetch component {}. Status is {} ", componentId);
375 return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(getComponentVertex.right().value()));
378 List<PropertyDataDefinition> propertiesOld = oldGroupInstance.getProperties();
379 newProperties.forEach(np -> {
380 Optional<PropertyDataDefinition> prop = propertiesOld.stream().filter(p -> p.getName().equals(np.getName())).findFirst();
381 if (prop.isPresent()) {
382 prop.get().setValue(np.getValue());
385 GroupInstanceDataDefinition groupInstanceDataDefinition = new GroupInstanceDataDefinition(oldGroupInstance);
386 List<String> pathKeys = new ArrayList<>();
387 pathKeys.add(instanceId);
388 StorageOperationStatus updateDataRes = updateToscaDataDeepElementOfToscaElement(componentId, EdgeLabelEnum.INST_GROUPS, VertexTypeEnum.INST_GROUPS, groupInstanceDataDefinition, pathKeys, JsonPresentationFields.NAME);
389 if (updateDataRes != StorageOperationStatus.OK) {
390 log.debug("Failed to update properties for group instance {} error {}", oldGroupInstance.getName(), updateDataRes);
391 return Either.right(updateDataRes);
393 return Either.left(oldGroupInstance);