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 org.apache.commons.collections4.CollectionUtils;
20 import org.apache.commons.collections4.MapUtils;
21 import org.openecomp.core.utilities.CommonMethods;
22 import org.openecomp.core.utilities.json.JsonSchemaDataGenerator;
23 import org.openecomp.core.utilities.json.JsonUtil;
24 import org.openecomp.sdc.common.errors.CoreException;
25 import org.openecomp.sdc.common.errors.ErrorCategory;
26 import org.openecomp.sdc.common.errors.ErrorCode;
27 import org.openecomp.sdc.logging.api.Logger;
28 import org.openecomp.sdc.logging.api.LoggerFactory;
29 import org.openecomp.sdc.vendorsoftwareproduct.CompositionEntityDataManager;
30 import org.openecomp.sdc.vendorsoftwareproduct.dao.ComponentDao;
31 import org.openecomp.sdc.vendorsoftwareproduct.dao.ComputeDao;
32 import org.openecomp.sdc.vendorsoftwareproduct.dao.DeploymentFlavorDao;
33 import org.openecomp.sdc.vendorsoftwareproduct.dao.ImageDao;
34 import org.openecomp.sdc.vendorsoftwareproduct.dao.NetworkDao;
35 import org.openecomp.sdc.vendorsoftwareproduct.dao.NicDao;
36 import org.openecomp.sdc.vendorsoftwareproduct.dao.VendorSoftwareProductInfoDao;
37 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.*;
38 import org.openecomp.sdc.vendorsoftwareproduct.services.schemagenerator.SchemaGenerator;
39 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.Component;
40 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.ComponentData;
41 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.CompositionData;
42 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.CompositionEntityId;
43 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.CompositionEntityType;
44 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.CompositionEntityValidationData;
45 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.ComputeData;
46 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.Image;
47 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.Network;
48 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.NetworkType;
49 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.Nic;
50 import org.openecomp.sdc.vendorsoftwareproduct.types.schemagenerator.ComponentQuestionnaireSchemaInput;
51 import org.openecomp.sdc.vendorsoftwareproduct.types.schemagenerator.SchemaTemplateContext;
52 import org.openecomp.sdc.vendorsoftwareproduct.types.schemagenerator.SchemaTemplateInput;
53 import org.openecomp.sdc.versioning.dao.types.Version;
55 import java.util.ArrayList;
56 import java.util.Collection;
57 import java.util.Collections;
58 import java.util.EnumMap;
59 import java.util.HashMap;
60 import java.util.HashSet;
61 import java.util.List;
63 import java.util.Objects;
66 public class CompositionEntityDataManagerImpl implements CompositionEntityDataManager {
68 private static final String COMPOSITION_ENTITY_DATA_MANAGER_ERR =
69 "COMPOSITION_ENTITY_DATA_MANAGER_ERR";
70 private static final String COMPOSITION_ENTITY_DATA_MANAGER_ERR_MSG =
71 "Invalid input: %s may not be null";
72 private static final String MISSING_OR_INVALID_QUESTIONNAIRE_MSG =
73 "Data is missing/invalid for this %s. Please refill and resubmit.";
75 private static final Logger logger =
76 LoggerFactory.getLogger(CompositionEntityDataManagerImpl.class);
77 private Map<CompositionEntityId, CompositionEntityData> entities = new HashMap<>();
78 private Map<CompositionEntityType, String> nonDynamicSchemas =
79 new EnumMap<>(CompositionEntityType.class);
80 private List<CompositionEntityValidationData> roots = new ArrayList<>();
82 private VendorSoftwareProductInfoDao vspInfoDao;
83 private ComponentDao componentDao;
84 private NicDao nicDao;
85 private NetworkDao networkDao;
86 private ImageDao imageDao;
87 private ComputeDao computeDao;
88 private DeploymentFlavorDao deploymentFlavorDao;
90 public CompositionEntityDataManagerImpl(VendorSoftwareProductInfoDao vspInfoDao,
91 ComponentDao componentDao,
92 NicDao nicDao, NetworkDao networkDao,
93 ImageDao imageDao, ComputeDao computeDao,
94 DeploymentFlavorDao deploymentFlavorDao) {
95 this.vspInfoDao = vspInfoDao;
96 this.componentDao = componentDao;
98 this.networkDao = networkDao;
99 this.imageDao = imageDao;
100 this.computeDao = computeDao;
101 this.deploymentFlavorDao = deploymentFlavorDao;
105 * Validate entity composition entity validation data.
107 * @param entity the entity
108 * @param schemaTemplateContext the schema template context
109 * @param schemaTemplateInput the schema template input
110 * @return the composition entity validation data
113 public CompositionEntityValidationData validateEntity(CompositionEntity entity,
114 SchemaTemplateContext schemaTemplateContext,
115 SchemaTemplateInput schemaTemplateInput) {
116 if (entity == null) {
117 throw new CoreException(
118 new ErrorCode.ErrorCodeBuilder().withCategory(ErrorCategory.APPLICATION)
119 .withId(COMPOSITION_ENTITY_DATA_MANAGER_ERR).withMessage(
120 String.format(COMPOSITION_ENTITY_DATA_MANAGER_ERR_MSG, "composition entity"))
123 if (schemaTemplateContext == 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, "schema template context"))
131 CompositionEntityValidationData validationData =
132 new CompositionEntityValidationData(entity.getType(), entity.getId());
134 schemaTemplateContext == SchemaTemplateContext.composition ? entity.getCompositionData()
135 : entity.getQuestionnaireData();
136 validationData.setErrors(JsonUtil.validate(
137 json == null ? JsonUtil.object2Json(new Object()) : json,
138 generateSchema(schemaTemplateContext, entity.getType(), schemaTemplateInput)));
139 return validationData;
145 * @param entity the entity
146 * @param schemaTemplateInput the schema template input
149 public void addEntity(CompositionEntity entity, SchemaTemplateInput schemaTemplateInput) {
150 if (entity == null) {
151 throw new CoreException(
152 new ErrorCode.ErrorCodeBuilder().withCategory(ErrorCategory.APPLICATION)
153 .withId(COMPOSITION_ENTITY_DATA_MANAGER_ERR).withMessage(
154 String.format(COMPOSITION_ENTITY_DATA_MANAGER_ERR_MSG, "composition entity"))
157 entities.put(entity.getCompositionEntityId(),
158 new CompositionEntityData(entity, schemaTemplateInput));
162 * Validate entities questionnaire map.
167 public Map<CompositionEntityId, Collection<String>> validateEntitiesQuestionnaire() {
168 Map<CompositionEntityId, Collection<String>> errorsByEntityId = new HashMap<>();
169 entities.forEach((key, value) -> {
170 Collection<String> errors = validateQuestionnaire(value);
171 if (errors != null) {
172 errorsByEntityId.put(key, errors);
175 return errorsByEntityId;
182 public void buildTrees() {
183 Map<CompositionEntityId, CompositionEntityValidationData> entitiesValidationData =
185 entities.forEach((key, value) -> addValidationDataEntity(entitiesValidationData, key,
189 public Collection<CompositionEntityValidationData> getTrees() {
194 public void saveCompositionData(String vspId, Version version, CompositionData compositionData) {
195 if (Objects.isNull(compositionData)) {
199 Map<String, String> networkIdByName = saveNetworks(vspId, version, compositionData);
200 saveComponents(vspId, version, compositionData, networkIdByName);
204 public Set<CompositionEntityValidationData> getAllErrorsByVsp(String vspId) {
205 Set<CompositionEntityValidationData> entitiesWithErrors = new HashSet<>();
206 for (CompositionEntityValidationData root : roots) {
207 if (root.getEntityId().equals(vspId)) {
208 getEntityListWithErrors(root, entitiesWithErrors);
213 if (CollectionUtils.isNotEmpty(entitiesWithErrors)) {
214 updateValidationCompositionEntityName(entitiesWithErrors);
215 return entitiesWithErrors;
218 return new HashSet<>();
221 private boolean isThereErrorsInSubTree(CompositionEntityValidationData entity) {
222 if (Objects.isNull(entity)) {
226 if (CollectionUtils.isNotEmpty(entity.getErrors())) {
230 Collection<CompositionEntityValidationData> subEntitiesValidationData =
231 entity.getSubEntitiesValidationData();
232 return !CollectionUtils.isEmpty(subEntitiesValidationData) &&
233 checkForErrorsInChildren(subEntitiesValidationData);
237 private boolean checkForErrorsInChildren(
238 Collection<CompositionEntityValidationData> subEntitiesValidationData) {
239 boolean result = false;
240 for (CompositionEntityValidationData subEntity : subEntitiesValidationData) {
241 if (CollectionUtils.isNotEmpty(subEntity.getErrors())) {
245 result = isThereErrorsInSubTree(subEntity) || result;
253 private void saveComponents(String vspId, Version version, CompositionData compositionData,
254 Map<String, String> networkIdByName) {
255 if (CollectionUtils.isNotEmpty(compositionData.getComponents())) {
256 for (Component component : compositionData.getComponents()) {
257 ComponentEntity componentEntity = new ComponentEntity(vspId, version, null);
258 componentEntity.setComponentCompositionData(component.getData());
260 String componentId = createComponent(componentEntity, false).getId();
262 saveImagesByComponent(vspId, version, component, componentId);
263 saveComputesFlavorByComponent(vspId, version, component, componentId);
265 saveNicsByComponent(vspId, version, networkIdByName, component, componentId);
270 private void saveNicsByComponent(String vspId, Version version,
271 Map<String, String> networkIdByName, Component component,
272 String componentId) {
273 if (CollectionUtils.isNotEmpty(component.getNics())) {
274 for (Nic nic : component.getNics()) {
275 if (nic.getNetworkName() != null && MapUtils.isNotEmpty(networkIdByName)) {
276 nic.setNetworkId(networkIdByName.get(nic.getNetworkName()));
278 nic.setNetworkName(null);
279 //For heat flow set network type to be internal by default for NIC
280 nic.setNetworkType(NetworkType.Internal);
282 NicEntity nicEntity = new NicEntity(vspId, version, componentId, null);
283 nicEntity.setNicCompositionData(nic);
284 createNic(nicEntity);
289 private Map<String, String> saveNetworks(String vspId, Version version,
290 CompositionData compositionData) {
291 Map<String, String> networkIdByName = new HashMap<>();
292 if (CollectionUtils.isNotEmpty(compositionData.getNetworks())) {
293 for (Network network : compositionData.getNetworks()) {
295 NetworkEntity networkEntity = new NetworkEntity(vspId, version, null);
296 networkEntity.setNetworkCompositionData(network);
298 if (network.getName() != null) {
299 networkIdByName.put(network.getName(), createNetwork(networkEntity).getId());
303 return networkIdByName;
306 private NetworkEntity createNetwork(NetworkEntity network) {
307 //network.setId(CommonMethods.nextUuId()); will be set by the dao
308 networkDao.create(network);
313 public ComponentEntity createComponent(ComponentEntity component, boolean isManualVsp) {
314 //component.setId(CommonMethods.nextUuId()); will be set by the dao
315 ComponentQuestionnaireSchemaInput schemaInput = new ComponentQuestionnaireSchemaInput(null,
316 null, component.getComponentCompositionData().getDisplayName(), isManualVsp);
317 String questionnarieData = new JsonSchemaDataGenerator(generateSchema(SchemaTemplateContext.questionnaire,
318 CompositionEntityType.component, schemaInput)).generateData();
319 component.setQuestionnaireData(questionnarieData);
321 componentDao.create(component);
326 public NicEntity createNic(NicEntity nic) {
327 //nic.setId(CommonMethods.nextUuId()); will be set by the dao
328 nic.setQuestionnaireData(
329 new JsonSchemaDataGenerator(
330 generateSchema(SchemaTemplateContext.questionnaire, CompositionEntityType.nic, null))
338 public void addErrorsToTrees(Map<CompositionEntityId, Collection<String>> errors) {
339 roots.forEach(root -> addErrorsToTree(root, null, errors));
343 * get a flat list of all questionnaire entities that have validation errors
345 public Set<CompositionEntityValidationData> getEntityListWithErrors() {
346 Set<CompositionEntityValidationData> treeAsList = new HashSet<>();
348 for (CompositionEntityValidationData entity : roots) {
349 if (CollectionUtils.isNotEmpty(entity.getErrors())) {
350 addNodeWithErrors(entity, treeAsList);
352 getEntityListWithErrors(entity, treeAsList);
355 updateValidationCompositionEntityName(treeAsList);
359 private void getEntityListWithErrors(CompositionEntityValidationData entity,
360 Set<CompositionEntityValidationData> compositionSet) {
361 if (CollectionUtils.isNotEmpty(entity.getErrors())) {
362 addNodeWithErrors(entity, compositionSet);
365 if (CollectionUtils.isEmpty(entity.getSubEntitiesValidationData())) {
369 for (CompositionEntityValidationData child : entity.getSubEntitiesValidationData()) {
370 getEntityListWithErrors(child, compositionSet);
375 private void addNodeWithErrors(CompositionEntityValidationData node,
376 Set<CompositionEntityValidationData> entitiesWithErrors) {
377 CompositionEntityValidationData compositionNodeToAdd = new CompositionEntityValidationData(node
378 .getEntityType(), node.getEntityId());
379 compositionNodeToAdd.setErrors(node.getErrors());
380 compositionNodeToAdd.setSubEntitiesValidationData(null);
382 entitiesWithErrors.add(compositionNodeToAdd);
385 public void removeNodesWithoutErrors() {
386 roots.forEach(root -> removeNodesWithoutErrors(root, null));
390 private CompositionEntityData getCompositionEntityDataById(CompositionEntityValidationData
392 for (Map.Entry<CompositionEntityId, CompositionEntityData> entityEntry : entities
394 if (entityEntry.getKey().getId().equals(entity.getEntityId())) {
395 return entityEntry.getValue();
402 private void updateValidationCompositionEntityName(Set<CompositionEntityValidationData>
404 for (CompositionEntityValidationData entity : compositionSet) {
405 String compositionData = getCompositionDataAsString(entity);
406 if (entity.getEntityType().equals(CompositionEntityType.vsp) ||
407 Objects.nonNull(compositionData)) {
408 entity.setEntityName(getEntityNameByEntityType(compositionData, entity));
413 private String getCompositionDataAsString(CompositionEntityValidationData entity) {
414 CompositionEntityData compositionEntityData = getCompositionEntityDataById(entity);
415 return compositionEntityData == null ? null : compositionEntityData.entity.getCompositionData();
419 private String getEntityNameByEntityType(String compositionData,
420 CompositionEntityValidationData entity) {
421 switch (entity.getEntityType()) {
423 ComponentData component = JsonUtil.json2Object(compositionData, ComponentData.class);
424 return component.getDisplayName();
427 Nic nic = JsonUtil.json2Object(compositionData, Nic.class);
428 return nic.getName();
431 Network network = JsonUtil.json2Object(compositionData, Network.class);
432 return network.getName();
435 Image image = JsonUtil.json2Object(compositionData, Image.class);
436 return image.getFileName();
439 ComputeData compute = JsonUtil.json2Object(compositionData, ComputeData.class);
440 return compute.getName();
443 CompositionEntityData vspEntity = getCompositionEntityDataById(entity);
444 if (Objects.isNull(vspEntity)) {
447 VspQuestionnaireEntity vspQuestionnaireEntity = (VspQuestionnaireEntity) vspEntity.entity;
448 VspDetails vspDetails =
449 vspInfoDao.get(new VspDetails(vspQuestionnaireEntity.getId(),
450 vspQuestionnaireEntity.getVersion()));
451 return vspDetails.getName();
457 private void removeNodesWithoutErrors(CompositionEntityValidationData node,
458 CompositionEntityValidationData parent) {
460 if (Objects.isNull(node)) {
464 if (hasChildren(node)) {
465 Collection<CompositionEntityValidationData> subNodes =
466 new ArrayList<>(node.getSubEntitiesValidationData());
467 subNodes.forEach(subNode -> removeNodesWithoutErrors(subNode, node));
468 node.setSubEntitiesValidationData(subNodes);
470 if (canNodeGetRemovedFromValidationDataTree(node)) {
471 removeNodeFromChildren(parent, node);
473 } else if (canNodeGetRemovedFromValidationDataTree(node)) {
474 removeNodeFromChildren(parent, node);
478 private void removeNodeFromChildren(CompositionEntityValidationData parent,
479 CompositionEntityValidationData childToRemove) {
480 if (!Objects.isNull(parent)) {
481 parent.getSubEntitiesValidationData().remove(childToRemove);
485 private boolean hasChildren(CompositionEntityValidationData node) {
486 return !CollectionUtils.isEmpty(node.getSubEntitiesValidationData());
489 private boolean canNodeGetRemovedFromValidationDataTree(CompositionEntityValidationData node) {
490 return !hasChildren(node) && CollectionUtils.isEmpty(node.getErrors());
494 private void addValidationDataEntity(
495 Map<CompositionEntityId, CompositionEntityValidationData> entitiesValidationData,
496 CompositionEntityId entityId, CompositionEntity entity) {
497 if (entitiesValidationData.containsKey(entityId)) {
501 CompositionEntityValidationData validationData =
502 new CompositionEntityValidationData(entity.getType(), entity.getId());
503 entitiesValidationData.put(entityId, validationData);
505 CompositionEntityId parentEntityId = entityId.getParentId();
506 if (parentEntityId == null) {
507 roots.add(validationData);
509 CompositionEntityData parentEntity = entities.get(parentEntityId);
510 if (parentEntity == null) {
511 roots.add(validationData);
513 addValidationDataEntity(entitiesValidationData, parentEntityId, parentEntity.entity);
514 entitiesValidationData.get(parentEntityId).addSubEntityValidationData(validationData);
519 private void addErrorsToTree(CompositionEntityValidationData node,
520 CompositionEntityId parentNodeId,
521 Map<CompositionEntityId, Collection<String>> errors) {
525 CompositionEntityId nodeId = new CompositionEntityId(node.getEntityId(), parentNodeId);
526 node.setErrors(errors.get(nodeId));
528 if (node.getSubEntitiesValidationData() != null) {
529 node.getSubEntitiesValidationData()
530 .forEach(subNode -> addErrorsToTree(subNode, nodeId, errors));
534 private Collection<String> validateQuestionnaire(CompositionEntityData compositionEntityData) {
535 logger.debug(String.format("validateQuestionnaire start: " +
536 "[entity.type]=%s, [entity.id]=%s, [entity.questionnaireString]=%s",
537 compositionEntityData.entity.getType().name(),
538 compositionEntityData.entity.getCompositionEntityId().toString(),
539 compositionEntityData.entity.getQuestionnaireData()));
541 if (Objects.isNull(compositionEntityData.entity.getQuestionnaireData()) ||
542 !JsonUtil.isValidJson(compositionEntityData.entity.getQuestionnaireData())) {
543 return Collections.singletonList(String
544 .format(MISSING_OR_INVALID_QUESTIONNAIRE_MSG, compositionEntityData.entity.getType()));
547 return JsonUtil.validate(
548 compositionEntityData.entity.getQuestionnaireData() == null
549 ? JsonUtil.object2Json(new Object())
550 : compositionEntityData.entity.getQuestionnaireData(),
551 getSchema(compositionEntityData.entity.getType(), SchemaTemplateContext.questionnaire,
552 compositionEntityData.schemaTemplateInput));
555 private String getSchema(CompositionEntityType compositionEntityType,
556 SchemaTemplateContext schemaTemplateContext,
557 SchemaTemplateInput schemaTemplateInput) {
558 return schemaTemplateInput == null
559 ? nonDynamicSchemas.computeIfAbsent(compositionEntityType,
560 k -> generateSchema(schemaTemplateContext, compositionEntityType, null))
561 : generateSchema(schemaTemplateContext, compositionEntityType, schemaTemplateInput);
564 private static class CompositionEntityData {
565 private CompositionEntity entity;
566 private SchemaTemplateInput schemaTemplateInput;
568 CompositionEntityData(CompositionEntity entity, SchemaTemplateInput schemaTemplateInput) {
569 this.entity = entity;
570 this.schemaTemplateInput = schemaTemplateInput;
575 // todo - make SchemaGenerator non static and mock it in UT instead of mocking this method (and
576 // make the method private
577 protected String generateSchema(SchemaTemplateContext schemaTemplateContext,
578 CompositionEntityType compositionEntityType,
579 SchemaTemplateInput schemaTemplateInput) {
580 return SchemaGenerator
581 .generate(schemaTemplateContext, compositionEntityType, schemaTemplateInput);
585 public DeploymentFlavorEntity createDeploymentFlavor(DeploymentFlavorEntity deploymentFlavor) {
586 deploymentFlavor.setId(CommonMethods.nextUuId());
587 deploymentFlavorDao.create(deploymentFlavor);
588 return deploymentFlavor;
592 public ImageEntity createImage(ImageEntity image) {
593 image.setId(CommonMethods.nextUuId());
595 image.setQuestionnaireData(
596 new JsonSchemaDataGenerator(SchemaGenerator
597 .generate(SchemaTemplateContext.questionnaire, CompositionEntityType.image, null))
600 imageDao.create(image);
604 public void saveComputesFlavorByComponent(String vspId, Version version, Component component,
605 String componentId) {
606 if (CollectionUtils.isNotEmpty(component.getCompute())) {
607 for (ComputeData flavor : component.getCompute()) {
608 ComputeEntity computeEntity = new ComputeEntity(vspId, version, componentId, null);
609 computeEntity.setComputeCompositionData(flavor);
610 computeEntity.setQuestionnaireData(
611 new JsonSchemaDataGenerator(SchemaGenerator
612 .generate(SchemaTemplateContext.questionnaire, CompositionEntityType.compute,
613 null)).generateData());
615 computeDao.create(computeEntity);
620 public void saveImagesByComponent(String vspId, Version version, Component component, String
622 if (CollectionUtils.isNotEmpty(component.getImages())) {
623 for (Image img : component.getImages()) {
624 ImageEntity imageEntity = new ImageEntity(vspId, version, componentId, null);
625 imageEntity.setImageCompositionData(img);
626 createImage(imageEntity);