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.vendorsoftwareproduct.impl;
23 import org.apache.commons.collections4.CollectionUtils;
24 import org.apache.commons.collections4.MapUtils;
25 import org.openecomp.core.utilities.CommonMethods;
26 import org.openecomp.core.utilities.json.JsonSchemaDataGenerator;
27 import org.openecomp.core.utilities.json.JsonUtil;
28 import org.openecomp.sdc.common.errors.CoreException;
29 import org.openecomp.sdc.common.errors.ErrorCategory;
30 import org.openecomp.sdc.common.errors.ErrorCode;
31 import org.openecomp.sdc.logging.api.Logger;
32 import org.openecomp.sdc.logging.api.LoggerFactory;
33 import org.openecomp.sdc.vendorsoftwareproduct.CompositionEntityDataManager;
34 import org.openecomp.sdc.vendorsoftwareproduct.dao.ComponentDao;
35 import org.openecomp.sdc.vendorsoftwareproduct.dao.ComputeDao;
36 import org.openecomp.sdc.vendorsoftwareproduct.dao.DeploymentFlavorDao;
37 import org.openecomp.sdc.vendorsoftwareproduct.dao.ImageDao;
38 import org.openecomp.sdc.vendorsoftwareproduct.dao.NetworkDao;
39 import org.openecomp.sdc.vendorsoftwareproduct.dao.NicDao;
40 import org.openecomp.sdc.vendorsoftwareproduct.dao.VendorSoftwareProductInfoDao;
41 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.ComponentEntity;
42 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.CompositionEntity;
43 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.ComputeEntity;
44 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.DeploymentFlavorEntity;
45 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.ImageEntity;
46 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.NetworkEntity;
47 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.NicEntity;
48 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspDetails;
49 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspQuestionnaireEntity;
50 import org.openecomp.sdc.vendorsoftwareproduct.services.schemagenerator.SchemaGenerator;
51 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.Component;
52 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.ComponentData;
53 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.CompositionData;
54 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.CompositionEntityId;
55 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.CompositionEntityType;
56 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.CompositionEntityValidationData;
57 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.ComputeData;
58 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.Image;
59 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.Network;
60 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.NetworkType;
61 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.Nic;
62 import org.openecomp.sdc.vendorsoftwareproduct.types.schemagenerator.SchemaTemplateContext;
63 import org.openecomp.sdc.vendorsoftwareproduct.types.schemagenerator.SchemaTemplateInput;
64 import org.openecomp.sdc.versioning.dao.types.Version;
66 import java.util.ArrayList;
67 import java.util.Collection;
68 import java.util.Collections;
69 import java.util.EnumMap;
70 import java.util.HashMap;
71 import java.util.HashSet;
72 import java.util.List;
74 import java.util.Objects;
77 public class CompositionEntityDataManagerImpl implements CompositionEntityDataManager {
79 private static final String COMPOSITION_ENTITY_DATA_MANAGER_ERR =
80 "COMPOSITION_ENTITY_DATA_MANAGER_ERR";
81 private static final String COMPOSITION_ENTITY_DATA_MANAGER_ERR_MSG =
82 "Invalid input: %s may not be null";
83 private static final String MISSING_OR_INVALID_QUESTIONNAIRE_MSG =
84 "Data is missing/invalid for this %s. Please refill and resubmit.";
86 private static final Logger logger =
87 LoggerFactory.getLogger(CompositionEntityDataManagerImpl.class);
88 private Map<CompositionEntityId, CompositionEntityData> entities = new HashMap<>();
89 private Map<CompositionEntityType, String> nonDynamicSchemas =
90 new EnumMap<>(CompositionEntityType.class);
91 private List<CompositionEntityValidationData> roots = new ArrayList<>();
93 private VendorSoftwareProductInfoDao vspInfoDao;
94 private ComponentDao componentDao;
95 private NicDao nicDao;
96 private NetworkDao networkDao;
97 private ImageDao imageDao;
98 private ComputeDao computeDao;
99 private DeploymentFlavorDao deploymentFlavorDao;
101 public CompositionEntityDataManagerImpl(VendorSoftwareProductInfoDao vspInfoDao,
102 ComponentDao componentDao,
103 NicDao nicDao, NetworkDao networkDao,
104 ImageDao imageDao, ComputeDao computeDao,
105 DeploymentFlavorDao deploymentFlavorDao) {
106 this.vspInfoDao = vspInfoDao;
107 this.componentDao = componentDao;
108 this.nicDao = nicDao;
109 this.networkDao = networkDao;
110 this.imageDao = imageDao;
111 this.computeDao = computeDao;
112 this.deploymentFlavorDao = deploymentFlavorDao;
116 * Validate entity composition entity validation data.
118 * @param entity the entity
119 * @param schemaTemplateContext the schema template context
120 * @param schemaTemplateInput the schema template input
121 * @return the composition entity validation data
124 public CompositionEntityValidationData validateEntity(CompositionEntity entity,
125 SchemaTemplateContext schemaTemplateContext,
126 SchemaTemplateInput schemaTemplateInput) {
127 if (entity == null) {
128 throw new CoreException(
129 new ErrorCode.ErrorCodeBuilder().withCategory(ErrorCategory.APPLICATION)
130 .withId(COMPOSITION_ENTITY_DATA_MANAGER_ERR).withMessage(
131 String.format(COMPOSITION_ENTITY_DATA_MANAGER_ERR_MSG, "composition entity"))
134 if (schemaTemplateContext == null) {
135 throw new CoreException(
136 new ErrorCode.ErrorCodeBuilder().withCategory(ErrorCategory.APPLICATION)
137 .withId(COMPOSITION_ENTITY_DATA_MANAGER_ERR).withMessage(
138 String.format(COMPOSITION_ENTITY_DATA_MANAGER_ERR_MSG, "schema template context"))
142 CompositionEntityValidationData validationData =
143 new CompositionEntityValidationData(entity.getType(), entity.getId());
145 schemaTemplateContext == SchemaTemplateContext.composition ? entity.getCompositionData()
146 : entity.getQuestionnaireData();
147 validationData.setErrors(JsonUtil.validate(
148 json == null ? JsonUtil.object2Json(new Object()) : json,
149 generateSchema(schemaTemplateContext, entity.getType(), schemaTemplateInput)));
150 return validationData;
156 * @param entity the entity
157 * @param schemaTemplateInput the schema template input
160 public void addEntity(CompositionEntity entity, SchemaTemplateInput schemaTemplateInput) {
161 if (entity == null) {
162 throw new CoreException(
163 new ErrorCode.ErrorCodeBuilder().withCategory(ErrorCategory.APPLICATION)
164 .withId(COMPOSITION_ENTITY_DATA_MANAGER_ERR).withMessage(
165 String.format(COMPOSITION_ENTITY_DATA_MANAGER_ERR_MSG, "composition entity"))
168 entities.put(entity.getCompositionEntityId(),
169 new CompositionEntityData(entity, schemaTemplateInput));
173 * Validate entities questionnaire map.
178 public Map<CompositionEntityId, Collection<String>> validateEntitiesQuestionnaire() {
179 Map<CompositionEntityId, Collection<String>> errorsByEntityId = new HashMap<>();
180 entities.forEach((key, value) -> {
181 Collection<String> errors = validateQuestionnaire(value);
182 if (errors != null) {
183 errorsByEntityId.put(key, errors);
186 return errorsByEntityId;
193 public void buildTrees() {
194 Map<CompositionEntityId, CompositionEntityValidationData> entitiesValidationData =
196 entities.forEach((key, value) -> addValidationDataEntity(entitiesValidationData, key,
200 public Collection<CompositionEntityValidationData> getTrees() {
205 public void saveCompositionData(String vspId, Version version, CompositionData compositionData) {
206 if (Objects.isNull(compositionData)) {
210 Map<String, String> networkIdByName = saveNetworks(vspId, version, compositionData);
211 saveComponents(vspId, version, compositionData, networkIdByName);
215 public Set<CompositionEntityValidationData> getAllErrorsByVsp(String vspId) {
216 Set<CompositionEntityValidationData> entitiesWithErrors = new HashSet<>();
217 for (CompositionEntityValidationData root : roots) {
218 if (root.getEntityId().equals(vspId)) {
219 getEntityListWithErrors(root, entitiesWithErrors);
224 if (CollectionUtils.isNotEmpty(entitiesWithErrors)) {
225 updateValidationCompositionEntityName(entitiesWithErrors);
226 return entitiesWithErrors;
229 return new HashSet<>();
232 private boolean isThereErrorsInSubTree(CompositionEntityValidationData entity) {
233 if (Objects.isNull(entity)) {
237 if (CollectionUtils.isNotEmpty(entity.getErrors())) {
241 Collection<CompositionEntityValidationData> subEntitiesValidationData =
242 entity.getSubEntitiesValidationData();
243 return !CollectionUtils.isEmpty(subEntitiesValidationData) &&
244 checkForErrorsInChildren(subEntitiesValidationData);
248 private boolean checkForErrorsInChildren(
249 Collection<CompositionEntityValidationData> subEntitiesValidationData) {
250 boolean result = false;
251 for (CompositionEntityValidationData subEntity : subEntitiesValidationData) {
252 if (CollectionUtils.isNotEmpty(subEntity.getErrors())) {
256 result = isThereErrorsInSubTree(subEntity) || result;
264 private void saveComponents(String vspId, Version version, CompositionData compositionData,
265 Map<String, String> networkIdByName) {
266 if (CollectionUtils.isNotEmpty(compositionData.getComponents())) {
267 for (Component component : compositionData.getComponents()) {
268 ComponentEntity componentEntity = new ComponentEntity(vspId, version, null);
269 componentEntity.setComponentCompositionData(component.getData());
271 String componentId = createComponent(componentEntity).getId();
273 saveImagesByComponent(vspId, version, component, componentId);
274 saveComputesFlavorByComponent(vspId, version, component, componentId);
276 saveNicsByComponent(vspId, version, networkIdByName, component, componentId);
281 private void saveNicsByComponent(String vspId, Version version,
282 Map<String, String> networkIdByName, Component component,
283 String componentId) {
284 if (CollectionUtils.isNotEmpty(component.getNics())) {
285 for (Nic nic : component.getNics()) {
286 if (nic.getNetworkName() != null && MapUtils.isNotEmpty(networkIdByName)) {
287 nic.setNetworkId(networkIdByName.get(nic.getNetworkName()));
289 nic.setNetworkName(null);
290 //For heat flow set network type to be internal by default for NIC
291 nic.setNetworkType(NetworkType.Internal);
293 NicEntity nicEntity = new NicEntity(vspId, version, componentId, null);
294 nicEntity.setNicCompositionData(nic);
295 createNic(nicEntity);
300 private Map<String, String> saveNetworks(String vspId, Version version,
301 CompositionData compositionData) {
302 Map<String, String> networkIdByName = new HashMap<>();
303 if (CollectionUtils.isNotEmpty(compositionData.getNetworks())) {
304 for (Network network : compositionData.getNetworks()) {
306 NetworkEntity networkEntity = new NetworkEntity(vspId, version, null);
307 networkEntity.setNetworkCompositionData(network);
309 if (network.getName() != null) {
310 networkIdByName.put(network.getName(), createNetwork(networkEntity).getId());
314 return networkIdByName;
317 private NetworkEntity createNetwork(NetworkEntity network) {
318 //network.setId(CommonMethods.nextUuId()); will be set by the dao
319 networkDao.create(network);
324 public ComponentEntity createComponent(ComponentEntity component) {
325 //component.setId(CommonMethods.nextUuId()); will be set by the dao
326 component.setQuestionnaireData(
327 new JsonSchemaDataGenerator(
328 generateSchema(SchemaTemplateContext.questionnaire, CompositionEntityType.component,
332 componentDao.create(component);
337 public NicEntity createNic(NicEntity nic) {
338 //nic.setId(CommonMethods.nextUuId()); will be set by the dao
339 nic.setQuestionnaireData(
340 new JsonSchemaDataGenerator(
341 generateSchema(SchemaTemplateContext.questionnaire, CompositionEntityType.nic, null))
349 public void addErrorsToTrees(Map<CompositionEntityId, Collection<String>> errors) {
350 roots.forEach(root -> addErrorsToTree(root, null, errors));
354 * get a flat list of all questionnaire entities that have validation errors
356 public Set<CompositionEntityValidationData> getEntityListWithErrors() {
357 Set<CompositionEntityValidationData> treeAsList = new HashSet<>();
359 for (CompositionEntityValidationData entity : roots) {
360 if (CollectionUtils.isNotEmpty(entity.getErrors())) {
361 addNodeWithErrors(entity, treeAsList);
363 getEntityListWithErrors(entity, treeAsList);
366 updateValidationCompositionEntityName(treeAsList);
370 private void getEntityListWithErrors(CompositionEntityValidationData entity,
371 Set<CompositionEntityValidationData> compositionSet) {
372 if (CollectionUtils.isNotEmpty(entity.getErrors())) {
373 addNodeWithErrors(entity, compositionSet);
376 if (CollectionUtils.isEmpty(entity.getSubEntitiesValidationData())) {
380 for (CompositionEntityValidationData child : entity.getSubEntitiesValidationData()) {
381 getEntityListWithErrors(child, compositionSet);
386 private void addNodeWithErrors(CompositionEntityValidationData node,
387 Set<CompositionEntityValidationData> entitiesWithErrors) {
388 CompositionEntityValidationData compositionNodeToAdd = new CompositionEntityValidationData(node
389 .getEntityType(), node.getEntityId());
390 compositionNodeToAdd.setErrors(node.getErrors());
391 compositionNodeToAdd.setSubEntitiesValidationData(null);
393 entitiesWithErrors.add(compositionNodeToAdd);
396 public void removeNodesWithoutErrors() {
397 roots.forEach(root -> removeNodesWithoutErrors(root, null));
401 private CompositionEntityData getCompositionEntityDataById(CompositionEntityValidationData
403 for (Map.Entry<CompositionEntityId, CompositionEntityData> entityEntry : entities
405 if (entityEntry.getKey().getId().equals(entity.getEntityId())) {
406 return entityEntry.getValue();
413 private void updateValidationCompositionEntityName(Set<CompositionEntityValidationData>
415 for (CompositionEntityValidationData entity : compositionSet) {
416 String compositionData = getCompositionDataAsString(entity);
417 if (entity.getEntityType().equals(CompositionEntityType.vsp) ||
418 Objects.nonNull(compositionData)) {
419 entity.setEntityName(getEntityNameByEntityType(compositionData, entity));
424 private String getCompositionDataAsString(CompositionEntityValidationData entity) {
425 CompositionEntityData compositionEntityData = getCompositionEntityDataById(entity);
426 return compositionEntityData == null ? null : compositionEntityData.entity.getCompositionData();
430 private String getEntityNameByEntityType(String compositionData,
431 CompositionEntityValidationData entity) {
432 switch (entity.getEntityType()) {
434 ComponentData component = JsonUtil.json2Object(compositionData, ComponentData.class);
435 return component.getDisplayName();
438 Nic nic = JsonUtil.json2Object(compositionData, Nic.class);
439 return nic.getName();
442 Network network = JsonUtil.json2Object(compositionData, Network.class);
443 return network.getName();
446 Image image = JsonUtil.json2Object(compositionData, Image.class);
447 return image.getFileName();
450 ComputeData compute = JsonUtil.json2Object(compositionData, ComputeData.class);
451 return compute.getName();
454 CompositionEntityData vspEntity = getCompositionEntityDataById(entity);
455 if (Objects.isNull(vspEntity)) {
458 VspQuestionnaireEntity vspQuestionnaireEntity = (VspQuestionnaireEntity) vspEntity.entity;
459 VspDetails vspDetails =
460 vspInfoDao.get(new VspDetails(vspQuestionnaireEntity.getId(),
461 vspQuestionnaireEntity.getVersion()));
462 return vspDetails.getName();
468 private void removeNodesWithoutErrors(CompositionEntityValidationData node,
469 CompositionEntityValidationData parent) {
471 if (Objects.isNull(node)) {
475 if (hasChildren(node)) {
476 Collection<CompositionEntityValidationData> subNodes =
477 new ArrayList<>(node.getSubEntitiesValidationData());
478 subNodes.forEach(subNode -> removeNodesWithoutErrors(subNode, node));
479 node.setSubEntitiesValidationData(subNodes);
481 if (canNodeGetRemovedFromValidationDataTree(node)) {
482 removeNodeFromChildren(parent, node);
484 } else if (canNodeGetRemovedFromValidationDataTree(node)) {
485 removeNodeFromChildren(parent, node);
489 private void removeNodeFromChildren(CompositionEntityValidationData parent,
490 CompositionEntityValidationData childToRemove) {
491 if (!Objects.isNull(parent)) {
492 parent.getSubEntitiesValidationData().remove(childToRemove);
496 private boolean hasChildren(CompositionEntityValidationData node) {
497 return !CollectionUtils.isEmpty(node.getSubEntitiesValidationData());
500 private boolean canNodeGetRemovedFromValidationDataTree(CompositionEntityValidationData node) {
501 return !hasChildren(node) && CollectionUtils.isEmpty(node.getErrors());
505 private void addValidationDataEntity(
506 Map<CompositionEntityId, CompositionEntityValidationData> entitiesValidationData,
507 CompositionEntityId entityId, CompositionEntity entity) {
508 if (entitiesValidationData.containsKey(entityId)) {
512 CompositionEntityValidationData validationData =
513 new CompositionEntityValidationData(entity.getType(), entity.getId());
514 entitiesValidationData.put(entityId, validationData);
516 CompositionEntityId parentEntityId = entityId.getParentId();
517 if (parentEntityId == null) {
518 roots.add(validationData);
520 CompositionEntityData parentEntity = entities.get(parentEntityId);
521 if (parentEntity == null) {
522 roots.add(validationData);
524 addValidationDataEntity(entitiesValidationData, parentEntityId, parentEntity.entity);
525 entitiesValidationData.get(parentEntityId).addSubEntityValidationData(validationData);
530 private void addErrorsToTree(CompositionEntityValidationData node,
531 CompositionEntityId parentNodeId,
532 Map<CompositionEntityId, Collection<String>> errors) {
536 CompositionEntityId nodeId = new CompositionEntityId(node.getEntityId(), parentNodeId);
537 node.setErrors(errors.get(nodeId));
539 if (node.getSubEntitiesValidationData() != null) {
540 node.getSubEntitiesValidationData()
541 .forEach(subNode -> addErrorsToTree(subNode, nodeId, errors));
545 private Collection<String> validateQuestionnaire(CompositionEntityData compositionEntityData) {
546 logger.debug(String.format("validateQuestionnaire start: " +
547 "[entity.type]=%s, [entity.id]=%s, [entity.questionnaireString]=%s",
548 compositionEntityData.entity.getType().name(),
549 compositionEntityData.entity.getCompositionEntityId().toString(),
550 compositionEntityData.entity.getQuestionnaireData()));
552 if (Objects.isNull(compositionEntityData.entity.getQuestionnaireData()) ||
553 !JsonUtil.isValidJson(compositionEntityData.entity.getQuestionnaireData())) {
554 return Collections.singletonList(String
555 .format(MISSING_OR_INVALID_QUESTIONNAIRE_MSG, compositionEntityData.entity.getType()));
558 return JsonUtil.validate(
559 compositionEntityData.entity.getQuestionnaireData() == null
560 ? JsonUtil.object2Json(new Object())
561 : compositionEntityData.entity.getQuestionnaireData(),
562 getSchema(compositionEntityData.entity.getType(), SchemaTemplateContext.questionnaire,
563 compositionEntityData.schemaTemplateInput));
566 private String getSchema(CompositionEntityType compositionEntityType,
567 SchemaTemplateContext schemaTemplateContext,
568 SchemaTemplateInput schemaTemplateInput) {
569 return schemaTemplateInput == null
570 ? nonDynamicSchemas.computeIfAbsent(compositionEntityType,
571 k -> generateSchema(schemaTemplateContext, compositionEntityType, null))
572 : generateSchema(schemaTemplateContext, compositionEntityType, schemaTemplateInput);
575 private static class CompositionEntityData {
576 private CompositionEntity entity;
577 private SchemaTemplateInput schemaTemplateInput;
579 CompositionEntityData(CompositionEntity entity, SchemaTemplateInput schemaTemplateInput) {
580 this.entity = entity;
581 this.schemaTemplateInput = schemaTemplateInput;
586 // todo - make SchemaGenerator non static and mock it in UT instead of mocking this method (and
587 // make the method private
588 protected String generateSchema(SchemaTemplateContext schemaTemplateContext,
589 CompositionEntityType compositionEntityType,
590 SchemaTemplateInput schemaTemplateInput) {
591 return SchemaGenerator
592 .generate(schemaTemplateContext, compositionEntityType, schemaTemplateInput);
596 public DeploymentFlavorEntity createDeploymentFlavor(DeploymentFlavorEntity deploymentFlavor) {
597 deploymentFlavor.setId(CommonMethods.nextUuId());
598 deploymentFlavorDao.create(deploymentFlavor);
599 return deploymentFlavor;
603 public ImageEntity createImage(ImageEntity image) {
604 image.setId(CommonMethods.nextUuId());
606 image.setQuestionnaireData(
607 new JsonSchemaDataGenerator(SchemaGenerator
608 .generate(SchemaTemplateContext.questionnaire, CompositionEntityType.image, null))
611 imageDao.create(image);
615 public void saveComputesFlavorByComponent(String vspId, Version version, Component component,
616 String componentId) {
617 if (CollectionUtils.isNotEmpty(component.getCompute())) {
618 for (ComputeData flavor : component.getCompute()) {
619 ComputeEntity computeEntity = new ComputeEntity(vspId, version, componentId, null);
620 computeEntity.setComputeCompositionData(flavor);
621 computeEntity.setQuestionnaireData(
622 new JsonSchemaDataGenerator(SchemaGenerator
623 .generate(SchemaTemplateContext.questionnaire, CompositionEntityType.compute,
624 null)).generateData());
626 computeDao.create(computeEntity);
631 public void saveImagesByComponent(String vspId, Version version, Component component, String
633 if (CollectionUtils.isNotEmpty(component.getImages())) {
634 for (Image img : component.getImages()) {
635 ImageEntity imageEntity = new ImageEntity(vspId, version, componentId, null);
636 imageEntity.setImageCompositionData(img);
637 createImage(imageEntity);