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.components.impl;
23 import fj.data.Either;
24 import org.apache.commons.collections.CollectionUtils;
25 import org.apache.commons.collections.MapUtils;
26 import org.apache.commons.io.FilenameUtils;
27 import org.apache.commons.lang.StringUtils;
28 import org.apache.commons.lang3.math.NumberUtils;
29 import org.apache.commons.lang3.tuple.ImmutablePair;
30 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
31 import org.openecomp.sdc.be.components.impl.lock.LockingTransactional;
32 import org.openecomp.sdc.be.components.impl.policy.PolicyTargetsUpdateHandler;
33 import org.openecomp.sdc.be.components.utils.Utils;
34 import org.openecomp.sdc.be.components.validation.AccessValidations;
35 import org.openecomp.sdc.be.components.validation.ComponentValidations;
36 import org.openecomp.sdc.be.config.BeEcompErrorManager;
37 import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity;
38 import org.openecomp.sdc.be.config.ConfigurationManager;
39 import org.openecomp.sdc.be.dao.api.ActionStatus;
40 import org.openecomp.sdc.be.dao.titan.TitanOperationStatus;
41 import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition;
42 import org.openecomp.sdc.be.datatypes.elements.GroupDataDefinition;
43 import org.openecomp.sdc.be.datatypes.elements.PolicyTargetType;
44 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
45 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
46 import org.openecomp.sdc.be.datatypes.enums.CreatedFrom;
47 import org.openecomp.sdc.be.info.ArtifactDefinitionInfo;
48 import org.openecomp.sdc.be.info.ArtifactTemplateInfo;
49 import org.openecomp.sdc.be.info.GroupDefinitionInfo;
50 import org.openecomp.sdc.be.model.*;
51 import org.openecomp.sdc.be.model.PropertyDefinition.GroupInstancePropertyValueUpdateBehavior;
52 import org.openecomp.sdc.be.model.PropertyDefinition.PropertyNames;
53 import org.openecomp.sdc.be.model.jsontitan.operations.GroupsOperation;
54 import org.openecomp.sdc.be.model.jsontitan.operations.TopologyTemplateOperation;
55 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
56 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
57 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
58 import org.openecomp.sdc.common.api.Constants;
59 import org.openecomp.sdc.common.log.wrappers.Logger;
60 import org.openecomp.sdc.common.util.ValidationUtils;
61 import org.openecomp.sdc.exception.ResponseFormat;
62 import org.springframework.beans.factory.annotation.Autowired;
65 import java.util.Map.Entry;
66 import java.util.regex.Pattern;
67 import java.util.stream.Collectors;
69 import static java.util.stream.Collectors.toList;
70 import static org.openecomp.sdc.be.model.jsontitan.utils.ModelConverter.extractCapabilitiesFromGroups;
71 import static org.openecomp.sdc.be.model.jsontitan.utils.ModelConverter.extractCapabilityPropertiesFromGroups;
73 @org.springframework.stereotype.Component("groupBusinessLogic")
74 public class GroupBusinessLogic extends BaseBusinessLogic {
76 public static final String GROUP_DELIMITER_REGEX = "\\.\\.";
78 public static final String INITIAL_VERSION = "1";
80 private static final String ADDING_GROUP = "AddingGroup";
82 private static final String CREATE_GROUP = "CreateGroup";
84 private static final String UPDATE_GROUP = "UpdateGroup";
86 private static final String GET_GROUP = "GetGroup";
88 private static final String DELETE_GROUP = "DeleteGroup";
90 private static final Logger log = Logger.getLogger(GroupBusinessLogic.class);
92 private AccessValidations accessValidations;
94 @javax.annotation.Resource
96 private GroupsOperation groupsOperation;
99 PolicyTargetsUpdateHandler policyTargetsUpdateHandler;
101 private String getComponentTypeForResponse(org.openecomp.sdc.be.model.Component component) {
102 String componentTypeForResponse = "SERVICE";
103 if (component instanceof Resource) {
104 componentTypeForResponse = ((Resource) component).getResourceType().name();
106 return componentTypeForResponse;
110 * Verify that the artifact members belongs to the component
116 private Either<Boolean, ResponseFormat> verifyArtifactsBelongsToComponent(Component component, List<String> artifacts, String context) {
118 if (CollectionUtils.isEmpty(artifacts)) {
119 return Either.left(true);
122 Map<String, ArtifactDefinition> deploymentArtifacts = component.getDeploymentArtifacts();
123 if (MapUtils.isEmpty(deploymentArtifacts)) {
124 BeEcompErrorManager.getInstance().logInvalidInputError(context, "No deployment artifact found under component " + component.getNormalizedName(), ErrorSeverity.INFO);
125 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
128 List<String> currentArtifacts = deploymentArtifacts.values().stream().map(ArtifactDefinition::getUniqueId).collect(toList());
129 log.debug("The deployment artifacts of component {} are {}", component.getNormalizedName(), deploymentArtifacts);
130 if (!currentArtifacts.containsAll(artifacts)) {
131 BeEcompErrorManager.getInstance().logInvalidInputError(context, "Not all artifacts belongs to component " + component.getNormalizedName(), ErrorSeverity.INFO);
132 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
135 return Either.left(true);
140 * verify that the members are component instances of the component
143 * @param groupMembers
144 * @param memberToscaTypes
147 private Either<Boolean, ResponseFormat> verifyComponentInstancesAreValidMembers(Component component, String groupName, Map<String, String> groupMembers, List<String> memberToscaTypes) {
149 if (MapUtils.isEmpty(groupMembers)) {
150 return Either.left(true);
153 if (CollectionUtils.isEmpty(memberToscaTypes)) {
154 return Either.left(true);
157 List<ComponentInstance> componentInstances = component.getComponentInstances();
158 if (CollectionUtils.isNotEmpty(componentInstances)) {
159 Map<String, ComponentInstance> compInstUidToCompInstMap = componentInstances.stream().collect(Collectors.toMap(ComponentInstance::getUniqueId, p -> p));
161 Set<String> allCompInstances = compInstUidToCompInstMap.keySet();
163 for (Entry<String, String> groupMember : groupMembers.entrySet()) {
164 String compName = groupMember.getKey();
165 String compUid = groupMember.getValue();
167 if (!allCompInstances.contains(compUid)) {
169 * %1 - member name %2 - group name %3 - VF name %4 - component type [VF ]
171 String componentTypeForResponse = getComponentTypeForResponse(component);
173 BeEcompErrorManager.getInstance().logInvalidInputError(CREATE_GROUP, "Not all group members exists under the component", ErrorSeverity.INFO);
174 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_INVALID_COMPONENT_INSTANCE, compName, groupName, component.getNormalizedName(), componentTypeForResponse));
179 return Either.left(true);
185 * Update GroupDefinition metadata
189 * @param componentType
190 * @param updatedGroup
191 * @param inTransaction
194 public Either<GroupDefinition, ResponseFormat> validateAndUpdateGroupMetadata(String componentId, User user, ComponentTypeEnum componentType, GroupDefinition updatedGroup, boolean inTransaction , boolean shouldLock) {
196 Either<GroupDefinition, ResponseFormat> result = null;
198 // Validate user exist
199 validateUserExists(user.getUserId(), UPDATE_GROUP, inTransaction);
200 // Validate component exist
201 Either<? extends org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponent = validateComponentExists(componentId, componentType, null);
202 if (validateComponent.isRight()) {
203 result = Either.right(validateComponent.right().value());
206 org.openecomp.sdc.be.model.Component component = validateComponent.left().value();
207 // validate we can work on component
208 Either<Boolean, ResponseFormat> canWork = validateCanWorkOnComponent(component, user.getUserId());
209 if (canWork.isRight()) {
210 result = Either.right(canWork.right().value());
213 List<GroupDefinition> currentGroups = component.getGroups();
214 if (CollectionUtils.isEmpty(currentGroups)) {
215 log.error("Failed to update the metadata of group {} on component {}. The status is {}. ", updatedGroup.getName(), component.getName(), ActionStatus.GROUP_IS_MISSING);
216 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_IS_MISSING, updatedGroup.getName(), component.getName(), component.getComponentType().getValue()));
219 // Validate groups exists in the component
220 Optional<GroupDefinition> currentGroupOpt = currentGroups.stream().filter(g -> g.getUniqueId().equals(updatedGroup.getUniqueId())).findAny();
221 if (!currentGroupOpt.isPresent()) {
222 log.error("Failed to update the metadata of group {} on component {}. The status is {}. ", updatedGroup.getName(), component.getName(), ActionStatus.GROUP_IS_MISSING);
223 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_IS_MISSING, updatedGroup.getName(), component.getName(), component.getComponentType().getValue()));
226 GroupDefinition currentGroup = currentGroupOpt.get();
228 Either<Boolean, ResponseFormat> lockResult = lockComponent(componentId, component, "Update GroupDefinition Metadata");
229 if (lockResult.isRight()) {
230 result = Either.right(lockResult.right().value());
234 // Validate group type is vfModule
235 if (currentGroup.getType().equals(Constants.GROUP_TOSCA_HEAT)) {
236 log.error("Failed to update the metadata of group {}. Group type is {} and cannot be updated", currentGroup.getName(), currentGroup.getType());
237 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.GROUP_TYPE_IS_INVALID, updatedGroup.getType());
238 result = Either.right(responseFormat);
241 result = updateGroupMetadata(component, currentGroup, updatedGroup);
245 if (result != null && result.isLeft()) {
251 graphLockOperation.unlockComponent(componentId, componentType.getNodeType());
256 private Either<GroupDefinition, ResponseFormat> updateGroupMetadata(Component component, GroupDefinition currentGroup, GroupDefinition updatedGroup) {
257 String currentGroupName = currentGroup.getName();
258 Either<GroupDefinition, ResponseFormat> result = validateAndUpdateGroupMetadata(currentGroup, updatedGroup);
260 if (result.isRight()) {
261 log.debug("Failed to validate a metadata of the group {} on component {}. ", updatedGroup.getName(), component.getName());
263 if (result.isLeft()) {
264 result = updateGroup(component, currentGroup, currentGroupName);
269 private Either<GroupDefinition, ResponseFormat> updateGroup(Component component, GroupDefinition updatedGroup, String currentGroupName) {
270 Either<GroupDefinition, StorageOperationStatus> handleGroupRes;
271 Either<GroupDefinition, ResponseFormat> result = null;
272 if (updatedGroup.getName().equals(currentGroupName)) {
273 handleGroupRes = groupsOperation.updateGroup(component, updatedGroup);
274 if (handleGroupRes.isRight()) {
275 log.debug("Failed to update a metadata of the group {} on component {}. ", updatedGroup.getName(), component.getName());
276 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(handleGroupRes.right().value())));
279 StorageOperationStatus deleteStatus = groupsOperation.deleteGroup(component, currentGroupName);
280 if (deleteStatus != StorageOperationStatus.OK) {
281 log.debug("Failed to delete the group {} from component {}. ", updatedGroup.getName(), component.getName());
282 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(deleteStatus)));
284 handleGroupRes = groupsOperation.addGroup(component, updatedGroup);
285 if (handleGroupRes.isRight()) {
286 log.debug("Failed to add the group {} to component {}. ", updatedGroup.getName(), component.getName());
287 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(handleGroupRes.right().value())));
290 if (result == null) {
291 result = Either.left(updatedGroup);
297 * Validate and update GroupDefinition metadata
299 * @param currentGroup
303 private Either<GroupDefinition, ResponseFormat> validateAndUpdateGroupMetadata(GroupDefinition currentGroup, GroupDefinition groupUpdate) {
304 // Check if to update, and update GroupDefinition name.
305 Either<Boolean, ResponseFormat> response = validateAndUpdateGroupName(currentGroup, groupUpdate);
306 if (response.isRight()) {
307 ResponseFormat errorResponse = response.right().value();
308 return Either.right(errorResponse);
311 // Do not allow to update GroupDefinition version directly.
312 String versionUpdated = groupUpdate.getVersion();
313 String versionCurrent = currentGroup.getVersion();
314 if (versionUpdated != null && !versionCurrent.equals(versionUpdated)) {
315 log.info("update Group: recived request to update version to {} the field is not updatable ignoring.", versionUpdated);
318 return Either.left(currentGroup);
322 * Validate and update GroupDefinition name
324 * @param currentGroup
328 private Either<Boolean, ResponseFormat> validateAndUpdateGroupName(GroupDefinition currentGroup, GroupDefinition groupUpdate) {
329 String nameUpdated = groupUpdate.getName();
330 String nameCurrent = currentGroup.getName();
331 if (!nameCurrent.equals(nameUpdated)) {
332 Either<Boolean, ResponseFormat> validatNameResponse = validateGroupName(currentGroup.getName(), groupUpdate.getName() ,true);
333 if (validatNameResponse.isRight()) {
334 ResponseFormat errorRespons = validatNameResponse.right().value();
335 return Either.right(errorRespons);
337 currentGroup.setName(groupUpdate.getName());
339 return Either.left(true);
343 * Validate that group name to update is valid (same as current group name except for middle part). For example: Current group name: MyResource..MyDesc..Module-1 Group to update: MyResource..MyDesc2..Module-1 Verify that only the second part
344 * MyDesc was changed.
346 * @param currentGroupName
347 * @param groupUpdateName
350 private Either<Boolean, ResponseFormat> validateGroupName(String currentGroupName, String groupUpdateName , boolean isforceNameModification) {
352 // Check if the group name is in old format.
353 if (Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(groupUpdateName).matches()) {
354 log.error("Group name {} is in old format", groupUpdateName);
355 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_VF_MODULE_NAME, groupUpdateName));
358 // Check that name pats 1 and 3 did not changed (only the second
359 // part can be changed)
360 // But verify before that the current group format is the new one
361 if (!Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(currentGroupName).matches()) {
362 String[] split1 = currentGroupName.split(GROUP_DELIMITER_REGEX);
363 String currentResourceName = split1[0];
364 String currentCounter = split1[2];
366 String[] split2 = groupUpdateName.split(GROUP_DELIMITER_REGEX);
367 String groupUpdateResourceName = split2[0];
368 String groupUpdateCounter = split2[2];
369 if (!isforceNameModification){ //if not forced ,allow name prefix&suffix validation [no changes]
370 if (!currentResourceName.equals(groupUpdateResourceName)) {
371 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_VF_MODULE_NAME_MODIFICATION, currentResourceName));
374 if (!currentCounter.equals(groupUpdateCounter)) {
375 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_VF_MODULE_NAME_MODIFICATION, currentCounter));
381 return Either.left(true);
382 } catch (Exception e) {
383 log.error("Error valiadting group name", e);
384 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
390 * associate artifacts to a given group
394 * @param componentType
395 * @param inTransaction
398 public Either<GroupDefinitionInfo, ResponseFormat> getGroupWithArtifactsById(ComponentTypeEnum componentType, String componentId, String groupId, String userId, boolean inTransaction) {
400 Either<GroupDefinitionInfo, ResponseFormat> result = null;
402 // Validate user exist
403 validateUserExists(userId, GET_GROUP, true);
404 // Validate component exist
405 org.openecomp.sdc.be.model.Component component = null;
408 ComponentParametersView componentParametersView = new ComponentParametersView();
409 componentParametersView.disableAll();
410 componentParametersView.setIgnoreGroups(false);
411 componentParametersView.setIgnoreArtifacts(false);
412 componentParametersView.setIgnoreUsers(false);
414 Either<? extends org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponent = validateComponentExists(componentId, componentType, componentParametersView);
415 if (validateComponent.isRight()) {
416 result = Either.right(validateComponent.right().value());
419 component = validateComponent.left().value();
421 Either<GroupDefinition, StorageOperationStatus> groupEither = findGroupOnComponent(component, groupId);
423 if (groupEither.isRight()) {
424 log.debug("Faild to find group {} under component {}", groupId, component.getUniqueId());
425 BeEcompErrorManager.getInstance().logInvalidInputError(GET_GROUP, "group " + groupId + " not found under component " + component.getUniqueId(), ErrorSeverity.INFO);
426 String componentTypeForResponse = getComponentTypeForResponse(component);
427 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_IS_MISSING, groupId, component.getSystemName(), componentTypeForResponse));
430 GroupDefinition group = groupEither.left().value();
432 Boolean isBase = null;
433 List<GroupProperty> props = group.convertToGroupProperties();
434 if (props != null && !props.isEmpty()) {
435 Optional<GroupProperty> isBasePropOp = props.stream().filter(p -> p.getName().equals(Constants.IS_BASE)).findAny();
436 if (isBasePropOp.isPresent()) {
437 GroupProperty propIsBase = isBasePropOp.get();
438 isBase = Boolean.parseBoolean(propIsBase.getValue());
441 BeEcompErrorManager.getInstance().logInvalidInputError(GET_GROUP, "failed to find prop isBase " + component.getNormalizedName(), ErrorSeverity.INFO);
445 List<ArtifactDefinitionInfo> artifacts = new ArrayList<>();
446 List<ArtifactDefinition> artifactsFromComponent = new ArrayList<>();
447 List<String> artifactsIds = group.getArtifacts();
449 Map<String, ArtifactDefinition> deploymentArtifacts = null;
450 if (MapUtils.isNotEmpty(component.getDeploymentArtifacts())) {
451 deploymentArtifacts = component.getDeploymentArtifacts().values().stream().collect(Collectors.toMap(ArtifactDataDefinition::getUniqueId, a -> a));
454 if (artifactsIds != null && !artifactsIds.isEmpty()) {
455 for (String id : artifactsIds) {
456 if (deploymentArtifacts == null || !deploymentArtifacts.containsKey(id)) {
457 log.debug("Failed to get artifact {} . Status is {} ", id, StorageOperationStatus.NOT_FOUND);
458 ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(StorageOperationStatus.NOT_FOUND));
459 result = Either.right(responseFormat);
462 artifactsFromComponent.add(deploymentArtifacts.get(id));
464 if (!artifactsFromComponent.isEmpty()) {
465 for (ArtifactDefinition artifactDefinition : artifactsFromComponent) {
466 ArtifactDefinitionInfo artifactDefinitionInfo = new ArtifactDefinitionInfo(artifactDefinition);
467 artifacts.add(artifactDefinitionInfo);
472 GroupDefinitionInfo resultInfo = new GroupDefinitionInfo(group);
473 resultInfo.setIsBase(isBase);
474 if (!artifacts.isEmpty()) {
475 resultInfo.setArtifacts(artifacts);
477 result = Either.left(resultInfo);
483 if (!inTransaction) {
485 if (result == null || result.isRight()) {
486 log.debug("Going to execute rollback on create group.");
489 log.debug("Going to execute commit on create group.");
499 private Either<GroupDefinition, StorageOperationStatus> findGroupOnComponent(Component component, String groupId) {
501 Either<GroupDefinition, StorageOperationStatus> result = null;
502 if (CollectionUtils.isNotEmpty(component.getGroups())) {
503 Optional<GroupDefinition> foundGroup = component.getGroups().stream().filter(g -> g.getUniqueId().equals(groupId)).findFirst();
504 if (foundGroup.isPresent()) {
505 result = Either.left(foundGroup.get());
508 if (result == null) {
509 result = Either.right(StorageOperationStatus.NOT_FOUND);
514 public Either<Boolean, ResponseFormat> validateGenerateVfModuleGroupNames(List<ArtifactTemplateInfo> allGroups, String resourceSystemName, int startGroupCounter) {
515 Either<Boolean, ResponseFormat> validateGenerateGroupNamesRes = Either.left(true);
516 Collections.sort(allGroups, ArtifactTemplateInfo::compareByGroupName);
517 for (ArtifactTemplateInfo group : allGroups) {
518 Either<String, ResponseFormat> validateGenerateGroupNameRes = validateGenerateVfModuleGroupName(resourceSystemName, group.getDescription(), startGroupCounter++);
519 if (validateGenerateGroupNameRes.isRight()) {
520 validateGenerateGroupNamesRes = Either.right(validateGenerateGroupNameRes.right().value());
523 group.setGroupName(validateGenerateGroupNameRes.left().value());
525 return validateGenerateGroupNamesRes;
529 * Generate module name from resourceName, description and counter
531 * @param resourceSystemName
533 * @param groupCounter
536 private Either<String, ResponseFormat> validateGenerateVfModuleGroupName(String resourceSystemName, String description, int groupCounter) {
537 Either<String, ResponseFormat> validateGenerateGroupNameRes;
538 if (resourceSystemName != null && description != null && Pattern.compile(Constants.MODULE_DESC_PATTERN).matcher(description).matches()) {
539 final String fileName = description.replaceAll(GROUP_DELIMITER_REGEX, "\\.");
540 validateGenerateGroupNameRes = Either.left(String.format(Constants.MODULE_NAME_FORMAT, resourceSystemName, FilenameUtils.removeExtension(fileName), groupCounter));
542 validateGenerateGroupNameRes = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_VF_MODULE_NAME));
544 return validateGenerateGroupNameRes;
547 Either<Map<String, GroupDefinition>, ResponseFormat> validateUpdateVfGroupNames(Map<String, GroupDefinition> groups, String resourceSystemName) {
549 Map<String, GroupDefinition> updatedNamesGroups = new HashMap<>();
550 Either<Map<String, GroupDefinition>, ResponseFormat> result = Either.left(updatedNamesGroups);
551 for (Entry<String, GroupDefinition> groupEntry : groups.entrySet()) {
552 GroupDefinition curGroup = groupEntry.getValue();
553 String groupType = curGroup.getType();
554 String groupName = groupEntry.getKey();
557 Either<String, ResponseFormat> newGroupNameRes;
558 if (groupType.equals(Constants.DEFAULT_GROUP_VF_MODULE) && !Pattern.compile(Constants.MODULE_NEW_NAME_PATTERN).matcher(groupName).matches()) {
560 if (Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(groupEntry.getKey()).matches()) {
561 counter = Integer.parseInt(groupEntry.getKey().split(Constants.MODULE_NAME_DELIMITER)[1]);
562 description = curGroup.getDescription();
564 counter = getNextVfModuleNameCounter(updatedNamesGroups);
565 description = groupName;
567 newGroupNameRes = validateGenerateVfModuleGroupName(resourceSystemName, description, counter);
568 if (newGroupNameRes.isRight()) {
569 log.debug("Failed to generate new vf module group name. Status is {} ", newGroupNameRes.right().value());
570 result = Either.right(newGroupNameRes.right().value());
573 groupName = newGroupNameRes.left().value();
574 curGroup.setName(groupName);
576 updatedNamesGroups.put(groupName, curGroup);
581 public int getNextVfModuleNameCounter(Map<String, GroupDefinition> groups) {
583 if (groups != null && !groups.isEmpty()) {
584 counter = getNextVfModuleNameCounter(groups.values());
589 public int getNextVfModuleNameCounter(Collection<GroupDefinition> groups) {
591 if (groups != null && !groups.isEmpty()) {
592 List<Integer> counters = groups.stream().filter(group -> Pattern.compile(Constants.MODULE_NEW_NAME_PATTERN).matcher(group.getName()).matches() || Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(group.getName()).matches())
593 .map(group -> Integer.parseInt(group.getName().split(Constants.MODULE_NAME_DELIMITER)[1])).collect(toList());
594 counter = (counters == null || counters.isEmpty()) ? 0 : counters.stream().max(Integer::compare).get() + 1;
599 public Either<List<GroupDefinition>, ResponseFormat> validateUpdateVfGroupNamesOnGraph(List<GroupDefinition> groups, Component component) {
600 List<GroupDefinition> updatedGroups = new ArrayList<>();
601 Either<List<GroupDefinition>, ResponseFormat> result = Either.left(updatedGroups);
603 for (GroupDefinition group : groups) {
604 String groupType = group.getType();
605 String oldGroupName = group.getName();
607 Either<String, ResponseFormat> newGroupNameRes;
609 if (groupType.equals(Constants.DEFAULT_GROUP_VF_MODULE) && Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(oldGroupName).matches()) {
610 counter = Integer.parseInt(group.getName().split(Constants.MODULE_NAME_DELIMITER)[1]);
611 newGroupNameRes = validateGenerateVfModuleGroupName(component.getSystemName(), group.getDescription(), counter);
612 if (newGroupNameRes.isRight()) {
613 log.debug("Failed to generate new vf module group name. Status is {} ", newGroupNameRes.right().value());
614 result = Either.right(newGroupNameRes.right().value());
617 newGroupName = newGroupNameRes.left().value();
618 group.setName(newGroupName);
621 updatedGroups.add(group);
625 result = Either.left(updatedGroups);
630 public Either<GroupDefinitionInfo, ResponseFormat> getGroupInstWithArtifactsById(ComponentTypeEnum componentType, String componentId, String componentInstanceId, String groupInstId, String userId, boolean inTransaction) {
631 Either<GroupDefinitionInfo, ResponseFormat> result = null;
633 // Validate user exist
634 validateUserExists(userId, UPDATE_GROUP, true);
635 // Validate component exist
636 org.openecomp.sdc.be.model.Component component = null;
639 ComponentParametersView componentParametersView = new ComponentParametersView();
640 componentParametersView.disableAll();
641 componentParametersView.setIgnoreUsers(false);
642 componentParametersView.setIgnoreComponentInstances(false);
643 componentParametersView.setIgnoreArtifacts(false);
645 Either<? extends org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponent = validateComponentExists(componentId, componentType, componentParametersView);
646 if (validateComponent.isRight()) {
647 result = Either.right(validateComponent.right().value());
650 component = validateComponent.left().value();
651 Either<ImmutablePair<ComponentInstance, GroupInstance>, StorageOperationStatus> findComponentInstanceAndGroupInstanceRes = findComponentInstanceAndGroupInstanceOnComponent(component, componentInstanceId, groupInstId);
653 if (findComponentInstanceAndGroupInstanceRes.isRight()) {
654 log.debug("Failed to get group {} . Status is {} ", groupInstId, findComponentInstanceAndGroupInstanceRes.right().value());
655 ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(findComponentInstanceAndGroupInstanceRes.right().value()));
656 result = Either.right(responseFormat);
660 GroupInstance group = findComponentInstanceAndGroupInstanceRes.left().value().getRight();
662 Boolean isBase = null;
663 List<? extends GroupProperty> props = group.convertToGroupInstancesProperties();
664 if (props != null && !props.isEmpty()) {
665 Optional<? extends GroupProperty> isBasePropOp = props.stream().filter(p -> p.getName().equals(Constants.IS_BASE)).findAny();
666 if (isBasePropOp.isPresent()) {
667 GroupProperty propIsBase = isBasePropOp.get();
668 isBase = Boolean.parseBoolean(propIsBase.getValue());
671 BeEcompErrorManager.getInstance().logInvalidInputError(GET_GROUP, "failed to find prop isBase " + component.getNormalizedName(), ErrorSeverity.INFO);
675 List<ArtifactDefinitionInfo> artifacts = new ArrayList<>();
676 List<String> artifactsIds = group.getArtifacts();
677 if (artifactsIds != null && !artifactsIds.isEmpty()) {
679 List<ComponentInstance> instances = component.getComponentInstances();
680 if (instances != null) {
681 Optional<ComponentInstance> findFirst = instances.stream().filter(i -> i.getUniqueId().equals(componentInstanceId)).findFirst();
682 if (findFirst.isPresent()) {
683 ComponentInstance ci = findFirst.get();
684 Map<String, ArtifactDefinition> deploymentArtifacts = ci.getDeploymentArtifacts();
685 for (String id : artifactsIds) {
686 Optional<ArtifactDefinition> artOp = deploymentArtifacts.values().stream().filter(a -> a.getUniqueId().equals(id)).findFirst();
687 if (artOp.isPresent()) {
688 artifacts.add(new ArtifactDefinitionInfo(artOp.get()));
691 List<String> instArtifactsIds = group.getGroupInstanceArtifacts();
692 for (String id : instArtifactsIds) {
693 Optional<ArtifactDefinition> artOp = deploymentArtifacts.values().stream().filter(a -> a.getUniqueId().equals(id)).findFirst();
694 if (artOp.isPresent()) {
695 artifacts.add(new ArtifactDefinitionInfo(artOp.get()));
702 GroupDefinitionInfo resultInfo = new GroupDefinitionInfo(group);
703 resultInfo.setIsBase(isBase);
704 if (!artifacts.isEmpty()) {
705 resultInfo.setArtifacts(artifacts);
707 result = Either.left(resultInfo);
713 if (!inTransaction) {
715 if (result == null || result.isRight()) {
716 log.debug("Going to execute rollback on create group.");
719 log.debug("Going to execute commit on create group.");
728 private Either<ImmutablePair<ComponentInstance, GroupInstance>, StorageOperationStatus> findComponentInstanceAndGroupInstanceOnComponent(Component component, String componentInstanceId, String groupInstId) {
730 Either<ImmutablePair<ComponentInstance, GroupInstance>, StorageOperationStatus> result = null;
731 if (CollectionUtils.isNotEmpty(component.getComponentInstances())) {
732 Optional<GroupInstance> foundGroup;
733 Optional<ComponentInstance> foundComponent = component.getComponentInstances().stream().filter(ci -> ci.getUniqueId().equals(componentInstanceId)).findFirst();
734 if (foundComponent.isPresent() && CollectionUtils.isNotEmpty(foundComponent.get().getGroupInstances())) {
735 foundGroup = foundComponent.get().getGroupInstances().stream().filter(gi -> gi.getUniqueId().equals(groupInstId)).findFirst();
736 if (foundGroup.isPresent()) {
737 result = Either.left(new ImmutablePair<>(foundComponent.get(), foundGroup.get()));
741 if (result == null) {
742 result = Either.right(StorageOperationStatus.NOT_FOUND);
747 private Either<Boolean, ResponseFormat> validateMinMaxAndInitialCountPropertyLogic(Map<PropertyNames, String> newValues, Map<PropertyNames, String> currValues, Map<PropertyNames, String> parentValues) {
749 Either<Boolean, ResponseFormat> result;
750 for (Entry<PropertyNames, String> entry : newValues.entrySet()) {
751 PropertyNames currPropertyName = entry.getKey();
752 if (currPropertyName == PropertyNames.MIN_INSTANCES) {
753 String minValue = parentValues.get(PropertyNames.MIN_INSTANCES);
754 String maxValue = newValues.containsKey(PropertyNames.INITIAL_COUNT) ? newValues.get(PropertyNames.MAX_INSTANCES) : currValues.get(PropertyNames.INITIAL_COUNT);
755 result = validateValueInRange(new ImmutablePair<>(currPropertyName, entry.getValue()), new ImmutablePair<>(PropertyNames.MIN_INSTANCES, minValue),
756 new ImmutablePair<>(PropertyNames.MAX_INSTANCES, maxValue));
757 if (result.isRight()) {
760 } else if (currPropertyName == PropertyNames.INITIAL_COUNT) {
761 String minValue = newValues.containsKey(PropertyNames.MIN_INSTANCES) ? newValues.get(PropertyNames.MIN_INSTANCES) : currValues.get(PropertyNames.MIN_INSTANCES);
762 String maxValue = newValues.containsKey(PropertyNames.MAX_INSTANCES) ? newValues.get(PropertyNames.MAX_INSTANCES) : currValues.get(PropertyNames.MAX_INSTANCES);
763 result = validateValueInRange(new ImmutablePair<>(currPropertyName, entry.getValue()), new ImmutablePair<>(PropertyNames.MIN_INSTANCES, minValue),
764 new ImmutablePair<>(PropertyNames.MAX_INSTANCES, maxValue));
765 if (result.isRight()) {
768 } else if (currPropertyName == PropertyNames.MAX_INSTANCES) {
769 String minValue = newValues.containsKey(PropertyNames.INITIAL_COUNT) ? newValues.get(PropertyNames.MIN_INSTANCES) : currValues.get(PropertyNames.INITIAL_COUNT);
770 String maxValue = parentValues.get(PropertyNames.MAX_INSTANCES);
771 result = validateValueInRange(new ImmutablePair<>(currPropertyName, entry.getValue()), new ImmutablePair<>(PropertyNames.MIN_INSTANCES, minValue),
772 new ImmutablePair<>(PropertyNames.MAX_INSTANCES, maxValue));
773 if (result.isRight()) {
778 return Either.left(true);
781 private Either<Boolean, ResponseFormat> validateValueInRange(ImmutablePair<PropertyNames, String> newValue, ImmutablePair<PropertyNames, String> min, ImmutablePair<PropertyNames, String> max) {
782 Either<Boolean, ResponseFormat> result;
783 final String warnMessage = "Failed to validate {} as property value of {}. It must be not higher than {}, and not lower than {}.";
784 int newValueInt = parseIntValue(newValue.getValue(), newValue.getKey());
785 int minInt = parseIntValue(min.getValue(), min.getKey());
786 int maxInt = parseIntValue(max.getValue(), max.getKey());
787 if (newValueInt < 0 || minInt < 0 || maxInt < 0) {
788 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_PROPERTY));
789 } else if (newValueInt < minInt || newValueInt > maxInt) {
790 log.debug(warnMessage, newValue.getValue(), newValue.getKey().getPropertyName(), min.getValue(), max.getValue());
792 .right(componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_MIN_MAX_INSTANCES_PROPERTY_VALUE, newValue.getKey().getPropertyName(), maxInt == Integer.MAX_VALUE ? Constants.UNBOUNDED : max.getValue(), min.getValue()));
794 result = Either.left(true);
799 private int parseIntValue(String value, PropertyNames propertyName) {
801 if (propertyName == PropertyNames.MAX_INSTANCES) {
802 result = convertIfUnboundMax(value);
803 } else if (NumberUtils.isNumber(value)) {
804 result = Integer.parseInt(value);
812 * validates received new property values and updates group instance in case of success
814 * @param oldGroupInstance
815 * @param newProperties
818 public Either<GroupInstance, ResponseFormat> validateAndUpdateGroupInstancePropertyValues(String componentId, String instanceId, GroupInstance oldGroupInstance, List<GroupInstanceProperty> newProperties) {
820 Either<GroupInstance, ResponseFormat> actionResult = null;
821 Either<GroupInstance, StorageOperationStatus> updateGroupInstanceResult = null;
822 Either<List<GroupInstanceProperty>, ResponseFormat> validateRes = validateReduceGroupInstancePropertiesBeforeUpdate(oldGroupInstance, newProperties);
823 if (validateRes.isRight()) {
824 log.debug("Failed to validate group instance {} properties before update. ", oldGroupInstance.getName());
825 actionResult = Either.right(validateRes.right().value());
827 if (actionResult == null) {
828 List<GroupInstanceProperty> validatedReducedNewProperties = validateRes.left().value();
829 updateGroupInstanceResult = groupsOperation.updateGroupInstancePropertyValuesOnGraph(componentId, instanceId, oldGroupInstance, validatedReducedNewProperties);
830 if (updateGroupInstanceResult.isRight()) {
831 log.debug("Failed to update group instance {} property values. ", oldGroupInstance.getName());
832 actionResult = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(updateGroupInstanceResult.right().value())));
835 if (actionResult == null) {
836 actionResult = Either.left(updateGroupInstanceResult.left().value());
841 private Either<List<GroupInstanceProperty>, ResponseFormat> validateReduceGroupInstancePropertiesBeforeUpdate(GroupInstance oldGroupInstance, List<GroupInstanceProperty> newProperties) {
843 Either<Boolean, ResponseFormat> validationRes = null;
844 Either<List<GroupInstanceProperty>, ResponseFormat> actionResult;
845 Map<String, GroupInstanceProperty> existingProperties = oldGroupInstance.convertToGroupInstancesProperties().stream().collect(Collectors.toMap(PropertyDataDefinition::getName, p -> p));
846 Map<PropertyNames, String> newPropertyValues = new EnumMap<>(PropertyNames.class);
847 List<GroupInstanceProperty> reducedProperties = new ArrayList<>();
848 String currPropertyName;
850 for (GroupInstanceProperty currNewProperty : newProperties) {
851 currPropertyName = currNewProperty.getName();
852 validationRes = handleAndAddProperty(reducedProperties, newPropertyValues, currNewProperty, existingProperties.get(currPropertyName));
853 if (validationRes.isRight()) {
854 log.debug("Failed to handle property {} of group instance {}. ", currPropertyName, oldGroupInstance.getName());
858 if (validationRes == null || validationRes.isLeft()) {
859 Map<PropertyNames, String> existingPropertyValues = new EnumMap<>(PropertyNames.class);
860 Map<PropertyNames, String> parentPropertyValues = new EnumMap<>(PropertyNames.class);
861 fillValuesAndParentValuesFromExistingProperties(existingProperties, existingPropertyValues, parentPropertyValues);
862 validationRes = validateMinMaxAndInitialCountPropertyLogic(newPropertyValues, existingPropertyValues, parentPropertyValues);
864 if (validationRes.isLeft()) {
865 actionResult = Either.left(reducedProperties);
867 actionResult = Either.right(validationRes.right().value());
869 } catch (Exception e) {
870 log.error("Exception occured during validation and reducing group instance properties. The message is {}", e.getMessage(), e);
871 actionResult = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
876 private void fillValuesAndParentValuesFromExistingProperties(Map<String, GroupInstanceProperty> existingProperties, Map<PropertyNames, String> propertyValues, Map<PropertyNames, String> parentPropertyValues) {
877 PropertyNames[] allPropertyNames = PropertyNames.values();
878 for (PropertyNames name : allPropertyNames) {
879 if (isUpdatable(name)) {
880 propertyValues.put(name, String.valueOf(existingProperties.get(name.getPropertyName()).getValue()));
881 parentPropertyValues.put(name, String.valueOf(existingProperties.get(name.getPropertyName()).getParentValue()));
886 private Either<Boolean, ResponseFormat> handleAndAddProperty(List<GroupInstanceProperty> reducedProperties, Map<PropertyNames, String> newPropertyValues, GroupInstanceProperty currNewProperty, GroupInstanceProperty currExistingProperty) {
888 Either<Boolean, ResponseFormat> validationRes = null;
889 String currPropertyName = currNewProperty.getName();
890 PropertyNames propertyName = PropertyNames.findName(currPropertyName);
892 if (currExistingProperty == null) {
893 log.warn("The value of property with the name {} cannot be updated. The property not found on group instance. ", currPropertyName);
894 } else if (isUpdatable(propertyName)) {
895 validationRes = validateAndUpdatePropertyValue(currNewProperty, currExistingProperty);
896 if (validationRes.isRight()) {
897 log.debug("Failed to validate property value {} of property {}. ", currNewProperty.getValue(), currPropertyName);
899 addPropertyUpdatedValues(reducedProperties, propertyName, newPropertyValues, currNewProperty, currExistingProperty);
902 validateImmutableProperty(currExistingProperty, currNewProperty);
904 if (validationRes == null) {
905 validationRes = Either.left(true);
907 } catch (Exception e) {
908 log.error("Exception occured during handle and adding property. The message is {}", e.getMessage(), e);
909 validationRes = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
911 return validationRes;
914 private boolean isUpdatable(PropertyNames updatablePropertyName) {
915 return updatablePropertyName != null && updatablePropertyName.getUpdateBehavior().getLevelNumber() >= GroupInstancePropertyValueUpdateBehavior.UPDATABLE_ON_SERVICE_LEVEL.getLevelNumber();
918 private void addPropertyUpdatedValues(List<GroupInstanceProperty> reducedProperties, PropertyNames propertyName, Map<PropertyNames, String> newPropertyValues, GroupInstanceProperty newProperty, GroupInstanceProperty existingProperty) {
920 String newValue = newProperty.getValue();
921 if (!newValue.equals(String.valueOf(existingProperty.getValue()))) {
922 newProperty.setValueUniqueUid(existingProperty.getValueUniqueUid());
923 reducedProperties.add(newProperty);
925 if (!isEmptyMinInitialCountValue(propertyName, newValue)) {
926 newPropertyValues.put(propertyName, newValue);
930 private boolean isEmptyMinInitialCountValue(PropertyNames propertyName, String newValue) {
931 boolean result = false;
932 if ((propertyName == PropertyNames.MIN_INSTANCES || propertyName == PropertyNames.INITIAL_COUNT) && !NumberUtils.isNumber(newValue)) {
938 private int convertIfUnboundMax(String value) {
941 if (!NumberUtils.isNumber(value)) {
942 result = Integer.MAX_VALUE;
944 result = Integer.parseInt(value);
949 private Either<Boolean, ResponseFormat> validateAndUpdatePropertyValue(GroupInstanceProperty newProperty, GroupInstanceProperty existingProperty) {
951 Either<Boolean, ResponseFormat> validationRes = null;
952 String parentValue = existingProperty.getParentValue();
954 newProperty.setParentValue(parentValue);
955 if (StringUtils.isEmpty(newProperty.getValue())) {
956 newProperty.setValue(parentValue);
958 if (StringUtils.isEmpty(existingProperty.getValue())) {
959 existingProperty.setValue(parentValue);
961 StorageOperationStatus status = groupOperation.validateAndUpdatePropertyValue(newProperty);
962 if (status != StorageOperationStatus.OK) {
963 log.debug("Failed to validate property value {} of property with name {}. Status is {}. ", newProperty.getValue(), newProperty.getName(), status);
964 validationRes = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(status)));
966 if (validationRes == null) {
967 validationRes = Either.left(true);
969 return validationRes;
972 private void validateImmutableProperty(GroupProperty oldProperty, GroupProperty newProperty) {
973 if (oldProperty.getValue() == null && newProperty.getValue() != null || oldProperty.getValue() != null && !oldProperty.getValue().equals(newProperty.getValue())) {
974 log.warn("The value of property with the name {} cannot be updated on service level. Going to ignore new property value {}. ", oldProperty.getName(), newProperty.getValue());
978 @LockingTransactional
979 public GroupDefinition createGroup(String componentId, ComponentTypeEnum componentTypeEnum, String groupType,
982 Component component = accessValidations.validateUserCanWorkOnComponent(componentId, componentTypeEnum, userId, CREATE_GROUP);
984 validateGroupTypePerComponent(groupType, component);
986 GroupTypeDefinition groupTypeDefinition = groupTypeOperation.getLatestGroupTypeByType(groupType, false)
988 .on(se -> onGroupTypeNotFound(component));
990 boolean hasExistingGroups = CollectionUtils.isNotEmpty(component.getGroups());
991 GroupDefinition groupDefinition = new GroupDefinition();
992 groupDefinition.setType(groupType);
994 //find next valid counter
996 if (hasExistingGroups) {
997 nextCounter = getNewGroupCounter(component);
999 String name = TopologyTemplateOperation.buildSubComponentName(component.getName(), groupType, nextCounter);
1000 groupDefinition.setName(name);
1001 groupDefinition.setDescription(groupTypeDefinition.getDescription());
1002 groupDefinition.setInvariantName(name);
1003 groupDefinition.setCreatedFrom(CreatedFrom.UI);
1005 //Add default type properties
1006 List<PropertyDefinition> groupTypeProperties = groupTypeDefinition.getProperties();
1007 List<GroupProperty> properties = groupTypeProperties.stream()
1008 .map(GroupProperty::new)
1010 groupDefinition.convertFromGroupProperties(properties);
1012 groupDefinition.convertCapabilityDefinitions(groupTypeDefinition.getCapabilities());
1014 List<GroupDefinition> gdList;
1015 if (toscaOperationFacade.canAddGroups(componentId)) {
1016 gdList = addGroups(component, Arrays.asList(groupDefinition), false)
1018 .on(this::onFailedGroupDBOperation);
1020 //createGroups also creates an edge and vertex to store group data
1021 gdList = createGroups(component, Arrays.asList(groupDefinition), false)
1023 .on(this::onFailedGroupDBOperation);
1025 return gdList.get(0);
1028 private void validateGroupTypePerComponent(String groupType, Component component) {
1029 String specificType = component.getComponentMetadataDefinition().getMetadataDataDefinition().getActualComponentType();
1030 if (!component.isTopologyTemplate()) {
1031 throw new ComponentException(ActionStatus.GROUP_TYPE_ILLEGAL_PER_COMPONENT, groupType,
1034 Map<String, Set<String>> excludedGroupTypesMap = ConfigurationManager.getConfigurationManager().getConfiguration()
1035 .getExcludedGroupTypesMapping();
1037 if (MapUtils.isNotEmpty(excludedGroupTypesMap) && StringUtils.isNotEmpty(specificType)) {
1038 Set<String> excludedGroupTypesPerComponent = excludedGroupTypesMap.get(specificType);
1039 if (excludedGroupTypesPerComponent!=null && excludedGroupTypesPerComponent.contains(groupType)) {
1040 throw new ComponentException(ActionStatus.GROUP_TYPE_ILLEGAL_PER_COMPONENT, groupType, specificType);
1045 private int getNewGroupCounter(Component component) {
1046 List<String> existingNames = component.getGroups()
1048 .map(GroupDataDefinition::getName)
1050 List<String> existingIds = component.getGroups()
1052 .map(GroupDataDefinition::getUniqueId)
1054 existingIds.addAll(existingNames);
1056 return Utils.getNextCounter(existingIds);
1059 @LockingTransactional
1060 public GroupDefinition updateGroup(String componentId, ComponentTypeEnum componentTypeEnum, String groupId,
1061 String userId, GroupDefinition updatedGroup) {
1062 Component component = accessValidations.validateUserCanWorkOnComponent(componentId, componentTypeEnum, userId, UPDATE_GROUP);
1064 GroupDefinition existingGroup = findGroupOnComponent(component, groupId)
1066 .on(se -> onGroupNotFoundInComponentError(component, groupId));
1068 String existingGroupName = existingGroup.getName();
1069 String updatedGroupName = updatedGroup.getName();
1070 assertNewNameIsValidAndUnique(existingGroupName, updatedGroupName, component);
1071 existingGroup.setName(updatedGroupName);
1073 return updateGroup(component, existingGroup, existingGroupName)
1075 .on(this::onFailedUpdateGroupDBOperation);
1078 private void assertNewNameIsValidAndUnique(String currentGroupName, String updatedGroupName, Component component) {
1079 if (!ValidationUtils.validateResourceInstanceNameLength(updatedGroupName)) {
1080 throw new ComponentException(ActionStatus.EXCEEDS_LIMIT, "Group Name", ValidationUtils.RSI_NAME_MAX_LENGTH.toString());
1082 if (!ValidationUtils.validateResourceInstanceName(updatedGroupName)) {
1083 throw new ComponentException(ActionStatus.INVALID_VF_MODULE_NAME, updatedGroupName);
1085 if (!ComponentValidations.validateNameIsUniqueInComponent(currentGroupName, updatedGroupName, component)) {
1086 throw new ComponentException(ActionStatus.COMPONENT_NAME_ALREADY_EXIST, "Group", updatedGroupName);
1090 @LockingTransactional
1091 public GroupDefinition deleteGroup(String componentId, ComponentTypeEnum componentTypeEnum, String groupId,
1093 Component component = accessValidations.validateUserCanWorkOnComponent(componentId, componentTypeEnum, userId, DELETE_GROUP);
1095 GroupDefinition groupDefinition = findGroupOnComponent(component, groupId)
1097 .on(se -> onGroupNotFoundInComponentError(component, groupId));
1099 List<GroupDefinition> gdList = deleteGroups(component, java.util.Arrays.asList(groupDefinition))
1101 .on(this::onFailedGroupDBOperation);
1103 updatePolicyTargetReferencingDeletedGroup(groupId, component);
1104 return gdList.get(0);
1107 private List<GroupDefinition> onFailedGroupDBOperation(ResponseFormat responseFormat) {
1108 titanDao.rollback();
1109 throw new ComponentException(responseFormat);
1112 private GroupDefinition onFailedUpdateGroupDBOperation(ResponseFormat responseFormat) {
1113 titanDao.rollback();
1114 throw new ComponentException(responseFormat);
1117 private GroupDefinition onGroupNotFoundInComponentError(Component component, String groupId) {
1118 throw new ComponentException(ActionStatus.GROUP_IS_MISSING, groupId,
1119 component.getSystemName(), getComponentTypeForResponse(component));
1122 private GroupTypeDefinition onGroupTypeNotFound(Component component) {
1123 throw new ComponentException(ActionStatus.GROUP_TYPE_IS_INVALID, component.getSystemName(),
1124 component.getComponentType().toString());
1127 private void updatePolicyTargetReferencingDeletedGroup(String groupId, Component component) {
1128 log.debug("#updatePolicyTargetReferencingDeletedGroup - removing all component {} policy targets referencing group {}", component.getUniqueId(), groupId);
1129 ActionStatus actionStatus = policyTargetsUpdateHandler.removePoliciesTargets(component, groupId, PolicyTargetType.GROUPS);
1130 if (ActionStatus.OK != actionStatus) {
1131 titanDao.rollback();
1132 throw new ComponentException(actionStatus, groupId);
1137 public Either<List<GroupDefinition>, ResponseFormat> createGroups(Component component, final List<GroupDefinition> groupDefinitions, boolean fromCsar) {
1139 Map<String, GroupDataDefinition> groups = new HashMap<>();
1140 Either<List<GroupDefinition>, ResponseFormat> result = null;
1141 Either<List<GroupDefinition>, StorageOperationStatus> createGroupsResult = null;
1142 Either<Map<String, DataTypeDefinition>, TitanOperationStatus> allDataTypes = dataTypeCache.getAll();
1143 if (allDataTypes.isRight()) {
1144 TitanOperationStatus status = allDataTypes.right().value();
1145 BeEcompErrorManager.getInstance().logInternalFlowError("AddPropertyToGroup", "Failed to add property to group. Status is " + status, ErrorSeverity.ERROR);
1146 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(DaoStatusConverter.convertTitanStatusToStorageStatus(status))));
1150 // handle groups and convert to tosca data
1151 if (groupDefinitions != null && !groupDefinitions.isEmpty()) {
1152 for (GroupDefinition groupDefinition : groupDefinitions) {
1153 Either<GroupDefinition, ResponseFormat> handleGroupRes = handleGroup(component, groupDefinition, allDataTypes.left().value());
1154 if (handleGroupRes.isRight()) {
1155 result = Either.right(handleGroupRes.right().value());
1158 GroupDefinition handledGroup = handleGroupRes.left().value();
1159 groups.put(handledGroup.getName(), new GroupDataDefinition(handledGroup));
1163 if (result == null) {
1164 createGroupsResult = groupsOperation.createGroups(component, groups);
1165 if (createGroupsResult.isRight()) {
1166 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(createGroupsResult.right().value())));
1169 if (result == null) {
1170 addCalculatedCapabilitiesWithPropertiesToComponent(component, groupDefinitions, fromCsar);
1172 if (result == null) {
1173 result = Either.left(groupDefinitions);
1178 private void updateCalculatedCapabilitiesWithPropertiesOnComponent(Component component, final List<GroupDefinition> groupDefinitions, boolean fromCsar) {
1179 groupDefinitions.forEach(GroupDefinition::updateEmptyCapabilitiesOwnerFields);
1180 StorageOperationStatus status = groupsOperation.updateCalculatedCapabilitiesWithProperties(component.getUniqueId(),
1181 extractCapabilitiesFromGroups(groupDefinitions), extractCapabilityPropertiesFromGroups(groupDefinitions, fromCsar));
1182 if(status != StorageOperationStatus.OK){
1183 log.error("#updateCalculatedCapabilitiesWithPropertiesOnComponent - failed to update the groups' calculated capabilities with the properties on the component {}. ", component.getUniqueId());
1184 rollbackWithException(componentsUtils.convertFromStorageResponse(status));
1188 private void addCalculatedCapabilitiesWithPropertiesToComponent(Component component, final List<GroupDefinition> groupDefinitions, boolean fromCsar) {
1189 groupDefinitions.forEach(GroupDefinition::updateEmptyCapabilitiesOwnerFields);
1190 StorageOperationStatus status = groupsOperation.addCalculatedCapabilitiesWithProperties(component.getUniqueId(),
1191 extractCapabilitiesFromGroups(groupDefinitions), extractCapabilityPropertiesFromGroups(groupDefinitions, fromCsar));
1192 if(status != StorageOperationStatus.OK){
1193 log.error("#addCalculatedCapabilitiesWithPropertiesToComponent - failed to add the groups' calculated capabilities with the properties to the component {}. ", component.getUniqueId());
1194 rollbackWithException(componentsUtils.convertFromStorageResponse(status));
1198 private void deleteCalculatedCapabilitiesWithPropertiesFromComponent(Component component, final List<GroupDefinition> groupDefinitions) {
1199 StorageOperationStatus status = groupsOperation.deleteCalculatedCapabilitiesWithProperties(component.getUniqueId(), groupDefinitions);
1200 if(status != StorageOperationStatus.OK){
1201 log.error("#deleteCalculatedCapabilitiesWithPropertiesFromComponent - failed to remove the groups' calculated capabilities with the properties from the component {}. ", component.getUniqueId());
1202 rollbackWithException(componentsUtils.convertFromStorageResponse(status));
1206 public Either<List<GroupDefinition>, ResponseFormat> addGroups(Component component, final List<GroupDefinition> groupDefinitions, boolean fromCsar) {
1208 Either<List<GroupDefinition>, ResponseFormat> result = null;
1209 Either<List<GroupDefinition>, StorageOperationStatus> createGroupsResult = null;
1210 List<GroupDataDefinition> groups = new ArrayList<>();
1212 Either<Map<String, DataTypeDefinition>, TitanOperationStatus> allDataTypes = dataTypeCache.getAll();
1213 if (allDataTypes.isRight()) {
1214 TitanOperationStatus status = allDataTypes.right().value();
1215 BeEcompErrorManager.getInstance().logInternalFlowError("AddPropertyToGroup", "Failed to add property to group. Status is " + status, ErrorSeverity.ERROR);
1216 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(DaoStatusConverter.convertTitanStatusToStorageStatus(status))));
1220 // handle groups and convert to tosca data
1221 if (groupDefinitions != null && !groupDefinitions.isEmpty()) {
1222 for (GroupDefinition groupDefinition : groupDefinitions) {
1223 Either<GroupDefinition, ResponseFormat> handleGroupRes = handleGroup(component, groupDefinition, allDataTypes.left().value());
1224 if (handleGroupRes.isRight()) {
1225 result = Either.right(handleGroupRes.right().value());
1228 GroupDefinition handledGroup = handleGroupRes.left().value();
1229 groups.add(new GroupDataDefinition(handledGroup));
1232 if (result == null) {
1233 createGroupsResult = groupsOperation.addGroups(component, groups);
1234 if (createGroupsResult.isRight()) {
1235 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(createGroupsResult.right().value())));
1238 if (result == null) {
1239 addCalculatedCapabilitiesWithPropertiesToComponent(component, groupDefinitions, fromCsar);
1241 if (result == null) {
1242 result = Either.left(groupDefinitions);
1247 public Either<List<GroupDefinition>, ResponseFormat> deleteGroups(Component component, List<GroupDefinition> groupDefinitions) {
1249 Either<List<GroupDefinition>, StorageOperationStatus> deleteGroupsResult;
1251 deleteGroupsResult = groupsOperation.deleteGroups(component, groupDefinitions.stream().map(GroupDataDefinition::new).collect(toList()));
1252 if (deleteGroupsResult.isRight()) {
1253 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(deleteGroupsResult.right().value())));
1255 deleteCalculatedCapabilitiesWithPropertiesFromComponent(component, groupDefinitions);
1257 return Either.left(deleteGroupsResult.left().value());
1261 * Update specific group version
1262 * @param fromCsar TODO
1265 public Either<List<GroupDefinition>, ResponseFormat> updateGroups(Component component, List<GroupDefinition> groupDefinitions, boolean fromCsar) {
1267 Either<List<GroupDefinition>, ResponseFormat> result = null;
1268 Either<List<GroupDefinition>, StorageOperationStatus> createGroupsResult;
1270 createGroupsResult = groupsOperation.updateGroups(component, groupDefinitions.stream().map(GroupDataDefinition::new).collect(toList()), true);
1271 if (createGroupsResult.isRight()) {
1272 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(createGroupsResult.right().value())));
1274 if (result == null) {
1275 updateCalculatedCapabilitiesWithPropertiesOnComponent(component, groupDefinitions, fromCsar);
1277 if (result == null) {
1278 result = Either.left(groupDefinitions);
1283 private Either<GroupDefinition, ResponseFormat> handleGroup(Component component, GroupDefinition groupDefinition, Map<String, DataTypeDefinition> allDAtaTypes) {
1285 log.trace("Going to create group {}", groupDefinition);
1286 // 3. verify group not already exist
1287 String groupDefinitionName = groupDefinition.getName();
1288 if (groupExistsInComponent(groupDefinitionName, component)) {
1289 String componentTypeForResponse = getComponentTypeForResponse(component);
1290 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_ALREADY_EXIST, groupDefinitionName, component.getNormalizedName(), componentTypeForResponse));
1292 // 4. verify type of group exist
1293 String groupType = groupDefinition.getType();
1294 if (StringUtils.isEmpty(groupType)) {
1295 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_MISSING_GROUP_TYPE, groupDefinitionName));
1297 Either<GroupTypeDefinition, StorageOperationStatus> getGroupType = groupTypeOperation.getLatestGroupTypeByType(groupType, true);
1298 if (getGroupType.isRight()) {
1299 StorageOperationStatus status = getGroupType.right().value();
1300 if (status == StorageOperationStatus.NOT_FOUND) {
1301 BeEcompErrorManager.getInstance().logInvalidInputError(CREATE_GROUP, "group type " + groupType + " cannot be found", ErrorSeverity.INFO);
1302 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_TYPE_IS_INVALID, groupType));
1304 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
1307 // 6. verify the component instances type are allowed according to
1308 // the member types in the group type
1309 GroupTypeDefinition groupTypeDefinition = getGroupType.left().value();
1311 Either<Boolean, ResponseFormat> areValidMembers = verifyComponentInstancesAreValidMembers(component, groupDefinitionName, groupDefinition.getMembers(), groupTypeDefinition.getMembers());
1313 if (areValidMembers.isRight()) {
1314 ResponseFormat responseFormat = areValidMembers.right().value();
1315 return Either.right(responseFormat);
1317 // 7. verify the artifacts belongs to the component
1318 Either<Boolean, ResponseFormat> areValidArtifacts = verifyArtifactsBelongsToComponent(component, groupDefinition.getArtifacts(), CREATE_GROUP);
1319 if (areValidArtifacts.isRight()) {
1320 ResponseFormat responseFormat = areValidArtifacts.right().value();
1321 return Either.right(responseFormat);
1323 List<PropertyDefinition> groupTypeProperties = groupTypeDefinition.getProperties();
1325 List<GroupProperty> properties = groupDefinition.convertToGroupProperties();
1326 List<GroupProperty> updatedGroupTypeProperties = new ArrayList<>();
1327 if (CollectionUtils.isNotEmpty(properties)) {
1328 if (CollectionUtils.isEmpty(groupTypeProperties)) {
1329 BeEcompErrorManager.getInstance().logInvalidInputError(ADDING_GROUP, "group type does not have properties", ErrorSeverity.INFO);
1330 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(DaoStatusConverter.convertTitanStatusToStorageStatus(TitanOperationStatus.MATCH_NOT_FOUND))));
1333 Map<String, PropertyDefinition> groupTypePropertiesMap = groupTypeProperties.stream().collect(Collectors.toMap(PropertyDefinition::getName, p -> p));
1335 Either<GroupProperty, TitanOperationStatus> addPropertyResult;
1337 for (GroupProperty prop : properties) {
1338 addPropertyResult = handleProperty(prop, groupTypePropertiesMap.get(prop.getName()), i, allDAtaTypes, groupType);
1339 if (addPropertyResult.isRight()) {
1340 BeEcompErrorManager.getInstance().logInvalidInputError(ADDING_GROUP, "failed to validate property", ErrorSeverity.INFO);
1341 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(DaoStatusConverter.convertTitanStatusToStorageStatus(addPropertyResult.right().value()))));
1343 updatedGroupTypeProperties.add(addPropertyResult.left().value());
1349 if (groupDefinition.getUniqueId() == null) {
1350 String uid = UniqueIdBuilder.buildGroupingUid(component.getUniqueId(), groupDefinitionName);
1351 groupDefinition.setUniqueId(uid);
1353 groupDefinition.convertFromGroupProperties(updatedGroupTypeProperties);
1354 groupDefinition.setInvariantUUID(UniqueIdBuilder.buildInvariantUUID());
1355 groupDefinition.setGroupUUID(UniqueIdBuilder.generateUUID());
1356 groupDefinition.setVersion(INITIAL_VERSION);
1357 groupDefinition.setTypeUid(groupTypeDefinition.getUniqueId());
1359 return Either.left(groupDefinition);
1362 private static boolean groupExistsInComponent(String groupDefinitionName, Component component) {
1363 boolean found = false;
1364 List<GroupDefinition> groups = component.getGroups();
1365 if (CollectionUtils.isNotEmpty(groups)) {
1366 found = groups.stream().filter(p -> p.getName().equalsIgnoreCase(groupDefinitionName)).findFirst().orElse(null) != null;
1371 private Either<GroupProperty, TitanOperationStatus> handleProperty(GroupProperty groupProperty, PropertyDefinition prop, Integer index, Map<String, DataTypeDefinition> allDataTypes, String groupType) {
1374 return Either.right(TitanOperationStatus.ILLEGAL_ARGUMENT);
1377 String propertyType = prop.getType();
1378 String value = groupProperty.getValue();
1380 Either<String, TitanOperationStatus> checkInnerType = propertyOperation.checkInnerType(prop);
1381 if (checkInnerType.isRight()) {
1382 TitanOperationStatus status = checkInnerType.right().value();
1383 return Either.right(status);
1386 String innerType = checkInnerType.left().value();
1388 log.debug("Before validateAndUpdatePropertyValue");
1389 Either<Object, Boolean> isValid = propertyOperation.validateAndUpdatePropertyValue(propertyType, value, innerType, allDataTypes);
1390 log.debug("After validateAndUpdatePropertyValue. isValid = {}", isValid);
1392 String newValue = value;
1393 if (isValid.isRight()) {
1394 Boolean res = isValid.right().value();
1396 return Either.right(TitanOperationStatus.ILLEGAL_ARGUMENT);
1399 Object object = isValid.left().value();
1400 if (object != null) {
1401 newValue = object.toString();
1405 String uniqueId = shouldReconstructUniqueId(groupType) ? UniqueIdBuilder.buildGroupPropertyValueUid(prop.getUniqueId(), index)
1406 : prop.getUniqueId();
1408 groupProperty.setUniqueId(uniqueId);
1409 groupProperty.setValue(newValue);
1410 groupProperty.setType(prop.getType());
1411 groupProperty.setDefaultValue(prop.getDefaultValue());
1412 groupProperty.setDescription(prop.getDescription());
1413 groupProperty.setSchema(prop.getSchema());
1414 groupProperty.setPassword(prop.isPassword());
1415 groupProperty.setParentUniqueId(prop.getUniqueId());
1417 log.debug("Before adding property value to graph {}", groupProperty);
1419 return Either.left(groupProperty);
1422 // For old groups we want to leave indexing of property
1423 // For new groups we just need the types
1424 private boolean shouldReconstructUniqueId(String groupType) {
1425 return Constants.GROUP_TOSCA_HEAT.equals(groupType) || Constants.DEFAULT_GROUP_VF_MODULE.equals(groupType);