2 * Copyright © 2016-2018 European Support Limited
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org.openecomp.sdc.vendorsoftwareproduct.impl;
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.EnumMap;
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.List;
27 import java.util.Objects;
29 import org.apache.commons.collections4.CollectionUtils;
30 import org.apache.commons.collections4.MapUtils;
31 import org.openecomp.core.utilities.CommonMethods;
32 import org.openecomp.core.utilities.json.JsonSchemaDataGenerator;
33 import org.openecomp.core.utilities.json.JsonUtil;
34 import org.openecomp.sdc.common.errors.CoreException;
35 import org.openecomp.sdc.common.errors.ErrorCategory;
36 import org.openecomp.sdc.common.errors.ErrorCode;
37 import org.openecomp.sdc.logging.api.Logger;
38 import org.openecomp.sdc.logging.api.LoggerFactory;
39 import org.openecomp.sdc.vendorsoftwareproduct.CompositionEntityDataManager;
40 import org.openecomp.sdc.vendorsoftwareproduct.dao.ComponentDao;
41 import org.openecomp.sdc.vendorsoftwareproduct.dao.ComputeDao;
42 import org.openecomp.sdc.vendorsoftwareproduct.dao.DeploymentFlavorDao;
43 import org.openecomp.sdc.vendorsoftwareproduct.dao.ImageDao;
44 import org.openecomp.sdc.vendorsoftwareproduct.dao.NetworkDao;
45 import org.openecomp.sdc.vendorsoftwareproduct.dao.NicDao;
46 import org.openecomp.sdc.vendorsoftwareproduct.dao.VendorSoftwareProductInfoDao;
47 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.ComponentEntity;
48 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.CompositionEntity;
49 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.ComputeEntity;
50 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.DeploymentFlavorEntity;
51 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.ImageEntity;
52 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.NetworkEntity;
53 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.NicEntity;
54 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspDetails;
55 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspQuestionnaireEntity;
56 import org.openecomp.sdc.vendorsoftwareproduct.services.schemagenerator.SchemaGenerator;
57 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.Component;
58 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.ComponentData;
59 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.CompositionData;
60 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.CompositionEntityId;
61 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.CompositionEntityType;
62 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.CompositionEntityValidationData;
63 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.ComputeData;
64 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.Image;
65 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.Network;
66 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.NetworkType;
67 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.Nic;
68 import org.openecomp.sdc.vendorsoftwareproduct.types.schemagenerator.ComponentQuestionnaireSchemaInput;
69 import org.openecomp.sdc.vendorsoftwareproduct.types.schemagenerator.SchemaTemplateContext;
70 import org.openecomp.sdc.vendorsoftwareproduct.types.schemagenerator.SchemaTemplateInput;
71 import org.openecomp.sdc.versioning.dao.types.Version;
73 public class CompositionEntityDataManagerImpl implements CompositionEntityDataManager {
75 private static final String COMPOSITION_ENTITY_DATA_MANAGER_ERR =
76 "COMPOSITION_ENTITY_DATA_MANAGER_ERR";
77 private static final String COMPOSITION_ENTITY_DATA_MANAGER_ERR_MSG =
78 "Invalid input: %s may not be null";
79 private static final String MISSING_OR_INVALID_QUESTIONNAIRE_MSG =
80 "Data is missing/invalid for this %s. Please refill and resubmit.";
82 private static final Logger logger =
83 LoggerFactory.getLogger(CompositionEntityDataManagerImpl.class);
84 private Map<CompositionEntityId, CompositionEntityData> entities = new HashMap<>();
85 private Map<CompositionEntityType, String> nonDynamicSchemas =
86 new EnumMap<>(CompositionEntityType.class);
87 private List<CompositionEntityValidationData> roots = new ArrayList<>();
89 private VendorSoftwareProductInfoDao vspInfoDao;
90 private ComponentDao componentDao;
91 private NicDao nicDao;
92 private NetworkDao networkDao;
93 private ImageDao imageDao;
94 private ComputeDao computeDao;
95 private DeploymentFlavorDao deploymentFlavorDao;
97 public CompositionEntityDataManagerImpl(VendorSoftwareProductInfoDao vspInfoDao,
98 ComponentDao componentDao,
99 NicDao nicDao, NetworkDao networkDao,
100 ImageDao imageDao, ComputeDao computeDao,
101 DeploymentFlavorDao deploymentFlavorDao) {
102 this.vspInfoDao = vspInfoDao;
103 this.componentDao = componentDao;
104 this.nicDao = nicDao;
105 this.networkDao = networkDao;
106 this.imageDao = imageDao;
107 this.computeDao = computeDao;
108 this.deploymentFlavorDao = deploymentFlavorDao;
112 * Validate entity composition entity validation data.
114 * @param entity the entity
115 * @param schemaTemplateContext the schema template context
116 * @param schemaTemplateInput the schema template input
117 * @return the composition entity validation data
120 public CompositionEntityValidationData validateEntity(CompositionEntity entity,
121 SchemaTemplateContext schemaTemplateContext,
122 SchemaTemplateInput schemaTemplateInput) {
123 if (entity == null) {
124 throw new CoreException(
125 new ErrorCode.ErrorCodeBuilder().withCategory(ErrorCategory.APPLICATION)
126 .withId(COMPOSITION_ENTITY_DATA_MANAGER_ERR).withMessage(
127 String.format(COMPOSITION_ENTITY_DATA_MANAGER_ERR_MSG, "composition entity"))
130 if (schemaTemplateContext == null) {
131 throw new CoreException(
132 new ErrorCode.ErrorCodeBuilder().withCategory(ErrorCategory.APPLICATION)
133 .withId(COMPOSITION_ENTITY_DATA_MANAGER_ERR).withMessage(
134 String.format(COMPOSITION_ENTITY_DATA_MANAGER_ERR_MSG, "schema template context"))
138 CompositionEntityValidationData validationData =
139 new CompositionEntityValidationData(entity.getType(), entity.getId());
141 schemaTemplateContext == SchemaTemplateContext.composition ? entity.getCompositionData()
142 : entity.getQuestionnaireData();
143 validationData.setErrors(JsonUtil.validate(
144 json == null ? JsonUtil.object2Json(new Object()) : json,
145 generateSchema(schemaTemplateContext, entity.getType(), schemaTemplateInput)));
146 return validationData;
152 * @param entity the entity
153 * @param schemaTemplateInput the schema template input
156 public void addEntity(CompositionEntity entity, SchemaTemplateInput schemaTemplateInput) {
157 if (entity == null) {
158 throw new CoreException(
159 new ErrorCode.ErrorCodeBuilder().withCategory(ErrorCategory.APPLICATION)
160 .withId(COMPOSITION_ENTITY_DATA_MANAGER_ERR).withMessage(
161 String.format(COMPOSITION_ENTITY_DATA_MANAGER_ERR_MSG, "composition entity"))
164 entities.put(entity.getCompositionEntityId(),
165 new CompositionEntityData(entity, schemaTemplateInput));
169 * Validate entities questionnaire map.
174 public Map<CompositionEntityId, Collection<String>> validateEntitiesQuestionnaire() {
175 Map<CompositionEntityId, Collection<String>> errorsByEntityId = new HashMap<>();
176 entities.forEach((key, value) -> {
177 Collection<String> errors = validateQuestionnaire(value);
178 if (errors != null) {
179 errorsByEntityId.put(key, errors);
182 return errorsByEntityId;
189 public void buildTrees() {
190 Map<CompositionEntityId, CompositionEntityValidationData> entitiesValidationData =
192 entities.forEach((key, value) -> addValidationDataEntity(entitiesValidationData, key,
196 public Collection<CompositionEntityValidationData> getTrees() {
201 public void saveCompositionData(String vspId, Version version, CompositionData compositionData) {
202 if (Objects.isNull(compositionData)) {
206 Map<String, String> networkIdByName = saveNetworks(vspId, version, compositionData);
207 saveComponents(vspId, version, compositionData, networkIdByName);
211 public Set<CompositionEntityValidationData> getAllErrorsByVsp(String vspId) {
212 Set<CompositionEntityValidationData> entitiesWithErrors = new HashSet<>();
213 for (CompositionEntityValidationData root : roots) {
214 if (root.getEntityId().equals(vspId)) {
215 getEntityListWithErrors(root, entitiesWithErrors);
220 if (CollectionUtils.isNotEmpty(entitiesWithErrors)) {
221 updateValidationCompositionEntityName(entitiesWithErrors);
222 return entitiesWithErrors;
225 return new HashSet<>();
228 private void saveComponents(String vspId, Version version, CompositionData compositionData,
229 Map<String, String> networkIdByName) {
230 if (CollectionUtils.isNotEmpty(compositionData.getComponents())) {
231 for (Component component : compositionData.getComponents()) {
232 ComponentEntity componentEntity = new ComponentEntity(vspId, version, null);
233 componentEntity.setComponentCompositionData(component.getData());
235 String componentId = createComponent(componentEntity, false).getId();
237 saveImagesByComponent(vspId, version, component, componentId);
238 saveComputesFlavorByComponent(vspId, version, component, componentId);
240 saveNicsByComponent(vspId, version, networkIdByName, component, componentId);
245 private void saveNicsByComponent(String vspId, Version version,
246 Map<String, String> networkIdByName, Component component,
247 String componentId) {
248 if (CollectionUtils.isNotEmpty(component.getNics())) {
249 for (Nic nic : component.getNics()) {
250 if (nic.getNetworkName() != null && MapUtils.isNotEmpty(networkIdByName)) {
251 nic.setNetworkId(networkIdByName.get(nic.getNetworkName()));
253 nic.setNetworkName(null);
254 //For heat flow set network type to be internal by default for NIC
255 nic.setNetworkType(NetworkType.Internal);
257 NicEntity nicEntity = new NicEntity(vspId, version, componentId, null);
258 nicEntity.setNicCompositionData(nic);
259 createNic(nicEntity);
264 private Map<String, String> saveNetworks(String vspId, Version version,
265 CompositionData compositionData) {
266 Map<String, String> networkIdByName = new HashMap<>();
267 if (CollectionUtils.isNotEmpty(compositionData.getNetworks())) {
268 for (Network network : compositionData.getNetworks()) {
270 NetworkEntity networkEntity = new NetworkEntity(vspId, version, null);
271 networkEntity.setNetworkCompositionData(network);
273 if (network.getName() != null) {
274 networkIdByName.put(network.getName(), createNetwork(networkEntity).getId());
278 return networkIdByName;
281 private NetworkEntity createNetwork(NetworkEntity network) {
282 //network.setId(CommonMethods.nextUuId()); will be set by the dao
283 networkDao.create(network);
288 public ComponentEntity createComponent(ComponentEntity component, boolean isManualVsp) {
289 //component.setId(CommonMethods.nextUuId()); will be set by the dao
290 ComponentQuestionnaireSchemaInput schemaInput = new ComponentQuestionnaireSchemaInput(null,
291 null, component.getComponentCompositionData().getDisplayName(), isManualVsp);
292 String questionnarieData = new JsonSchemaDataGenerator(generateSchema(SchemaTemplateContext.questionnaire,
293 CompositionEntityType.component, schemaInput)).generateData();
294 component.setQuestionnaireData(questionnarieData);
296 componentDao.create(component);
301 public NicEntity createNic(NicEntity nic) {
302 //nic.setId(CommonMethods.nextUuId()); will be set by the dao
303 nic.setQuestionnaireData(
304 new JsonSchemaDataGenerator(
305 generateSchema(SchemaTemplateContext.questionnaire, CompositionEntityType.nic, null))
313 public void addErrorsToTrees(Map<CompositionEntityId, Collection<String>> errors) {
314 roots.forEach(root -> addErrorsToTree(root, null, errors));
318 * get a flat list of all questionnaire entities that have validation errors
320 public Set<CompositionEntityValidationData> getEntityListWithErrors() {
321 Set<CompositionEntityValidationData> treeAsList = new HashSet<>();
323 for (CompositionEntityValidationData entity : roots) {
324 if (CollectionUtils.isNotEmpty(entity.getErrors())) {
325 addNodeWithErrors(entity, treeAsList);
327 getEntityListWithErrors(entity, treeAsList);
330 updateValidationCompositionEntityName(treeAsList);
334 private void getEntityListWithErrors(CompositionEntityValidationData entity,
335 Set<CompositionEntityValidationData> compositionSet) {
336 if (CollectionUtils.isNotEmpty(entity.getErrors())) {
337 addNodeWithErrors(entity, compositionSet);
340 if (CollectionUtils.isEmpty(entity.getSubEntitiesValidationData())) {
344 for (CompositionEntityValidationData child : entity.getSubEntitiesValidationData()) {
345 getEntityListWithErrors(child, compositionSet);
350 private void addNodeWithErrors(CompositionEntityValidationData node,
351 Set<CompositionEntityValidationData> entitiesWithErrors) {
352 CompositionEntityValidationData compositionNodeToAdd = new CompositionEntityValidationData(node
353 .getEntityType(), node.getEntityId());
354 compositionNodeToAdd.setErrors(node.getErrors());
355 compositionNodeToAdd.setSubEntitiesValidationData(null);
357 entitiesWithErrors.add(compositionNodeToAdd);
360 public void removeNodesWithoutErrors() {
361 roots.forEach(root -> removeNodesWithoutErrors(root, null));
365 private CompositionEntityData getCompositionEntityDataById(CompositionEntityValidationData
367 for (Map.Entry<CompositionEntityId, CompositionEntityData> entityEntry : entities
369 if (entityEntry.getKey().getId().equals(entity.getEntityId())) {
370 return entityEntry.getValue();
377 private void updateValidationCompositionEntityName(Set<CompositionEntityValidationData>
379 for (CompositionEntityValidationData entity : compositionSet) {
380 String compositionData = getCompositionDataAsString(entity);
381 if (entity.getEntityType().equals(CompositionEntityType.vsp) ||
382 Objects.nonNull(compositionData)) {
383 entity.setEntityName(getEntityNameByEntityType(compositionData, entity));
388 private String getCompositionDataAsString(CompositionEntityValidationData entity) {
389 CompositionEntityData compositionEntityData = getCompositionEntityDataById(entity);
390 return compositionEntityData == null ? null : compositionEntityData.entity.getCompositionData();
394 private String getEntityNameByEntityType(String compositionData,
395 CompositionEntityValidationData entity) {
396 switch (entity.getEntityType()) {
398 ComponentData component = JsonUtil.json2Object(compositionData, ComponentData.class);
399 return component.getDisplayName();
402 Nic nic = JsonUtil.json2Object(compositionData, Nic.class);
403 return nic.getName();
406 Network network = JsonUtil.json2Object(compositionData, Network.class);
407 return network.getName();
410 Image image = JsonUtil.json2Object(compositionData, Image.class);
411 return image.getFileName();
414 ComputeData compute = JsonUtil.json2Object(compositionData, ComputeData.class);
415 return compute.getName();
418 CompositionEntityData vspEntity = getCompositionEntityDataById(entity);
419 if (Objects.isNull(vspEntity)) {
422 VspQuestionnaireEntity vspQuestionnaireEntity = (VspQuestionnaireEntity) vspEntity.entity;
423 VspDetails vspDetails =
424 vspInfoDao.get(new VspDetails(vspQuestionnaireEntity.getId(),
425 vspQuestionnaireEntity.getVersion()));
426 return vspDetails.getName();
432 private void removeNodesWithoutErrors(CompositionEntityValidationData node,
433 CompositionEntityValidationData parent) {
435 if (Objects.isNull(node)) {
439 if (hasChildren(node)) {
440 Collection<CompositionEntityValidationData> subNodes =
441 new ArrayList<>(node.getSubEntitiesValidationData());
442 subNodes.forEach(subNode -> removeNodesWithoutErrors(subNode, node));
443 node.setSubEntitiesValidationData(subNodes);
445 if (canNodeGetRemovedFromValidationDataTree(node)) {
446 removeNodeFromChildren(parent, node);
448 } else if (canNodeGetRemovedFromValidationDataTree(node)) {
449 removeNodeFromChildren(parent, node);
453 private void removeNodeFromChildren(CompositionEntityValidationData parent,
454 CompositionEntityValidationData childToRemove) {
455 if (!Objects.isNull(parent)) {
456 parent.getSubEntitiesValidationData().remove(childToRemove);
460 private boolean hasChildren(CompositionEntityValidationData node) {
461 return !CollectionUtils.isEmpty(node.getSubEntitiesValidationData());
464 private boolean canNodeGetRemovedFromValidationDataTree(CompositionEntityValidationData node) {
465 return !hasChildren(node) && CollectionUtils.isEmpty(node.getErrors());
469 private void addValidationDataEntity(
470 Map<CompositionEntityId, CompositionEntityValidationData> entitiesValidationData,
471 CompositionEntityId entityId, CompositionEntity entity) {
472 if (entitiesValidationData.containsKey(entityId)) {
476 CompositionEntityValidationData validationData =
477 new CompositionEntityValidationData(entity.getType(), entity.getId());
478 entitiesValidationData.put(entityId, validationData);
480 CompositionEntityId parentEntityId = entityId.getParentId();
481 if (parentEntityId == null) {
482 roots.add(validationData);
484 CompositionEntityData parentEntity = entities.get(parentEntityId);
485 if (parentEntity == null) {
486 roots.add(validationData);
488 addValidationDataEntity(entitiesValidationData, parentEntityId, parentEntity.entity);
489 entitiesValidationData.get(parentEntityId).addSubEntityValidationData(validationData);
494 private void addErrorsToTree(CompositionEntityValidationData node,
495 CompositionEntityId parentNodeId,
496 Map<CompositionEntityId, Collection<String>> errors) {
500 CompositionEntityId nodeId = new CompositionEntityId(node.getEntityId(), parentNodeId);
501 node.setErrors(errors.get(nodeId));
503 if (node.getSubEntitiesValidationData() != null) {
504 node.getSubEntitiesValidationData()
505 .forEach(subNode -> addErrorsToTree(subNode, nodeId, errors));
509 private Collection<String> validateQuestionnaire(CompositionEntityData compositionEntityData) {
510 logger.debug(String.format("validateQuestionnaire start: " +
511 "[entity.type]=%s, [entity.id]=%s, [entity.questionnaireString]=%s",
512 compositionEntityData.entity.getType().name(),
513 compositionEntityData.entity.getCompositionEntityId().toString(),
514 compositionEntityData.entity.getQuestionnaireData()));
516 if (Objects.isNull(compositionEntityData.entity.getQuestionnaireData()) ||
517 !JsonUtil.isValidJson(compositionEntityData.entity.getQuestionnaireData())) {
518 return Collections.singletonList(String
519 .format(MISSING_OR_INVALID_QUESTIONNAIRE_MSG, compositionEntityData.entity.getType()));
522 return JsonUtil.validate(
523 compositionEntityData.entity.getQuestionnaireData() == null
524 ? JsonUtil.object2Json(new Object())
525 : compositionEntityData.entity.getQuestionnaireData(),
526 getSchema(compositionEntityData.entity.getType(), SchemaTemplateContext.questionnaire,
527 compositionEntityData.schemaTemplateInput));
530 private String getSchema(CompositionEntityType compositionEntityType,
531 SchemaTemplateContext schemaTemplateContext,
532 SchemaTemplateInput schemaTemplateInput) {
533 return schemaTemplateInput == null
534 ? nonDynamicSchemas.computeIfAbsent(compositionEntityType,
535 k -> generateSchema(schemaTemplateContext, compositionEntityType, null))
536 : generateSchema(schemaTemplateContext, compositionEntityType, schemaTemplateInput);
539 private static class CompositionEntityData {
540 private CompositionEntity entity;
541 private SchemaTemplateInput schemaTemplateInput;
543 CompositionEntityData(CompositionEntity entity, SchemaTemplateInput schemaTemplateInput) {
544 this.entity = entity;
545 this.schemaTemplateInput = schemaTemplateInput;
550 // todo - make SchemaGenerator non static and mock it in UT instead of mocking this method (and
551 // make the method private
552 protected String generateSchema(SchemaTemplateContext schemaTemplateContext,
553 CompositionEntityType compositionEntityType,
554 SchemaTemplateInput schemaTemplateInput) {
555 return SchemaGenerator
556 .generate(schemaTemplateContext, compositionEntityType, schemaTemplateInput);
560 public DeploymentFlavorEntity createDeploymentFlavor(DeploymentFlavorEntity deploymentFlavor) {
561 deploymentFlavor.setId(CommonMethods.nextUuId());
562 deploymentFlavorDao.create(deploymentFlavor);
563 return deploymentFlavor;
567 public ImageEntity createImage(ImageEntity image) {
568 image.setId(CommonMethods.nextUuId());
570 image.setQuestionnaireData(
571 new JsonSchemaDataGenerator(SchemaGenerator
572 .generate(SchemaTemplateContext.questionnaire, CompositionEntityType.image, null))
575 imageDao.create(image);
579 public void saveComputesFlavorByComponent(String vspId, Version version, Component component,
580 String componentId) {
581 if (CollectionUtils.isNotEmpty(component.getCompute())) {
582 for (ComputeData flavor : component.getCompute()) {
583 ComputeEntity computeEntity = new ComputeEntity(vspId, version, componentId, null);
584 computeEntity.setComputeCompositionData(flavor);
585 computeEntity.setQuestionnaireData(
586 new JsonSchemaDataGenerator(SchemaGenerator
587 .generate(SchemaTemplateContext.questionnaire, CompositionEntityType.compute,
588 null)).generateData());
590 computeDao.create(computeEntity);
595 public void saveImagesByComponent(String vspId, Version version, Component component, String
597 if (CollectionUtils.isNotEmpty(component.getImages())) {
598 for (Image img : component.getImages()) {
599 ImageEntity imageEntity = new ImageEntity(vspId, version, componentId, null);
600 imageEntity.setImageCompositionData(img);
601 createImage(imageEntity);