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.services.impl.composition;
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.dao.ComponentDao;
34 import org.openecomp.sdc.vendorsoftwareproduct.dao.ComputeDao;
35 import org.openecomp.sdc.vendorsoftwareproduct.dao.DeploymentFlavorDao;
36 import org.openecomp.sdc.vendorsoftwareproduct.dao.ImageDao;
37 import org.openecomp.sdc.vendorsoftwareproduct.dao.NetworkDao;
38 import org.openecomp.sdc.vendorsoftwareproduct.dao.NicDao;
39 import org.openecomp.sdc.vendorsoftwareproduct.dao.VendorSoftwareProductInfoDao;
40 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.ComponentEntity;
41 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.CompositionEntity;
42 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.ComputeEntity;
43 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.DeploymentFlavorEntity;
44 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.ImageEntity;
45 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.NetworkEntity;
46 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.NicEntity;
47 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspDetails;
48 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspQuestionnaireEntity;
49 import org.openecomp.sdc.vendorsoftwareproduct.services.composition.CompositionEntityDataManager;
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.HashMap;
70 import java.util.HashSet;
71 import java.util.List;
73 import java.util.Objects;
76 public class CompositionEntityDataManagerImpl implements CompositionEntityDataManager {
78 private static final String COMPOSITION_ENTITY_DATA_MANAGER_ERR =
79 "COMPOSITION_ENTITY_DATA_MANAGER_ERR";
80 private static final String COMPOSITION_ENTITY_DATA_MANAGER_ERR_MSG =
81 "Invalid input: %s may not be null";
82 private static final String MISSING_OR_INVALID_QUESTIONNAIRE_MSG =
83 "Data is missing/invalid for this %s. Please refill and resubmit.";
85 private static final Logger logger =
86 LoggerFactory.getLogger(CompositionEntityDataManagerImpl.class);
87 private Map<CompositionEntityId, CompositionEntityData> entities = new HashMap<>();
88 private Map<CompositionEntityType, String> nonDynamicSchemas = new HashMap<>();
89 private List<CompositionEntityValidationData> roots = new ArrayList<>();
91 private VendorSoftwareProductInfoDao vspInfoDao;
92 private ComponentDao componentDao;
93 private NicDao nicDao;
94 private NetworkDao networkDao;
95 private ImageDao imageDao;
96 private ComputeDao computeDao;
97 private DeploymentFlavorDao deploymentFlavorDao;
99 public CompositionEntityDataManagerImpl(VendorSoftwareProductInfoDao vspInfoDao,
100 ComponentDao componentDao,
101 NicDao nicDao, NetworkDao networkDao,
102 ImageDao imageDao, ComputeDao computeDao,
103 DeploymentFlavorDao deploymentFlavorDao) {
104 this.vspInfoDao = vspInfoDao;
105 this.componentDao = componentDao;
106 this.nicDao = nicDao;
107 this.networkDao = networkDao;
108 this.imageDao = imageDao;
109 this.computeDao = computeDao;
110 this.deploymentFlavorDao = deploymentFlavorDao;
114 * Validate entity composition entity validation data.
116 * @param entity the entity
117 * @param schemaTemplateContext the schema template context
118 * @param schemaTemplateInput the schema template input
119 * @return the composition entity validation data
122 public CompositionEntityValidationData validateEntity(CompositionEntity entity,
123 SchemaTemplateContext schemaTemplateContext,
124 SchemaTemplateInput schemaTemplateInput) {
125 if (entity == null) {
126 throw new CoreException(
127 new ErrorCode.ErrorCodeBuilder().withCategory(ErrorCategory.APPLICATION)
128 .withId(COMPOSITION_ENTITY_DATA_MANAGER_ERR).withMessage(
129 String.format(COMPOSITION_ENTITY_DATA_MANAGER_ERR_MSG, "composition entity"))
132 if (schemaTemplateContext == null) {
133 throw new CoreException(
134 new ErrorCode.ErrorCodeBuilder().withCategory(ErrorCategory.APPLICATION)
135 .withId(COMPOSITION_ENTITY_DATA_MANAGER_ERR).withMessage(
136 String.format(COMPOSITION_ENTITY_DATA_MANAGER_ERR_MSG, "schema template context"))
140 CompositionEntityValidationData validationData =
141 new CompositionEntityValidationData(entity.getType(), entity.getId());
143 schemaTemplateContext == SchemaTemplateContext.composition ? entity.getCompositionData()
144 : entity.getQuestionnaireData();
145 validationData.setErrors(JsonUtil.validate(
146 json == null ? JsonUtil.object2Json(new Object()) : json,
147 generateSchema(schemaTemplateContext, entity.getType(), schemaTemplateInput)));
148 return validationData;
154 * @param entity the entity
155 * @param schemaTemplateInput the schema template input
158 public void addEntity(CompositionEntity entity, SchemaTemplateInput schemaTemplateInput) {
159 if (entity == null) {
160 throw new CoreException(
161 new ErrorCode.ErrorCodeBuilder().withCategory(ErrorCategory.APPLICATION)
162 .withId(COMPOSITION_ENTITY_DATA_MANAGER_ERR).withMessage(
163 String.format(COMPOSITION_ENTITY_DATA_MANAGER_ERR_MSG, "composition entity"))
166 entities.put(entity.getCompositionEntityId(),
167 new CompositionEntityData(entity, schemaTemplateInput));
171 * Validate entities questionnaire map.
176 public Map<CompositionEntityId, Collection<String>> validateEntitiesQuestionnaire() {
177 Map<CompositionEntityId, Collection<String>> errorsByEntityId = new HashMap<>();
178 entities.entrySet().forEach(entry -> {
179 Collection<String> errors = validateQuestionnaire(entry.getValue());
180 if (errors != null) {
181 errorsByEntityId.put(entry.getKey(), errors);
184 return errorsByEntityId;
191 public void buildTrees() {
192 Map<CompositionEntityId, CompositionEntityValidationData> entitiesValidationData =
194 entities.entrySet().forEach(
195 entry -> addValidationDataEntity(entitiesValidationData, entry.getKey(),
196 entry.getValue().entity));
199 public Collection<CompositionEntityValidationData> getTrees() {
204 public void saveCompositionData(String vspId, Version version, CompositionData compositionData) {
205 if (Objects.isNull(compositionData)) {
209 Map<String, String> networkIdByName = saveNetworks(vspId, version, compositionData);
210 saveComponents(vspId, version, compositionData, networkIdByName);
214 public Set<CompositionEntityValidationData> getAllErrorsByVsp(String vspId) {
215 CompositionEntityValidationData matchVsp = null;
216 Set<CompositionEntityValidationData> entitiesWithErrors = new HashSet<>();
217 for (CompositionEntityValidationData root : roots) {
218 if (root.getEntityId().equals(vspId)) {
224 getEntityListWithErrors(matchVsp, entitiesWithErrors);
225 if (CollectionUtils.isNotEmpty(entitiesWithErrors)) {
226 updateValidationCompositionEntityName(entitiesWithErrors);
227 return entitiesWithErrors;
233 private boolean isThereErrorsInSubTree(CompositionEntityValidationData entity) {
234 if (Objects.isNull(entity)) {
238 if (CollectionUtils.isNotEmpty(entity.getErrors())) {
242 Collection<CompositionEntityValidationData> subEntitiesValidationData =
243 entity.getSubEntitiesValidationData();
244 return !CollectionUtils.isEmpty(subEntitiesValidationData) &&
245 checkForErrorsInChildren(subEntitiesValidationData);
249 private boolean checkForErrorsInChildren(
250 Collection<CompositionEntityValidationData> subEntitiesValidationData) {
251 boolean result = false;
252 for (CompositionEntityValidationData subEntity : subEntitiesValidationData) {
253 if (CollectionUtils.isNotEmpty(subEntity.getErrors())) {
257 result = isThereErrorsInSubTree(subEntity) || result;
265 public void saveComponents(String vspId, Version version, CompositionData compositionData,
266 Map<String, String> networkIdByName) {
267 if (CollectionUtils.isNotEmpty(compositionData.getComponents())) {
268 for (Component component : compositionData.getComponents()) {
269 ComponentEntity componentEntity = new ComponentEntity(vspId, version, null);
270 componentEntity.setComponentCompositionData(component.getData());
272 String componentId = createComponent(componentEntity).getId();
274 saveImagesByComponent(vspId, version, component, componentId);
275 saveComputesFlavorByComponent(vspId, version, component, componentId);
277 saveNicsByComponent(vspId, version, networkIdByName, component, componentId);
282 public void saveNicsByComponent(String vspId, Version version,
283 Map<String, String> networkIdByName, Component component,
284 String componentId) {
285 if (CollectionUtils.isNotEmpty(component.getNics())) {
286 for (Nic nic : component.getNics()) {
287 if (nic.getNetworkName() != null && MapUtils.isNotEmpty(networkIdByName)) {
288 nic.setNetworkId(networkIdByName.get(nic.getNetworkName()));
290 nic.setNetworkName(null);
291 //For heat flow set network type to be internal by default for NIC
292 nic.setNetworkType(NetworkType.Internal);
294 NicEntity nicEntity = new NicEntity(vspId, version, componentId, null);
295 nicEntity.setNicCompositionData(nic);
296 createNic(nicEntity);
301 public Map<String, String> saveNetworks(String vspId, Version version,
302 CompositionData compositionData) {
303 Map<String, String> networkIdByName = new HashMap<>();
304 if (CollectionUtils.isNotEmpty(compositionData.getNetworks())) {
305 for (Network network : compositionData.getNetworks()) {
307 NetworkEntity networkEntity = new NetworkEntity(vspId, version, null);
308 networkEntity.setNetworkCompositionData(network);
310 if (network.getName() != null) {
311 networkIdByName.put(network.getName(), createNetwork(networkEntity).getId());
315 return networkIdByName;
319 public NetworkEntity createNetwork(NetworkEntity network) {
320 //network.setId(CommonMethods.nextUuId()); will be set by the dao
321 networkDao.create(network);
326 public ComponentEntity createComponent(ComponentEntity component) {
327 //component.setId(CommonMethods.nextUuId()); will be set by the dao
328 component.setQuestionnaireData(
329 new JsonSchemaDataGenerator(
330 generateSchema(SchemaTemplateContext.questionnaire, CompositionEntityType.component,
334 componentDao.create(component);
339 public NicEntity createNic(NicEntity nic) {
340 //nic.setId(CommonMethods.nextUuId()); will be set by the dao
341 nic.setQuestionnaireData(
342 new JsonSchemaDataGenerator(
343 generateSchema(SchemaTemplateContext.questionnaire, CompositionEntityType.nic, null))
351 public void addErrorsToTrees(Map<CompositionEntityId, Collection<String>> errors) {
352 roots.forEach(root -> addErrorsToTree(root, null, errors));
356 * get a flat list of all questionnaire entities that have validation errors
358 public Set<CompositionEntityValidationData> getEntityListWithErrors() {
359 Set<CompositionEntityValidationData> treeAsList = new HashSet<>();
361 for (CompositionEntityValidationData entity : roots) {
362 if (CollectionUtils.isNotEmpty(entity.getErrors())) {
363 addNodeWithErrors(entity, treeAsList);
365 getEntityListWithErrors(entity, treeAsList);
368 updateValidationCompositionEntityName(treeAsList);
372 private void getEntityListWithErrors(CompositionEntityValidationData entity,
373 Set<CompositionEntityValidationData> compositionSet) {
374 if(CollectionUtils.isNotEmpty(entity.getErrors())){
375 addNodeWithErrors(entity, compositionSet);
378 if (CollectionUtils.isEmpty(entity.getSubEntitiesValidationData())) {
382 for (CompositionEntityValidationData child : entity.getSubEntitiesValidationData()) {
383 getEntityListWithErrors(child, compositionSet);
388 private void addNodeWithErrors(CompositionEntityValidationData node,
389 Set<CompositionEntityValidationData> entitiesWithErrors) {
390 CompositionEntityValidationData compositionNodeToAdd = new CompositionEntityValidationData(node
391 .getEntityType(), node.getEntityId());
392 compositionNodeToAdd.setErrors(node.getErrors());
393 compositionNodeToAdd.setSubEntitiesValidationData(null);
395 entitiesWithErrors.add(compositionNodeToAdd);
398 public void removeNodesWithoutErrors() {
399 roots.forEach(root -> removeNodesWithoutErrors(root, null));
403 private CompositionEntityData getCompositionEntityDataById(CompositionEntityValidationData
405 for (Map.Entry<CompositionEntityId, CompositionEntityData> entityEntry : entities
407 if (entityEntry.getKey().getId().equals(entity.getEntityId())) {
408 return entityEntry.getValue();
415 private void updateValidationCompositionEntityName(Set<CompositionEntityValidationData>
417 for (CompositionEntityValidationData entity : compositionSet) {
418 String compositionData = getCompositionDataAsString(entity);
419 if (entity.getEntityType().equals(CompositionEntityType.vsp) ||
420 Objects.nonNull(compositionData)) {
421 entity.setEntityName(getEntityNameByEntityType(compositionData, entity));
426 private String getCompositionDataAsString(CompositionEntityValidationData entity) {
427 CompositionEntityData compositionEntityData = getCompositionEntityDataById(entity);
428 return compositionEntityData == null ? null : compositionEntityData.entity.getCompositionData();
432 private String getEntityNameByEntityType(String compositionData,
433 CompositionEntityValidationData entity) {
434 switch (entity.getEntityType()) {
436 ComponentData component = JsonUtil.json2Object(compositionData, ComponentData.class);
437 return component.getDisplayName();
440 Nic nic = JsonUtil.json2Object(compositionData, Nic.class);
441 return nic.getName();
444 Network network = JsonUtil.json2Object(compositionData, Network.class);
445 return network.getName();
448 Image image = JsonUtil.json2Object(compositionData, Image.class);
449 return image.getFileName();
452 CompositionEntityData vspEntity = getCompositionEntityDataById(entity);
453 VspQuestionnaireEntity vspQuestionnaireEntity = (VspQuestionnaireEntity) vspEntity.entity;
454 VspDetails vspDetails =
455 vspInfoDao.get(new VspDetails(vspQuestionnaireEntity.getId(),
456 vspQuestionnaireEntity.getVersion()));
457 return vspDetails.getName();
463 private void removeNodesWithoutErrors(CompositionEntityValidationData node,
464 CompositionEntityValidationData parent) {
466 if (Objects.isNull(node)) {
470 if (hasChildren(node)) {
471 Collection<CompositionEntityValidationData> subNodes =
472 new ArrayList<>(node.getSubEntitiesValidationData());
473 subNodes.forEach(subNode -> removeNodesWithoutErrors(subNode, node));
474 node.setSubEntitiesValidationData(subNodes);
476 if (canNodeGetRemovedFromValidationDataTree(node)) {
477 removeNodeFromChildren(parent, node);
479 } else if (canNodeGetRemovedFromValidationDataTree(node)) {
480 removeNodeFromChildren(parent, node);
484 private void removeNodeFromChildren(CompositionEntityValidationData parent,
485 CompositionEntityValidationData childToRemove) {
486 if (!Objects.isNull(parent)) {
487 parent.getSubEntitiesValidationData().remove(childToRemove);
491 private boolean hasChildren(CompositionEntityValidationData node) {
492 return !CollectionUtils.isEmpty(node.getSubEntitiesValidationData());
495 private boolean canNodeGetRemovedFromValidationDataTree(CompositionEntityValidationData node) {
496 return !hasChildren(node) && CollectionUtils.isEmpty(node.getErrors());
500 private void addValidationDataEntity(
501 Map<CompositionEntityId, CompositionEntityValidationData> entitiesValidationData,
502 CompositionEntityId entityId, CompositionEntity entity) {
503 if (entitiesValidationData.containsKey(entityId)) {
507 CompositionEntityValidationData validationData =
508 new CompositionEntityValidationData(entity.getType(), entity.getId());
509 entitiesValidationData.put(entityId, validationData);
511 CompositionEntityId parentEntityId = entityId.getParentId();
512 if (parentEntityId == null) {
513 roots.add(validationData);
515 CompositionEntityData parentEntity = entities.get(parentEntityId);
516 if (parentEntity == null) {
517 roots.add(validationData);
519 addValidationDataEntity(entitiesValidationData, parentEntityId, parentEntity.entity);
520 entitiesValidationData.get(parentEntityId).addSubEntityValidationData(validationData);
525 private void addErrorsToTree(CompositionEntityValidationData node,
526 CompositionEntityId parentNodeId,
527 Map<CompositionEntityId, Collection<String>> errors) {
531 CompositionEntityId nodeId = new CompositionEntityId(node.getEntityId(), parentNodeId);
532 node.setErrors(errors.get(nodeId));
534 if (node.getSubEntitiesValidationData() != null) {
535 node.getSubEntitiesValidationData()
536 .forEach(subNode -> addErrorsToTree(subNode, nodeId, errors));
540 private Collection<String> validateQuestionnaire(CompositionEntityData compositionEntityData) {
541 logger.debug(String.format("validateQuestionnaire start: " +
542 "[entity.type]=%s, [entity.id]=%s, [entity.questionnaireString]=%s",
543 compositionEntityData.entity.getType().name(),
544 compositionEntityData.entity.getCompositionEntityId().toString(),
545 compositionEntityData.entity.getQuestionnaireData()));
547 if (Objects.isNull(compositionEntityData.entity.getQuestionnaireData()) ||
548 !JsonUtil.isValidJson(compositionEntityData.entity.getQuestionnaireData())) {
549 return Collections.singletonList(String
550 .format(MISSING_OR_INVALID_QUESTIONNAIRE_MSG, compositionEntityData.entity.getType()));
553 return JsonUtil.validate(
554 compositionEntityData.entity.getQuestionnaireData() == null
555 ? JsonUtil.object2Json(new Object())
556 : compositionEntityData.entity.getQuestionnaireData(),
557 getSchema(compositionEntityData.entity.getType(), SchemaTemplateContext.questionnaire,
558 compositionEntityData.schemaTemplateInput));
561 private String getSchema(CompositionEntityType compositionEntityType,
562 SchemaTemplateContext schemaTemplateContext,
563 SchemaTemplateInput schemaTemplateInput) {
564 return schemaTemplateInput == null
565 ? nonDynamicSchemas.computeIfAbsent(compositionEntityType,
566 k -> generateSchema(schemaTemplateContext, compositionEntityType, null))
567 : generateSchema(schemaTemplateContext, compositionEntityType, schemaTemplateInput);
570 private static class CompositionEntityData {
571 private CompositionEntity entity;
572 private SchemaTemplateInput schemaTemplateInput;
574 CompositionEntityData(CompositionEntity entity, SchemaTemplateInput schemaTemplateInput) {
575 this.entity = entity;
576 this.schemaTemplateInput = schemaTemplateInput;
581 // todo - make SchemaGenerator non static and mock it in UT instead of mocking this method (and
582 // make the method private
584 protected String generateSchema(SchemaTemplateContext schemaTemplateContext,
585 CompositionEntityType compositionEntityType,
586 SchemaTemplateInput schemaTemplateInput) {
587 return SchemaGenerator
588 .generate(schemaTemplateContext, compositionEntityType, schemaTemplateInput);
592 public DeploymentFlavorEntity createDeploymentFlavor(DeploymentFlavorEntity deploymentFlavor) {
593 deploymentFlavor.setId(CommonMethods.nextUuId());
594 deploymentFlavorDao.create(deploymentFlavor);
595 return deploymentFlavor;
599 public ImageEntity createImage(ImageEntity image) {
600 image.setId(CommonMethods.nextUuId());
602 image.setQuestionnaireData(
603 new JsonSchemaDataGenerator(SchemaGenerator
604 .generate(SchemaTemplateContext.questionnaire, CompositionEntityType.image, null))
607 imageDao.create(image);
611 public void saveComputesFlavorByComponent(String vspId, Version version, Component component,
612 String componentId) {
613 if (CollectionUtils.isNotEmpty(component.getCompute())) {
614 for (ComputeData flavor : component.getCompute()) {
615 ComputeEntity computeEntity = new ComputeEntity(vspId, version, componentId, null);
616 computeEntity.setComputeCompositionData(flavor);
617 computeEntity.setQuestionnaireData(
618 new JsonSchemaDataGenerator(SchemaGenerator
619 .generate(SchemaTemplateContext.questionnaire, CompositionEntityType.compute,
620 null)).generateData());
622 computeDao.create(computeEntity);
627 public void saveImagesByComponent(String vspId, Version version, Component component, String
629 if (CollectionUtils.isNotEmpty(component.getImages())) {
630 for (Image img : component.getImages()) {
631 ImageEntity imageEntity = new ImageEntity(vspId, version, componentId, null);
632 imageEntity.setImageCompositionData(img);
633 createImage(imageEntity);