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=========================================================
19 * Modifications copyright (c) 2019 Nokia
20 * ================================================================================
23 package org.openecomp.sdc.be.components.impl;
25 import fj.data.Either;
26 import org.apache.commons.collections.CollectionUtils;
27 import org.apache.commons.collections.MapUtils;
28 import org.apache.commons.io.FilenameUtils;
29 import org.apache.commons.lang.StringUtils;
30 import org.apache.commons.lang3.math.NumberUtils;
31 import org.apache.commons.lang3.tuple.ImmutablePair;
32 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
33 import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException;
34 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
35 import org.openecomp.sdc.be.components.impl.lock.LockingTransactional;
36 import org.openecomp.sdc.be.components.impl.policy.PolicyTargetsUpdateHandler;
37 import org.openecomp.sdc.be.components.utils.Utils;
38 import org.openecomp.sdc.be.components.validation.AccessValidations;
39 import org.openecomp.sdc.be.components.validation.ComponentValidations;
40 import org.openecomp.sdc.be.config.BeEcompErrorManager;
41 import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity;
42 import org.openecomp.sdc.be.config.ConfigurationManager;
43 import org.openecomp.sdc.be.dao.api.ActionStatus;
44 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
45 import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition;
46 import org.openecomp.sdc.be.datatypes.elements.GroupDataDefinition;
47 import org.openecomp.sdc.be.datatypes.elements.PolicyTargetType;
48 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
49 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
50 import org.openecomp.sdc.be.datatypes.enums.CreatedFrom;
51 import org.openecomp.sdc.be.info.ArtifactDefinitionInfo;
52 import org.openecomp.sdc.be.info.ArtifactTemplateInfo;
53 import org.openecomp.sdc.be.info.GroupDefinitionInfo;
54 import org.openecomp.sdc.be.model.*;
55 import org.openecomp.sdc.be.model.PropertyDefinition.GroupInstancePropertyValueUpdateBehavior;
56 import org.openecomp.sdc.be.model.PropertyDefinition.PropertyNames;
57 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.GroupsOperation;
58 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.TopologyTemplateOperation;
59 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
60 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
61 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
62 import org.openecomp.sdc.common.api.Constants;
63 import org.openecomp.sdc.common.log.wrappers.Logger;
64 import org.openecomp.sdc.common.util.ValidationUtils;
65 import org.openecomp.sdc.exception.ResponseFormat;
66 import org.springframework.beans.factory.annotation.Autowired;
69 import java.util.Map.Entry;
70 import java.util.regex.Pattern;
71 import java.util.stream.Collectors;
73 import static java.util.stream.Collectors.toList;
74 import static org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter.extractCapabilitiesFromGroups;
75 import static org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter.extractCapabilityPropertiesFromGroups;
77 @org.springframework.stereotype.Component("groupBusinessLogic")
78 public class GroupBusinessLogic extends BaseBusinessLogic {
80 public static final String GROUP_DELIMITER_REGEX = "\\.\\.";
82 public static final String INITIAL_VERSION = "1";
84 private static final String ADDING_GROUP = "AddingGroup";
86 private static final String CREATE_GROUP = "CreateGroup";
88 private static final String UPDATE_GROUP = "UpdateGroup";
90 private static final String GET_GROUP = "GetGroup";
92 private static final String DELETE_GROUP = "DeleteGroup";
94 private static final Logger log = Logger.getLogger(GroupBusinessLogic.class);
96 private AccessValidations accessValidations;
98 @javax.annotation.Resource
100 private GroupsOperation groupsOperation;
103 PolicyTargetsUpdateHandler policyTargetsUpdateHandler;
105 private String getComponentTypeForResponse(org.openecomp.sdc.be.model.Component component) {
106 String componentTypeForResponse = "SERVICE";
107 if (component instanceof Resource) {
108 componentTypeForResponse = ((Resource) component).getResourceType().name();
110 return componentTypeForResponse;
114 * Verify that the artifact members belongs to the component
120 private Either<Boolean, ResponseFormat> verifyArtifactsBelongsToComponent(Component component, List<String> artifacts, String context) {
122 if (CollectionUtils.isEmpty(artifacts)) {
123 return Either.left(true);
126 Map<String, ArtifactDefinition> deploymentArtifacts = component.getDeploymentArtifacts();
127 if (MapUtils.isEmpty(deploymentArtifacts)) {
128 BeEcompErrorManager.getInstance().logInvalidInputError(context, "No deployment artifact found under component " + component.getNormalizedName(), ErrorSeverity.INFO);
129 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
132 List<String> currentArtifacts = deploymentArtifacts.values().stream().map(ArtifactDefinition::getUniqueId).collect(toList());
133 log.debug("The deployment artifacts of component {} are {}", component.getNormalizedName(), deploymentArtifacts);
134 if (!currentArtifacts.containsAll(artifacts)) {
135 BeEcompErrorManager.getInstance().logInvalidInputError(context, "Not all artifacts belongs to component " + component.getNormalizedName(), ErrorSeverity.INFO);
136 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
139 return Either.left(true);
144 * verify that the members are component instances of the component
147 * @param groupMembers
148 * @param memberToscaTypes
151 private Either<Boolean, ResponseFormat> verifyComponentInstancesAreValidMembers(Component component, String groupName, Map<String, String> groupMembers, List<String> memberToscaTypes) {
153 if (MapUtils.isEmpty(groupMembers)) {
154 return Either.left(true);
157 if (CollectionUtils.isEmpty(memberToscaTypes)) {
158 return Either.left(true);
161 List<ComponentInstance> componentInstances = component.getComponentInstances();
162 if (CollectionUtils.isNotEmpty(componentInstances)) {
163 Map<String, ComponentInstance> compInstUidToCompInstMap = componentInstances.stream().collect(Collectors.toMap(ComponentInstance::getUniqueId, p -> p));
165 Set<String> allCompInstances = compInstUidToCompInstMap.keySet();
167 for (Entry<String, String> groupMember : groupMembers.entrySet()) {
168 String compName = groupMember.getKey();
169 String compUid = groupMember.getValue();
171 if (!allCompInstances.contains(compUid)) {
173 * %1 - member name %2 - group name %3 - VF name %4 - component type [VF ]
175 String componentTypeForResponse = getComponentTypeForResponse(component);
177 BeEcompErrorManager.getInstance().logInvalidInputError(CREATE_GROUP, "Not all group members exists under the component", ErrorSeverity.INFO);
178 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_INVALID_COMPONENT_INSTANCE, compName, groupName, component.getNormalizedName(), componentTypeForResponse));
183 return Either.left(true);
189 * Update GroupDefinition metadata
193 * @param componentType
194 * @param updatedGroup
195 * @param inTransaction
198 public Either<GroupDefinition, ResponseFormat> validateAndUpdateGroupMetadata(String componentId, User user, ComponentTypeEnum componentType, GroupDefinition updatedGroup, boolean inTransaction , boolean shouldLock) {
200 Either<GroupDefinition, ResponseFormat> result = null;
202 // Validate user exist
203 validateUserExists(user.getUserId(), UPDATE_GROUP, inTransaction);
204 // Validate component exist
205 Either<? extends org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponent = validateComponentExists(componentId, componentType, null);
206 if (validateComponent.isRight()) {
207 result = Either.right(validateComponent.right().value());
210 org.openecomp.sdc.be.model.Component component = validateComponent.left().value();
211 // validate we can work on component
212 Either<Boolean, ResponseFormat> canWork = validateCanWorkOnComponent(component, user.getUserId());
213 if (canWork.isRight()) {
214 result = Either.right(canWork.right().value());
217 List<GroupDefinition> currentGroups = component.getGroups();
218 if (CollectionUtils.isEmpty(currentGroups)) {
219 log.error("Failed to update the metadata of group {} on component {}. The status is {}. ", updatedGroup.getName(), component.getName(), ActionStatus.GROUP_IS_MISSING);
220 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_IS_MISSING, updatedGroup.getName(), component.getName(), component.getComponentType().getValue()));
223 // Validate groups exists in the component
224 Optional<GroupDefinition> currentGroupOpt = currentGroups.stream().filter(g -> g.getUniqueId().equals(updatedGroup.getUniqueId())).findAny();
225 if (!currentGroupOpt.isPresent()) {
226 log.error("Failed to update the metadata of group {} on component {}. The status is {}. ", updatedGroup.getName(), component.getName(), ActionStatus.GROUP_IS_MISSING);
227 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_IS_MISSING, updatedGroup.getName(), component.getName(), component.getComponentType().getValue()));
230 GroupDefinition currentGroup = currentGroupOpt.get();
232 Either<Boolean, ResponseFormat> lockResult = lockComponent(componentId, component, "Update GroupDefinition Metadata");
233 if (lockResult.isRight()) {
234 result = Either.right(lockResult.right().value());
238 // Validate group type is vfModule
239 if (currentGroup.getType().equals(Constants.GROUP_TOSCA_HEAT)) {
240 log.error("Failed to update the metadata of group {}. Group type is {} and cannot be updated", currentGroup.getName(), currentGroup.getType());
241 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.GROUP_TYPE_IS_INVALID, updatedGroup.getType());
242 result = Either.right(responseFormat);
245 result = updateGroupMetadata(component, currentGroup, updatedGroup);
249 if (result != null && result.isLeft()) {
250 janusGraphDao.commit();
252 janusGraphDao.rollback();
255 graphLockOperation.unlockComponent(componentId, componentType.getNodeType());
260 private Either<GroupDefinition, ResponseFormat> updateGroupMetadata(Component component, GroupDefinition currentGroup, GroupDefinition updatedGroup) {
261 String currentGroupName = currentGroup.getName();
262 Either<GroupDefinition, ResponseFormat> result = validateAndUpdateGroupMetadata(currentGroup, updatedGroup);
264 if (result.isRight()) {
265 log.debug("Failed to validate a metadata of the group {} on component {}. ", updatedGroup.getName(), component.getName());
267 if (result.isLeft()) {
268 result = updateGroup(component, currentGroup, currentGroupName);
273 private Either<GroupDefinition, ResponseFormat> updateGroup(Component component, GroupDefinition updatedGroup, String currentGroupName) {
274 Either<GroupDefinition, StorageOperationStatus> handleGroupRes;
275 Either<GroupDefinition, ResponseFormat> result = null;
276 if (updatedGroup.getName().equals(currentGroupName)) {
277 handleGroupRes = groupsOperation.updateGroup(component, updatedGroup);
278 if (handleGroupRes.isRight()) {
279 log.debug("Failed to update a metadata of the group {} on component {}. ", updatedGroup.getName(), component.getName());
280 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(handleGroupRes.right().value())));
283 StorageOperationStatus deleteStatus = groupsOperation.deleteGroup(component, currentGroupName);
284 if (deleteStatus != StorageOperationStatus.OK) {
285 log.debug("Failed to delete the group {} from component {}. ", updatedGroup.getName(), component.getName());
286 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(deleteStatus)));
288 handleGroupRes = groupsOperation.addGroup(component, updatedGroup);
289 if (handleGroupRes.isRight()) {
290 log.debug("Failed to add the group {} to component {}. ", updatedGroup.getName(), component.getName());
291 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(handleGroupRes.right().value())));
294 if (result == null) {
295 result = Either.left(updatedGroup);
301 * Validate and update GroupDefinition metadata
303 * @param currentGroup
307 private Either<GroupDefinition, ResponseFormat> validateAndUpdateGroupMetadata(GroupDefinition currentGroup, GroupDefinition groupUpdate) {
308 // Check if to update, and update GroupDefinition name.
309 Either<Boolean, ResponseFormat> response = validateAndUpdateGroupName(currentGroup, groupUpdate);
310 if (response.isRight()) {
311 ResponseFormat errorResponse = response.right().value();
312 return Either.right(errorResponse);
315 // Do not allow to update GroupDefinition version directly.
316 String versionUpdated = groupUpdate.getVersion();
317 String versionCurrent = currentGroup.getVersion();
318 if (versionUpdated != null && !versionCurrent.equals(versionUpdated)) {
319 log.info("update Group: recived request to update version to {} the field is not updatable ignoring.", versionUpdated);
322 return Either.left(currentGroup);
326 * Validate and update GroupDefinition name
328 * @param currentGroup
332 private Either<Boolean, ResponseFormat> validateAndUpdateGroupName(GroupDefinition currentGroup, GroupDefinition groupUpdate) {
333 String nameUpdated = groupUpdate.getName();
334 String nameCurrent = currentGroup.getName();
335 if (!nameCurrent.equals(nameUpdated)) {
336 Either<Boolean, ResponseFormat> validatNameResponse = validateGroupName(currentGroup.getName(), groupUpdate.getName() ,true);
337 if (validatNameResponse.isRight()) {
338 ResponseFormat errorRespons = validatNameResponse.right().value();
339 return Either.right(errorRespons);
341 currentGroup.setName(groupUpdate.getName());
343 return Either.left(true);
347 * 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
348 * MyDesc was changed.
350 * @param currentGroupName
351 * @param groupUpdateName
354 private Either<Boolean, ResponseFormat> validateGroupName(String currentGroupName, String groupUpdateName , boolean isforceNameModification) {
356 // Check if the group name is in old format.
357 if (Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(groupUpdateName).matches()) {
358 log.error("Group name {} is in old format", groupUpdateName);
359 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_VF_MODULE_NAME, groupUpdateName));
362 // Check that name pats 1 and 3 did not changed (only the second
363 // part can be changed)
364 // But verify before that the current group format is the new one
365 if (!Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(currentGroupName).matches()) {
366 String[] split1 = currentGroupName.split(GROUP_DELIMITER_REGEX);
367 String currentResourceName = split1[0];
368 String currentCounter = split1[2];
370 String[] split2 = groupUpdateName.split(GROUP_DELIMITER_REGEX);
371 String groupUpdateResourceName = split2[0];
372 String groupUpdateCounter = split2[2];
373 if (!isforceNameModification){ //if not forced ,allow name prefix&suffix validation [no changes]
374 if (!currentResourceName.equals(groupUpdateResourceName)) {
375 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_VF_MODULE_NAME_MODIFICATION, currentResourceName));
378 if (!currentCounter.equals(groupUpdateCounter)) {
379 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_VF_MODULE_NAME_MODIFICATION, currentCounter));
385 return Either.left(true);
386 } catch (Exception e) {
387 log.error("Error valiadting group name", e);
388 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
394 * associate artifacts to a given group
398 * @param componentType
399 * @param inTransaction
402 public Either<GroupDefinitionInfo, ResponseFormat> getGroupWithArtifactsById(ComponentTypeEnum componentType, String componentId, String groupId, String userId, boolean inTransaction) {
404 Either<GroupDefinitionInfo, ResponseFormat> result = null;
406 // Validate user exist
407 validateUserExists(userId, GET_GROUP, true);
408 // Validate component exist
409 org.openecomp.sdc.be.model.Component component = null;
412 ComponentParametersView componentParametersView = new ComponentParametersView();
413 componentParametersView.disableAll();
414 componentParametersView.setIgnoreGroups(false);
415 componentParametersView.setIgnoreArtifacts(false);
416 componentParametersView.setIgnoreUsers(false);
418 Either<? extends org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponent = validateComponentExists(componentId, componentType, componentParametersView);
419 if (validateComponent.isRight()) {
420 result = Either.right(validateComponent.right().value());
423 component = validateComponent.left().value();
425 Either<GroupDefinition, StorageOperationStatus> groupEither = findGroupOnComponent(component, groupId);
427 if (groupEither.isRight()) {
428 log.debug("Faild to find group {} under component {}", groupId, component.getUniqueId());
429 BeEcompErrorManager.getInstance().logInvalidInputError(GET_GROUP, "group " + groupId + " not found under component " + component.getUniqueId(), ErrorSeverity.INFO);
430 String componentTypeForResponse = getComponentTypeForResponse(component);
431 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_IS_MISSING, groupId, component.getSystemName(), componentTypeForResponse));
434 GroupDefinition group = groupEither.left().value();
436 Boolean isBase = null;
437 List<GroupProperty> props = group.convertToGroupProperties();
438 if (props != null && !props.isEmpty()) {
439 Optional<GroupProperty> isBasePropOp = props.stream().filter(p -> p.getName().equals(Constants.IS_BASE)).findAny();
440 if (isBasePropOp.isPresent()) {
441 GroupProperty propIsBase = isBasePropOp.get();
442 isBase = Boolean.parseBoolean(propIsBase.getValue());
445 BeEcompErrorManager.getInstance().logInvalidInputError(GET_GROUP, "failed to find prop isBase " + component.getNormalizedName(), ErrorSeverity.INFO);
449 List<ArtifactDefinitionInfo> artifacts = new ArrayList<>();
450 List<ArtifactDefinition> artifactsFromComponent = new ArrayList<>();
451 List<String> artifactsIds = group.getArtifacts();
453 Map<String, ArtifactDefinition> deploymentArtifacts = null;
454 if (MapUtils.isNotEmpty(component.getDeploymentArtifacts())) {
455 deploymentArtifacts = component.getDeploymentArtifacts().values().stream().collect(Collectors.toMap(ArtifactDataDefinition::getUniqueId, a -> a));
458 if (artifactsIds != null && !artifactsIds.isEmpty()) {
459 for (String id : artifactsIds) {
460 if (deploymentArtifacts == null || !deploymentArtifacts.containsKey(id)) {
461 log.debug("Failed to get artifact {} . Status is {} ", id, StorageOperationStatus.NOT_FOUND);
462 ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(StorageOperationStatus.NOT_FOUND));
463 result = Either.right(responseFormat);
466 artifactsFromComponent.add(deploymentArtifacts.get(id));
468 if (!artifactsFromComponent.isEmpty()) {
469 for (ArtifactDefinition artifactDefinition : artifactsFromComponent) {
470 ArtifactDefinitionInfo artifactDefinitionInfo = new ArtifactDefinitionInfo(artifactDefinition);
471 artifacts.add(artifactDefinitionInfo);
476 GroupDefinitionInfo resultInfo = new GroupDefinitionInfo(group);
477 resultInfo.setIsBase(isBase);
478 if (!artifacts.isEmpty()) {
479 resultInfo.setArtifacts(artifacts);
481 result = Either.left(resultInfo);
487 if (!inTransaction) {
489 if (result == null || result.isRight()) {
490 log.debug("Going to execute rollback on create group.");
491 janusGraphDao.rollback();
493 log.debug("Going to execute commit on create group.");
494 janusGraphDao.commit();
503 private Either<GroupDefinition, StorageOperationStatus> findGroupOnComponent(Component component, String groupId) {
505 Either<GroupDefinition, StorageOperationStatus> result = null;
506 if (CollectionUtils.isNotEmpty(component.getGroups())) {
507 Optional<GroupDefinition> foundGroup = component.getGroups().stream().filter(g -> g.getUniqueId().equals(groupId)).findFirst();
508 if (foundGroup.isPresent()) {
509 result = Either.left(foundGroup.get());
512 if (result == null) {
513 result = Either.right(StorageOperationStatus.NOT_FOUND);
518 public Either<Boolean, ResponseFormat> validateGenerateVfModuleGroupNames(List<ArtifactTemplateInfo> allGroups, String resourceSystemName, int startGroupCounter) {
519 Either<Boolean, ResponseFormat> validateGenerateGroupNamesRes = Either.left(true);
520 Collections.sort(allGroups, ArtifactTemplateInfo::compareByGroupName);
521 for (ArtifactTemplateInfo group : allGroups) {
522 Either<String, ResponseFormat> validateGenerateGroupNameRes = validateGenerateVfModuleGroupName(resourceSystemName, group.getDescription(), startGroupCounter++);
523 if (validateGenerateGroupNameRes.isRight()) {
524 validateGenerateGroupNamesRes = Either.right(validateGenerateGroupNameRes.right().value());
527 group.setGroupName(validateGenerateGroupNameRes.left().value());
529 return validateGenerateGroupNamesRes;
533 * Generate module name from resourceName, description and counter
535 * @param resourceSystemName
537 * @param groupCounter
540 private Either<String, ResponseFormat> validateGenerateVfModuleGroupName(String resourceSystemName, String description, int groupCounter) {
541 Either<String, ResponseFormat> validateGenerateGroupNameRes;
542 if (resourceSystemName != null && description != null && Pattern.compile(Constants.MODULE_DESC_PATTERN).matcher(description).matches()) {
543 final String fileName = description.replaceAll(GROUP_DELIMITER_REGEX, "\\.");
544 validateGenerateGroupNameRes = Either.left(String.format(Constants.MODULE_NAME_FORMAT, resourceSystemName, FilenameUtils.removeExtension(fileName), groupCounter));
546 validateGenerateGroupNameRes = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_VF_MODULE_NAME));
548 return validateGenerateGroupNameRes;
551 Either<Map<String, GroupDefinition>, ResponseFormat> validateUpdateVfGroupNames(Map<String, GroupDefinition> groups, String resourceSystemName) {
553 Map<String, GroupDefinition> updatedNamesGroups = new HashMap<>();
554 Either<Map<String, GroupDefinition>, ResponseFormat> result = Either.left(updatedNamesGroups);
555 for (Entry<String, GroupDefinition> groupEntry : groups.entrySet()) {
556 GroupDefinition curGroup = groupEntry.getValue();
557 String groupType = curGroup.getType();
558 String groupName = groupEntry.getKey();
561 Either<String, ResponseFormat> newGroupNameRes;
562 if (groupType.equals(Constants.DEFAULT_GROUP_VF_MODULE) && !Pattern.compile(Constants.MODULE_NEW_NAME_PATTERN).matcher(groupName).matches()) {
564 if (Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(groupEntry.getKey()).matches()) {
565 counter = Integer.parseInt(groupEntry.getKey().split(Constants.MODULE_NAME_DELIMITER)[1]);
566 description = curGroup.getDescription();
568 counter = getNextVfModuleNameCounter(updatedNamesGroups);
569 description = groupName;
571 newGroupNameRes = validateGenerateVfModuleGroupName(resourceSystemName, description, counter);
572 if (newGroupNameRes.isRight()) {
573 log.debug("Failed to generate new vf module group name. Status is {} ", newGroupNameRes.right().value());
574 result = Either.right(newGroupNameRes.right().value());
577 groupName = newGroupNameRes.left().value();
578 curGroup.setName(groupName);
580 updatedNamesGroups.put(groupName, curGroup);
585 public int getNextVfModuleNameCounter(Map<String, GroupDefinition> groups) {
587 if (groups != null && !groups.isEmpty()) {
588 counter = getNextVfModuleNameCounter(groups.values());
593 public int getNextVfModuleNameCounter(Collection<GroupDefinition> groups) {
595 if (groups != null && !groups.isEmpty()) {
596 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())
597 .map(group -> Integer.parseInt(group.getName().split(Constants.MODULE_NAME_DELIMITER)[1])).collect(toList());
598 counter = (counters == null || counters.isEmpty()) ? 0 : counters.stream().max(Integer::compare).get() + 1;
603 public Either<List<GroupDefinition>, ResponseFormat> validateUpdateVfGroupNamesOnGraph(List<GroupDefinition> groups, Component component) {
604 List<GroupDefinition> updatedGroups = new ArrayList<>();
605 Either<List<GroupDefinition>, ResponseFormat> result;
607 for (GroupDefinition group : groups) {
608 String groupType = group.getType();
609 String oldGroupName = group.getName();
611 Either<String, ResponseFormat> newGroupNameRes;
613 if (groupType.equals(Constants.DEFAULT_GROUP_VF_MODULE) && Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(oldGroupName).matches()) {
614 counter = Integer.parseInt(group.getName().split(Constants.MODULE_NAME_DELIMITER)[1]);
615 newGroupNameRes = validateGenerateVfModuleGroupName(component.getSystemName(), group.getDescription(), counter);
616 if (newGroupNameRes.isRight()) {
617 log.debug("Failed to generate new vf module group name. Status is {} ", newGroupNameRes.right().value());
618 result = Either.right(newGroupNameRes.right().value());
621 newGroupName = newGroupNameRes.left().value();
622 group.setName(newGroupName);
625 updatedGroups.add(group);
629 result = Either.left(updatedGroups);
634 public Either<GroupDefinitionInfo, ResponseFormat> getGroupInstWithArtifactsById(ComponentTypeEnum componentType, String componentId, String componentInstanceId, String groupInstId, String userId, boolean inTransaction) {
635 Either<GroupDefinitionInfo, ResponseFormat> result = null;
637 // Validate user exist
638 validateUserExists(userId, UPDATE_GROUP, true);
639 // Validate component exist
640 org.openecomp.sdc.be.model.Component component = null;
643 ComponentParametersView componentParametersView = new ComponentParametersView();
644 componentParametersView.disableAll();
645 componentParametersView.setIgnoreUsers(false);
646 componentParametersView.setIgnoreComponentInstances(false);
647 componentParametersView.setIgnoreArtifacts(false);
649 Either<? extends org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponent = validateComponentExists(componentId, componentType, componentParametersView);
650 if (validateComponent.isRight()) {
651 result = Either.right(validateComponent.right().value());
654 component = validateComponent.left().value();
655 Either<ImmutablePair<ComponentInstance, GroupInstance>, StorageOperationStatus> findComponentInstanceAndGroupInstanceRes = findComponentInstanceAndGroupInstanceOnComponent(component, componentInstanceId, groupInstId);
657 if (findComponentInstanceAndGroupInstanceRes.isRight()) {
658 log.debug("Failed to get group {} . Status is {} ", groupInstId, findComponentInstanceAndGroupInstanceRes.right().value());
659 ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(findComponentInstanceAndGroupInstanceRes.right().value()));
660 result = Either.right(responseFormat);
664 GroupInstance group = findComponentInstanceAndGroupInstanceRes.left().value().getRight();
666 Boolean isBase = null;
667 List<? extends GroupProperty> props = group.convertToGroupInstancesProperties();
668 if (props != null && !props.isEmpty()) {
669 Optional<? extends GroupProperty> isBasePropOp = props.stream().filter(p -> p.getName().equals(Constants.IS_BASE)).findAny();
670 if (isBasePropOp.isPresent()) {
671 GroupProperty propIsBase = isBasePropOp.get();
672 isBase = Boolean.parseBoolean(propIsBase.getValue());
675 BeEcompErrorManager.getInstance().logInvalidInputError(GET_GROUP, "failed to find prop isBase " + component.getNormalizedName(), ErrorSeverity.INFO);
679 List<ArtifactDefinitionInfo> artifacts = new ArrayList<>();
680 List<String> artifactsIds = group.getArtifacts();
681 if (artifactsIds != null && !artifactsIds.isEmpty()) {
683 List<ComponentInstance> instances = component.getComponentInstances();
684 if (instances != null) {
685 Optional<ComponentInstance> findFirst = instances.stream().filter(i -> i.getUniqueId().equals(componentInstanceId)).findFirst();
686 if (findFirst.isPresent()) {
687 ComponentInstance ci = findFirst.get();
688 Map<String, ArtifactDefinition> deploymentArtifacts = ci.getDeploymentArtifacts();
689 for (String id : artifactsIds) {
690 Optional<ArtifactDefinition> artOp = deploymentArtifacts.values().stream().filter(a -> a.getUniqueId().equals(id)).findFirst();
691 if (artOp.isPresent()) {
692 artifacts.add(new ArtifactDefinitionInfo(artOp.get()));
695 List<String> instArtifactsIds = group.getGroupInstanceArtifacts();
696 for (String id : instArtifactsIds) {
697 Optional<ArtifactDefinition> artOp = deploymentArtifacts.values().stream().filter(a -> a.getUniqueId().equals(id)).findFirst();
698 if (artOp.isPresent()) {
699 artifacts.add(new ArtifactDefinitionInfo(artOp.get()));
706 GroupDefinitionInfo resultInfo = new GroupDefinitionInfo(group);
707 resultInfo.setIsBase(isBase);
708 if (!artifacts.isEmpty()) {
709 resultInfo.setArtifacts(artifacts);
711 result = Either.left(resultInfo);
717 if (!inTransaction) {
719 if (result == null || result.isRight()) {
720 log.debug("Going to execute rollback on create group.");
721 janusGraphDao.rollback();
723 log.debug("Going to execute commit on create group.");
724 janusGraphDao.commit();
732 private Either<ImmutablePair<ComponentInstance, GroupInstance>, StorageOperationStatus> findComponentInstanceAndGroupInstanceOnComponent(Component component, String componentInstanceId, String groupInstId) {
734 Either<ImmutablePair<ComponentInstance, GroupInstance>, StorageOperationStatus> result = null;
735 if (CollectionUtils.isNotEmpty(component.getComponentInstances())) {
736 Optional<GroupInstance> foundGroup;
737 Optional<ComponentInstance> foundComponent = component.getComponentInstances().stream().filter(ci -> ci.getUniqueId().equals(componentInstanceId)).findFirst();
738 if (foundComponent.isPresent() && CollectionUtils.isNotEmpty(foundComponent.get().getGroupInstances())) {
739 foundGroup = foundComponent.get().getGroupInstances().stream().filter(gi -> gi.getUniqueId().equals(groupInstId)).findFirst();
740 if (foundGroup.isPresent()) {
741 result = Either.left(new ImmutablePair<>(foundComponent.get(), foundGroup.get()));
745 if (result == null) {
746 result = Either.right(StorageOperationStatus.NOT_FOUND);
751 private Either<Boolean, ResponseFormat> validateMinMaxAndInitialCountPropertyLogic(Map<PropertyNames, String> newValues, Map<PropertyNames, String> currValues, Map<PropertyNames, String> parentValues) {
753 Either<Boolean, ResponseFormat> result;
754 for (Entry<PropertyNames, String> entry : newValues.entrySet()) {
755 PropertyNames currPropertyName = entry.getKey();
756 if (currPropertyName == PropertyNames.MIN_INSTANCES) {
757 String minValue = parentValues.get(PropertyNames.MIN_INSTANCES);
758 String maxValue = newValues.containsKey(PropertyNames.INITIAL_COUNT) ? newValues.get(PropertyNames.MAX_INSTANCES) : currValues.get(PropertyNames.INITIAL_COUNT);
759 result = validateValueInRange(new ImmutablePair<>(currPropertyName, entry.getValue()), new ImmutablePair<>(PropertyNames.MIN_INSTANCES, minValue),
760 new ImmutablePair<>(PropertyNames.MAX_INSTANCES, maxValue));
761 if (result.isRight()) {
764 } else if (currPropertyName == PropertyNames.INITIAL_COUNT) {
765 String minValue = newValues.containsKey(PropertyNames.MIN_INSTANCES) ? newValues.get(PropertyNames.MIN_INSTANCES) : currValues.get(PropertyNames.MIN_INSTANCES);
766 String maxValue = newValues.containsKey(PropertyNames.MAX_INSTANCES) ? newValues.get(PropertyNames.MAX_INSTANCES) : currValues.get(PropertyNames.MAX_INSTANCES);
767 result = validateValueInRange(new ImmutablePair<>(currPropertyName, entry.getValue()), new ImmutablePair<>(PropertyNames.MIN_INSTANCES, minValue),
768 new ImmutablePair<>(PropertyNames.MAX_INSTANCES, maxValue));
769 if (result.isRight()) {
772 } else if (currPropertyName == PropertyNames.MAX_INSTANCES) {
773 String minValue = newValues.containsKey(PropertyNames.INITIAL_COUNT) ? newValues.get(PropertyNames.MIN_INSTANCES) : currValues.get(PropertyNames.INITIAL_COUNT);
774 String maxValue = parentValues.get(PropertyNames.MAX_INSTANCES);
775 result = validateValueInRange(new ImmutablePair<>(currPropertyName, entry.getValue()), new ImmutablePair<>(PropertyNames.MIN_INSTANCES, minValue),
776 new ImmutablePair<>(PropertyNames.MAX_INSTANCES, maxValue));
777 if (result.isRight()) {
782 return Either.left(true);
785 private Either<Boolean, ResponseFormat> validateValueInRange(ImmutablePair<PropertyNames, String> newValue, ImmutablePair<PropertyNames, String> min, ImmutablePair<PropertyNames, String> max) {
786 Either<Boolean, ResponseFormat> result;
787 final String warnMessage = "Failed to validate {} as property value of {}. It must be not higher than {}, and not lower than {}.";
788 int newValueInt = parseIntValue(newValue.getValue(), newValue.getKey());
789 int minInt = parseIntValue(min.getValue(), min.getKey());
790 int maxInt = parseIntValue(max.getValue(), max.getKey());
791 if (newValueInt < 0 || minInt < 0 || maxInt < 0) {
792 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_PROPERTY));
793 } else if (newValueInt < minInt || newValueInt > maxInt) {
794 log.debug(warnMessage, newValue.getValue(), newValue.getKey().getPropertyName(), min.getValue(), max.getValue());
796 .right(componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_MIN_MAX_INSTANCES_PROPERTY_VALUE, newValue.getKey().getPropertyName(), maxInt == Integer.MAX_VALUE ? Constants.UNBOUNDED : max.getValue(), min.getValue()));
798 result = Either.left(true);
803 private int parseIntValue(String value, PropertyNames propertyName) {
805 if (propertyName == PropertyNames.MAX_INSTANCES) {
806 result = convertIfUnboundMax(value);
807 } else if (NumberUtils.isNumber(value)) {
808 result = Integer.parseInt(value);
816 * validates received new property values and updates group instance in case of success
818 * @param oldGroupInstance
819 * @param newProperties
822 public Either<GroupInstance, ResponseFormat> validateAndUpdateGroupInstancePropertyValues(String componentId, String instanceId, GroupInstance oldGroupInstance, List<GroupInstanceProperty> newProperties) {
824 Either<GroupInstance, ResponseFormat> actionResult = null;
825 Either<GroupInstance, StorageOperationStatus> updateGroupInstanceResult = null;
826 Either<List<GroupInstanceProperty>, ResponseFormat> validateRes = validateReduceGroupInstancePropertiesBeforeUpdate(oldGroupInstance, newProperties);
827 if (validateRes.isRight()) {
828 log.debug("Failed to validate group instance {} properties before update. ", oldGroupInstance.getName());
829 actionResult = Either.right(validateRes.right().value());
831 if (actionResult == null) {
832 List<GroupInstanceProperty> validatedReducedNewProperties = validateRes.left().value();
833 updateGroupInstanceResult = groupsOperation.updateGroupInstancePropertyValuesOnGraph(componentId, instanceId, oldGroupInstance, validatedReducedNewProperties);
834 if (updateGroupInstanceResult.isRight()) {
835 log.debug("Failed to update group instance {} property values. ", oldGroupInstance.getName());
836 actionResult = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(updateGroupInstanceResult.right().value())));
839 if (actionResult == null) {
840 actionResult = Either.left(updateGroupInstanceResult.left().value());
845 private Either<List<GroupInstanceProperty>, ResponseFormat> validateReduceGroupInstancePropertiesBeforeUpdate(GroupInstance oldGroupInstance, List<GroupInstanceProperty> newProperties) {
847 Either<Boolean, ResponseFormat> validationRes = null;
848 Either<List<GroupInstanceProperty>, ResponseFormat> actionResult;
849 Map<String, GroupInstanceProperty> existingProperties = oldGroupInstance.convertToGroupInstancesProperties().stream().collect(Collectors.toMap(PropertyDataDefinition::getName, p -> p));
850 Map<PropertyNames, String> newPropertyValues = new EnumMap<>(PropertyNames.class);
851 List<GroupInstanceProperty> reducedProperties = new ArrayList<>();
852 String currPropertyName;
854 for (GroupInstanceProperty currNewProperty : newProperties) {
855 currPropertyName = currNewProperty.getName();
856 validationRes = handleAndAddProperty(reducedProperties, newPropertyValues, currNewProperty, existingProperties.get(currPropertyName));
857 if (validationRes.isRight()) {
858 log.debug("Failed to handle property {} of group instance {}. ", currPropertyName, oldGroupInstance.getName());
862 if (validationRes == null || validationRes.isLeft()) {
863 Map<PropertyNames, String> existingPropertyValues = new EnumMap<>(PropertyNames.class);
864 Map<PropertyNames, String> parentPropertyValues = new EnumMap<>(PropertyNames.class);
865 fillValuesAndParentValuesFromExistingProperties(existingProperties, existingPropertyValues, parentPropertyValues);
866 validationRes = validateMinMaxAndInitialCountPropertyLogic(newPropertyValues, existingPropertyValues, parentPropertyValues);
868 if (validationRes.isLeft()) {
869 actionResult = Either.left(reducedProperties);
871 actionResult = Either.right(validationRes.right().value());
873 } catch (Exception e) {
874 log.error("Exception occured during validation and reducing group instance properties. The message is {}", e.getMessage(), e);
875 actionResult = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
880 private void fillValuesAndParentValuesFromExistingProperties(Map<String, GroupInstanceProperty> existingProperties, Map<PropertyNames, String> propertyValues, Map<PropertyNames, String> parentPropertyValues) {
881 PropertyNames[] allPropertyNames = PropertyNames.values();
882 for (PropertyNames name : allPropertyNames) {
883 if (isUpdatable(name)) {
884 propertyValues.put(name, String.valueOf(existingProperties.get(name.getPropertyName()).getValue()));
885 parentPropertyValues.put(name, String.valueOf(existingProperties.get(name.getPropertyName()).getParentValue()));
890 private Either<Boolean, ResponseFormat> handleAndAddProperty(List<GroupInstanceProperty> reducedProperties, Map<PropertyNames, String> newPropertyValues, GroupInstanceProperty currNewProperty, GroupInstanceProperty currExistingProperty) {
892 Either<Boolean, ResponseFormat> validationRes = null;
893 String currPropertyName = currNewProperty.getName();
894 PropertyNames propertyName = PropertyNames.findName(currPropertyName);
896 if (currExistingProperty == null) {
897 log.warn("The value of property with the name {} cannot be updated. The property not found on group instance. ", currPropertyName);
898 } else if (isUpdatable(propertyName)) {
899 validationRes = validateAndUpdatePropertyValue(currNewProperty, currExistingProperty);
900 if (validationRes.isRight()) {
901 log.debug("Failed to validate property value {} of property {}. ", currNewProperty.getValue(), currPropertyName);
903 addPropertyUpdatedValues(reducedProperties, propertyName, newPropertyValues, currNewProperty, currExistingProperty);
906 validateImmutableProperty(currExistingProperty, currNewProperty);
908 if (validationRes == null) {
909 validationRes = Either.left(true);
911 } catch (Exception e) {
912 log.error("Exception occured during handle and adding property. The message is {}", e.getMessage(), e);
913 validationRes = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
915 return validationRes;
918 private boolean isUpdatable(PropertyNames updatablePropertyName) {
919 return updatablePropertyName != null && updatablePropertyName.getUpdateBehavior().getLevelNumber() >= GroupInstancePropertyValueUpdateBehavior.UPDATABLE_ON_SERVICE_LEVEL.getLevelNumber();
922 private void addPropertyUpdatedValues(List<GroupInstanceProperty> reducedProperties, PropertyNames propertyName, Map<PropertyNames, String> newPropertyValues, GroupInstanceProperty newProperty, GroupInstanceProperty existingProperty) {
924 String newValue = newProperty.getValue();
925 if (!newValue.equals(String.valueOf(existingProperty.getValue()))) {
926 newProperty.setValueUniqueUid(existingProperty.getValueUniqueUid());
927 reducedProperties.add(newProperty);
929 if (!isEmptyMinInitialCountValue(propertyName, newValue)) {
930 newPropertyValues.put(propertyName, newValue);
934 private boolean isEmptyMinInitialCountValue(PropertyNames propertyName, String newValue) {
935 boolean result = false;
936 if ((propertyName == PropertyNames.MIN_INSTANCES || propertyName == PropertyNames.INITIAL_COUNT) && !NumberUtils.isNumber(newValue)) {
942 private int convertIfUnboundMax(String value) {
945 if (!NumberUtils.isNumber(value)) {
946 result = Integer.MAX_VALUE;
948 result = Integer.parseInt(value);
953 private Either<Boolean, ResponseFormat> validateAndUpdatePropertyValue(GroupInstanceProperty newProperty, GroupInstanceProperty existingProperty) {
955 Either<Boolean, ResponseFormat> validationRes = null;
956 String parentValue = existingProperty.getParentValue();
958 newProperty.setParentValue(parentValue);
959 if (StringUtils.isEmpty(newProperty.getValue())) {
960 newProperty.setValue(parentValue);
962 if (StringUtils.isEmpty(existingProperty.getValue())) {
963 existingProperty.setValue(parentValue);
965 StorageOperationStatus status = groupOperation.validateAndUpdatePropertyValue(newProperty);
966 if (status != StorageOperationStatus.OK) {
967 log.debug("Failed to validate property value {} of property with name {}. Status is {}. ", newProperty.getValue(), newProperty.getName(), status);
968 validationRes = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(status)));
970 if (validationRes == null) {
971 validationRes = Either.left(true);
973 return validationRes;
976 private void validateImmutableProperty(GroupProperty oldProperty, GroupProperty newProperty) {
977 if (oldProperty.getValue() == null && newProperty.getValue() != null || oldProperty.getValue() != null && !oldProperty.getValue().equals(newProperty.getValue())) {
978 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());
982 @LockingTransactional
983 public GroupDefinition createGroup(String componentId, ComponentTypeEnum componentTypeEnum, String groupType,
986 Component component = accessValidations.validateUserCanWorkOnComponent(componentId, componentTypeEnum, userId, CREATE_GROUP);
988 validateGroupTypePerComponent(groupType, component);
990 GroupTypeDefinition groupTypeDefinition = groupTypeOperation.getLatestGroupTypeByType(groupType, false)
992 .on(se -> onGroupTypeNotFound(component));
994 boolean hasExistingGroups = CollectionUtils.isNotEmpty(component.getGroups());
995 GroupDefinition groupDefinition = new GroupDefinition();
996 groupDefinition.setType(groupType);
998 //find next valid counter
1000 if (hasExistingGroups) {
1001 nextCounter = getNewGroupCounter(component);
1003 String name = TopologyTemplateOperation.buildSubComponentName(component.getName(), groupType, nextCounter);
1004 groupDefinition.setName(name);
1005 groupDefinition.setDescription(groupTypeDefinition.getDescription());
1006 groupDefinition.setInvariantName(name);
1007 groupDefinition.setCreatedFrom(CreatedFrom.UI);
1009 //Add default type properties
1010 List<PropertyDefinition> groupTypeProperties = groupTypeDefinition.getProperties();
1011 List<GroupProperty> properties = groupTypeProperties.stream()
1012 .map(GroupProperty::new)
1014 groupDefinition.convertFromGroupProperties(properties);
1016 groupDefinition.convertCapabilityDefinitions(groupTypeDefinition.getCapabilities());
1018 List<GroupDefinition> gdList;
1019 if (toscaOperationFacade.canAddGroups(componentId)) {
1020 gdList = addGroups(component, Arrays.asList(groupDefinition), false)
1022 .on(this::onFailedGroupDBOperation);
1024 //createGroups also creates an edge and vertex to store group data
1025 gdList = createGroups(component, Arrays.asList(groupDefinition), false)
1027 .on(this::onFailedGroupDBOperation);
1029 return gdList.get(0);
1032 private void validateGroupTypePerComponent(String groupType, Component component) {
1033 String specificType = component.getComponentMetadataDefinition().getMetadataDataDefinition().getActualComponentType();
1034 if (!component.isTopologyTemplate()) {
1035 throw new ByActionStatusComponentException(ActionStatus.GROUP_TYPE_ILLEGAL_PER_COMPONENT, groupType,
1038 Map<String, Set<String>> excludedGroupTypesMap = ConfigurationManager.getConfigurationManager().getConfiguration()
1039 .getExcludedGroupTypesMapping();
1041 if (MapUtils.isNotEmpty(excludedGroupTypesMap) && StringUtils.isNotEmpty(specificType)) {
1042 Set<String> excludedGroupTypesPerComponent = excludedGroupTypesMap.get(specificType);
1043 if (excludedGroupTypesPerComponent!=null && excludedGroupTypesPerComponent.contains(groupType)) {
1044 throw new ByActionStatusComponentException(ActionStatus.GROUP_TYPE_ILLEGAL_PER_COMPONENT, groupType, specificType);
1049 private int getNewGroupCounter(Component component) {
1050 List<String> existingNames = component.getGroups()
1052 .map(GroupDataDefinition::getName)
1054 List<String> existingIds = component.getGroups()
1056 .map(GroupDataDefinition::getUniqueId)
1058 existingIds.addAll(existingNames);
1060 return Utils.getNextCounter(existingIds);
1063 @LockingTransactional
1064 public GroupDefinition updateGroup(String componentId, ComponentTypeEnum componentTypeEnum, String groupId,
1065 String userId, GroupDefinition updatedGroup) {
1066 Component component = accessValidations.validateUserCanWorkOnComponent(componentId, componentTypeEnum, userId, UPDATE_GROUP);
1068 GroupDefinition existingGroup = findGroupOnComponent(component, groupId)
1070 .on(se -> onGroupNotFoundInComponentError(component, groupId));
1072 String existingGroupName = existingGroup.getName();
1073 String updatedGroupName = updatedGroup.getName();
1074 assertNewNameIsValidAndUnique(existingGroupName, updatedGroupName, component);
1075 existingGroup.setName(updatedGroupName);
1077 return updateGroup(component, existingGroup, existingGroupName)
1079 .on(this::onFailedUpdateGroupDBOperation);
1082 private void assertNewNameIsValidAndUnique(String currentGroupName, String updatedGroupName, Component component) {
1083 if (!ValidationUtils.validateResourceInstanceNameLength(updatedGroupName)) {
1084 throw new ByActionStatusComponentException(ActionStatus.EXCEEDS_LIMIT, "Group Name", ValidationUtils.RSI_NAME_MAX_LENGTH.toString());
1086 if (!ValidationUtils.validateResourceInstanceName(updatedGroupName)) {
1087 throw new ByActionStatusComponentException(ActionStatus.INVALID_VF_MODULE_NAME, updatedGroupName);
1089 if (!ComponentValidations.validateNameIsUniqueInComponent(currentGroupName, updatedGroupName, component)) {
1090 throw new ByActionStatusComponentException(ActionStatus.COMPONENT_NAME_ALREADY_EXIST, "Group", updatedGroupName);
1094 @LockingTransactional
1095 public GroupDefinition deleteGroup(String componentId, ComponentTypeEnum componentTypeEnum, String groupId,
1097 Component component = accessValidations.validateUserCanWorkOnComponent(componentId, componentTypeEnum, userId, DELETE_GROUP);
1099 GroupDefinition groupDefinition = findGroupOnComponent(component, groupId)
1101 .on(se -> onGroupNotFoundInComponentError(component, groupId));
1103 List<GroupDefinition> gdList = deleteGroups(component, java.util.Arrays.asList(groupDefinition))
1105 .on(this::onFailedGroupDBOperation);
1107 updatePolicyTargetReferencingDeletedGroup(groupId, component);
1108 return gdList.get(0);
1111 private List<GroupDefinition> onFailedGroupDBOperation(ResponseFormat responseFormat) {
1112 janusGraphDao.rollback();
1113 throw new ByResponseFormatComponentException(responseFormat);
1116 private GroupDefinition onFailedUpdateGroupDBOperation(ResponseFormat responseFormat) {
1117 janusGraphDao.rollback();
1118 throw new ByResponseFormatComponentException(responseFormat);
1121 private GroupDefinition onGroupNotFoundInComponentError(Component component, String groupId) {
1122 throw new ByActionStatusComponentException(ActionStatus.GROUP_IS_MISSING, groupId,
1123 component.getSystemName(), getComponentTypeForResponse(component));
1126 private GroupTypeDefinition onGroupTypeNotFound(Component component) {
1127 throw new ByActionStatusComponentException(ActionStatus.GROUP_TYPE_IS_INVALID, component.getSystemName(),
1128 component.getComponentType().toString());
1131 private void updatePolicyTargetReferencingDeletedGroup(String groupId, Component component) {
1132 log.debug("#updatePolicyTargetReferencingDeletedGroup - removing all component {} policy targets referencing group {}", component.getUniqueId(), groupId);
1133 ActionStatus actionStatus = policyTargetsUpdateHandler.removePoliciesTargets(component, groupId, PolicyTargetType.GROUPS);
1134 if (ActionStatus.OK != actionStatus) {
1135 janusGraphDao.rollback();
1136 throw new ByActionStatusComponentException(actionStatus, groupId);
1141 public Either<List<GroupDefinition>, ResponseFormat> createGroups(Component component, final List<GroupDefinition> groupDefinitions, boolean fromCsar) {
1143 Map<String, GroupDataDefinition> groups = new HashMap<>();
1144 Either<List<GroupDefinition>, ResponseFormat> result = null;
1145 Either<List<GroupDefinition>, StorageOperationStatus> createGroupsResult = null;
1146 Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> allDataTypes = dataTypeCache.getAll();
1147 if (allDataTypes.isRight()) {
1148 JanusGraphOperationStatus status = allDataTypes.right().value();
1149 BeEcompErrorManager.getInstance().logInternalFlowError("AddPropertyToGroup", "Failed to add property to group. Status is " + status, ErrorSeverity.ERROR);
1150 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status))));
1154 // handle groups and convert to tosca data
1155 if (groupDefinitions != null && !groupDefinitions.isEmpty()) {
1156 for (GroupDefinition groupDefinition : groupDefinitions) {
1157 Either<GroupDefinition, ResponseFormat> handleGroupRes = handleGroup(component, groupDefinition, allDataTypes.left().value());
1158 if (handleGroupRes.isRight()) {
1159 result = Either.right(handleGroupRes.right().value());
1162 GroupDefinition handledGroup = handleGroupRes.left().value();
1163 groups.put(handledGroup.getName(), new GroupDataDefinition(handledGroup));
1167 if (result == null) {
1168 createGroupsResult = groupsOperation.createGroups(component, groups);
1169 if (createGroupsResult.isRight()) {
1170 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(createGroupsResult.right().value())));
1173 if (result == null) {
1174 addCalculatedCapabilitiesWithPropertiesToComponent(component, groupDefinitions, fromCsar);
1176 if (result == null) {
1177 result = Either.left(groupDefinitions);
1182 private void updateCalculatedCapabilitiesWithPropertiesOnComponent(Component component, final List<GroupDefinition> groupDefinitions, boolean fromCsar) {
1183 groupDefinitions.forEach(GroupDefinition::updateEmptyCapabilitiesOwnerFields);
1184 StorageOperationStatus status = groupsOperation.updateCalculatedCapabilitiesWithProperties(component.getUniqueId(),
1185 extractCapabilitiesFromGroups(groupDefinitions), extractCapabilityPropertiesFromGroups(groupDefinitions, fromCsar));
1186 if(status != StorageOperationStatus.OK){
1187 log.error("#updateCalculatedCapabilitiesWithPropertiesOnComponent - failed to update the groups' calculated capabilities with the properties on the component {}. ", component.getUniqueId());
1188 rollbackWithException(componentsUtils.convertFromStorageResponse(status));
1192 private void addCalculatedCapabilitiesWithPropertiesToComponent(Component component, final List<GroupDefinition> groupDefinitions, boolean fromCsar) {
1193 groupDefinitions.forEach(GroupDefinition::updateEmptyCapabilitiesOwnerFields);
1194 StorageOperationStatus status = groupsOperation.addCalculatedCapabilitiesWithProperties(component.getUniqueId(),
1195 extractCapabilitiesFromGroups(groupDefinitions), extractCapabilityPropertiesFromGroups(groupDefinitions, fromCsar));
1196 if(status != StorageOperationStatus.OK){
1197 log.error("#addCalculatedCapabilitiesWithPropertiesToComponent - failed to add the groups' calculated capabilities with the properties to the component {}. ", component.getUniqueId());
1198 rollbackWithException(componentsUtils.convertFromStorageResponse(status));
1202 private void deleteCalculatedCapabilitiesWithPropertiesFromComponent(Component component, final List<GroupDefinition> groupDefinitions) {
1203 StorageOperationStatus status = groupsOperation.deleteCalculatedCapabilitiesWithProperties(component.getUniqueId(), groupDefinitions);
1204 if(status != StorageOperationStatus.OK){
1205 log.error("#deleteCalculatedCapabilitiesWithPropertiesFromComponent - failed to remove the groups' calculated capabilities with the properties from the component {}. ", component.getUniqueId());
1206 rollbackWithException(componentsUtils.convertFromStorageResponse(status));
1210 public Either<List<GroupDefinition>, ResponseFormat> addGroups(Component component, final List<GroupDefinition> groupDefinitions, boolean fromCsar) {
1212 Either<List<GroupDefinition>, ResponseFormat> result = null;
1213 Either<List<GroupDefinition>, StorageOperationStatus> createGroupsResult = null;
1214 List<GroupDataDefinition> groups = new ArrayList<>();
1216 Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> allDataTypes = dataTypeCache.getAll();
1217 if (allDataTypes.isRight()) {
1218 JanusGraphOperationStatus status = allDataTypes.right().value();
1219 BeEcompErrorManager.getInstance().logInternalFlowError("AddPropertyToGroup", "Failed to add property to group. Status is " + status, ErrorSeverity.ERROR);
1220 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status))));
1224 // handle groups and convert to tosca data
1225 if (groupDefinitions != null && !groupDefinitions.isEmpty()) {
1226 for (GroupDefinition groupDefinition : groupDefinitions) {
1227 Either<GroupDefinition, ResponseFormat> handleGroupRes = handleGroup(component, groupDefinition, allDataTypes.left().value());
1228 if (handleGroupRes.isRight()) {
1229 result = Either.right(handleGroupRes.right().value());
1232 GroupDefinition handledGroup = handleGroupRes.left().value();
1233 groups.add(new GroupDataDefinition(handledGroup));
1236 if (result == null) {
1237 createGroupsResult = groupsOperation.addGroups(component, groups);
1238 if (createGroupsResult.isRight()) {
1239 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(createGroupsResult.right().value())));
1242 if (result == null) {
1243 addCalculatedCapabilitiesWithPropertiesToComponent(component, groupDefinitions, fromCsar);
1245 if (result == null) {
1246 result = Either.left(groupDefinitions);
1251 public Either<List<GroupDefinition>, ResponseFormat> deleteGroups(Component component, List<GroupDefinition> groupDefinitions) {
1253 Either<List<GroupDefinition>, StorageOperationStatus> deleteGroupsResult;
1255 deleteGroupsResult = groupsOperation.deleteGroups(component, groupDefinitions.stream().map(GroupDataDefinition::new).collect(toList()));
1256 if (deleteGroupsResult.isRight()) {
1257 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(deleteGroupsResult.right().value())));
1259 deleteCalculatedCapabilitiesWithPropertiesFromComponent(component, groupDefinitions);
1261 return Either.left(deleteGroupsResult.left().value());
1265 * Update specific group version
1266 * @param fromCsar TODO
1269 public Either<List<GroupDefinition>, ResponseFormat> updateGroups(Component component, List<GroupDefinition> groupDefinitions, boolean fromCsar) {
1271 Either<List<GroupDefinition>, ResponseFormat> result = null;
1272 Either<List<GroupDefinition>, StorageOperationStatus> createGroupsResult;
1274 createGroupsResult = groupsOperation.updateGroups(component, groupDefinitions.stream().map(GroupDataDefinition::new).collect(toList()), true);
1275 if (createGroupsResult.isRight()) {
1276 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(createGroupsResult.right().value())));
1278 if (result == null) {
1279 updateCalculatedCapabilitiesWithPropertiesOnComponent(component, groupDefinitions, fromCsar);
1281 if (result == null) {
1282 result = Either.left(groupDefinitions);
1287 private Either<GroupDefinition, ResponseFormat> handleGroup(Component component, GroupDefinition groupDefinition, Map<String, DataTypeDefinition> allDAtaTypes) {
1289 log.trace("Going to create group {}", groupDefinition);
1290 // 3. verify group not already exist
1291 String groupDefinitionName = groupDefinition.getName();
1292 if (groupExistsInComponent(groupDefinitionName, component)) {
1293 String componentTypeForResponse = getComponentTypeForResponse(component);
1294 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_ALREADY_EXIST, groupDefinitionName, component.getNormalizedName(), componentTypeForResponse));
1296 // 4. verify type of group exist
1297 String groupType = groupDefinition.getType();
1298 if (StringUtils.isEmpty(groupType)) {
1299 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_MISSING_GROUP_TYPE, groupDefinitionName));
1301 Either<GroupTypeDefinition, StorageOperationStatus> getGroupType = groupTypeOperation.getLatestGroupTypeByType(groupType, true);
1302 if (getGroupType.isRight()) {
1303 StorageOperationStatus status = getGroupType.right().value();
1304 if (status == StorageOperationStatus.NOT_FOUND) {
1305 BeEcompErrorManager.getInstance().logInvalidInputError(CREATE_GROUP, "group type " + groupType + " cannot be found", ErrorSeverity.INFO);
1306 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_TYPE_IS_INVALID, groupType));
1308 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
1311 // 6. verify the component instances type are allowed according to
1312 // the member types in the group type
1313 GroupTypeDefinition groupTypeDefinition = getGroupType.left().value();
1315 Either<Boolean, ResponseFormat> areValidMembers = verifyComponentInstancesAreValidMembers(component, groupDefinitionName, groupDefinition.getMembers(), groupTypeDefinition.getMembers());
1317 if (areValidMembers.isRight()) {
1318 ResponseFormat responseFormat = areValidMembers.right().value();
1319 return Either.right(responseFormat);
1321 // 7. verify the artifacts belongs to the component
1322 Either<Boolean, ResponseFormat> areValidArtifacts = verifyArtifactsBelongsToComponent(component, groupDefinition.getArtifacts(), CREATE_GROUP);
1323 if (areValidArtifacts.isRight()) {
1324 ResponseFormat responseFormat = areValidArtifacts.right().value();
1325 return Either.right(responseFormat);
1327 List<PropertyDefinition> groupTypeProperties = groupTypeDefinition.getProperties();
1329 List<GroupProperty> properties = groupDefinition.convertToGroupProperties();
1330 List<GroupProperty> updatedGroupTypeProperties = new ArrayList<>();
1331 if (CollectionUtils.isNotEmpty(properties)) {
1332 if (CollectionUtils.isEmpty(groupTypeProperties)) {
1333 BeEcompErrorManager.getInstance().logInvalidInputError(ADDING_GROUP, "group type does not have properties", ErrorSeverity.INFO);
1334 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(JanusGraphOperationStatus.MATCH_NOT_FOUND))));
1337 Map<String, PropertyDefinition> groupTypePropertiesMap = groupTypeProperties.stream().collect(Collectors.toMap(PropertyDefinition::getName, p -> p));
1339 Either<GroupProperty, JanusGraphOperationStatus> addPropertyResult;
1341 for (GroupProperty prop : properties) {
1342 addPropertyResult = handleProperty(prop, groupTypePropertiesMap.get(prop.getName()), i, allDAtaTypes, groupType);
1343 if (addPropertyResult.isRight()) {
1344 BeEcompErrorManager.getInstance().logInvalidInputError(ADDING_GROUP, "failed to validate property", ErrorSeverity.INFO);
1345 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(addPropertyResult.right().value()))));
1347 updatedGroupTypeProperties.add(addPropertyResult.left().value());
1353 if (groupDefinition.getUniqueId() == null) {
1354 String uid = UniqueIdBuilder.buildGroupingUid(component.getUniqueId(), groupDefinitionName);
1355 groupDefinition.setUniqueId(uid);
1357 groupDefinition.convertFromGroupProperties(updatedGroupTypeProperties);
1358 groupDefinition.setInvariantUUID(UniqueIdBuilder.buildInvariantUUID());
1359 groupDefinition.setGroupUUID(UniqueIdBuilder.generateUUID());
1360 groupDefinition.setVersion(INITIAL_VERSION);
1361 groupDefinition.setTypeUid(groupTypeDefinition.getUniqueId());
1363 return Either.left(groupDefinition);
1366 private static boolean groupExistsInComponent(String groupDefinitionName, Component component) {
1367 boolean found = false;
1368 List<GroupDefinition> groups = component.getGroups();
1369 if (CollectionUtils.isNotEmpty(groups)) {
1370 found = groups.stream().filter(p -> p.getName().equalsIgnoreCase(groupDefinitionName)).findFirst().orElse(null) != null;
1375 private Either<GroupProperty, JanusGraphOperationStatus> handleProperty(GroupProperty groupProperty, PropertyDefinition prop, Integer index, Map<String, DataTypeDefinition> allDataTypes, String groupType) {
1378 return Either.right(JanusGraphOperationStatus.ILLEGAL_ARGUMENT);
1381 String propertyType = prop.getType();
1382 String value = groupProperty.getValue();
1384 Either<String, JanusGraphOperationStatus> checkInnerType = propertyOperation.checkInnerType(prop);
1385 if (checkInnerType.isRight()) {
1386 JanusGraphOperationStatus status = checkInnerType.right().value();
1387 return Either.right(status);
1390 String innerType = checkInnerType.left().value();
1392 log.debug("Before validateAndUpdatePropertyValue");
1393 Either<Object, Boolean> isValid = propertyOperation.validateAndUpdatePropertyValue(propertyType, value, innerType, allDataTypes);
1394 log.debug("After validateAndUpdatePropertyValue. isValid = {}", isValid);
1396 String newValue = value;
1397 if (isValid.isRight()) {
1398 Boolean res = isValid.right().value();
1400 return Either.right(JanusGraphOperationStatus.ILLEGAL_ARGUMENT);
1403 Object object = isValid.left().value();
1404 if (object != null) {
1405 newValue = object.toString();
1409 String uniqueId = shouldReconstructUniqueId(groupType) ? UniqueIdBuilder.buildGroupPropertyValueUid(prop.getUniqueId(), index)
1410 : prop.getUniqueId();
1412 groupProperty.setUniqueId(uniqueId);
1413 groupProperty.setValue(newValue);
1414 groupProperty.setType(prop.getType());
1415 groupProperty.setDefaultValue(prop.getDefaultValue());
1416 groupProperty.setDescription(prop.getDescription());
1417 groupProperty.setSchema(prop.getSchema());
1418 groupProperty.setPassword(prop.isPassword());
1419 groupProperty.setParentUniqueId(prop.getUniqueId());
1421 log.debug("Before adding property value to graph {}", groupProperty);
1423 return Either.left(groupProperty);
1426 // For old groups we want to leave indexing of property
1427 // For new groups we just need the types
1428 private boolean shouldReconstructUniqueId(String groupType) {
1429 return Constants.GROUP_TOSCA_HEAT.equals(groupType) || Constants.DEFAULT_GROUP_VF_MODULE.equals(groupType);