[SDC-29] Amdocs OnBoard 1707 initial commit.
[sdc.git] / openecomp-be / lib / openecomp-sdc-vendor-software-product-lib / openecomp-sdc-vendor-software-product-core / src / main / java / org / openecomp / sdc / vendorsoftwareproduct / services / impl / composition / CompositionEntityDataManagerImpl.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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  */
20
21 package org.openecomp.sdc.vendorsoftwareproduct.services.impl.composition;
22
23 import org.apache.commons.collections4.CollectionUtils;
24 import org.apache.commons.collections4.MapUtils;
25 import org.openecomp.core.utilities.json.JsonSchemaDataGenerator;
26 import org.openecomp.core.utilities.json.JsonUtil;
27 import org.openecomp.sdc.common.errors.CoreException;
28 import org.openecomp.sdc.common.errors.ErrorCategory;
29 import org.openecomp.sdc.common.errors.ErrorCode;
30 import org.openecomp.sdc.logging.context.impl.MdcDataDebugMessage;
31 import org.openecomp.sdc.vendorsoftwareproduct.dao.ComponentDao;
32 import org.openecomp.sdc.vendorsoftwareproduct.dao.NetworkDao;
33 import org.openecomp.sdc.vendorsoftwareproduct.dao.NicDao;
34 import org.openecomp.sdc.vendorsoftwareproduct.dao.VendorSoftwareProductInfoDao;
35 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.ComponentEntity;
36 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.CompositionEntity;
37 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.NetworkEntity;
38 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.NicEntity;
39 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspDetails;
40 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspQuestionnaireEntity;
41 import org.openecomp.sdc.vendorsoftwareproduct.services.composition.CompositionEntityDataManager;
42 import org.openecomp.sdc.vendorsoftwareproduct.services.schemagenerator.SchemaGenerator;
43 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.Component;
44 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.ComponentData;
45 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.CompositionData;
46 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.CompositionEntityId;
47 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.CompositionEntityType;
48 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.CompositionEntityValidationData;
49 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.Network;
50 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.Nic;
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;
54
55 import java.util.ArrayList;
56 import java.util.Collection;
57 import java.util.HashMap;
58 import java.util.HashSet;
59 import java.util.List;
60 import java.util.Map;
61 import java.util.Objects;
62 import java.util.Set;
63
64 public class CompositionEntityDataManagerImpl implements CompositionEntityDataManager {
65
66   private static final String COMPOSITION_ENTITY_DATA_MANAGER_ERR =
67       "COMPOSITION_ENTITY_DATA_MANAGER_ERR";
68   private static final String COMPOSITION_ENTITY_DATA_MANAGER_ERR_MSG =
69       "Invalid input: %s may not be null";
70
71   private static MdcDataDebugMessage mdcDataDebugMessage = new MdcDataDebugMessage();
72
73   private Map<CompositionEntityId, CompositionEntityData> entities = new HashMap<>();
74   private Map<CompositionEntityType, String> nonDynamicSchemas = new HashMap<>();
75   private List<CompositionEntityValidationData> roots = new ArrayList<>();
76
77   private VendorSoftwareProductInfoDao vspInfoDao;
78   private ComponentDao componentDao;
79   private NicDao nicDao;
80   private NetworkDao networkDao;
81
82   public CompositionEntityDataManagerImpl(VendorSoftwareProductInfoDao vspInfoDao,
83                                           ComponentDao componentDao,
84                                           NicDao nicDao, NetworkDao networkDao) {
85     this.vspInfoDao = vspInfoDao;
86     this.componentDao = componentDao;
87     this.nicDao = nicDao;
88     this.networkDao = networkDao;
89   }
90
91   /**
92    * Validate entity composition entity validation data.
93    *
94    * @param entity                the entity
95    * @param schemaTemplateContext the schema template context
96    * @param schemaTemplateInput   the schema template input
97    * @return the composition entity validation data
98    */
99   @Override
100   public CompositionEntityValidationData validateEntity(CompositionEntity entity,
101                                                         SchemaTemplateContext schemaTemplateContext,
102                                                         SchemaTemplateInput schemaTemplateInput) {
103     mdcDataDebugMessage.debugEntryMessage(null);
104
105     if (entity == null) {
106       throw new CoreException(
107           new ErrorCode.ErrorCodeBuilder().withCategory(ErrorCategory.APPLICATION)
108               .withId(COMPOSITION_ENTITY_DATA_MANAGER_ERR).withMessage(
109               String.format(COMPOSITION_ENTITY_DATA_MANAGER_ERR_MSG, "composition entity"))
110               .build());
111     }
112     if (schemaTemplateContext == null) {
113       throw new CoreException(
114           new ErrorCode.ErrorCodeBuilder().withCategory(ErrorCategory.APPLICATION)
115               .withId(COMPOSITION_ENTITY_DATA_MANAGER_ERR).withMessage(
116               String.format(COMPOSITION_ENTITY_DATA_MANAGER_ERR_MSG, "schema template context"))
117               .build());
118     }
119
120     CompositionEntityValidationData validationData =
121         new CompositionEntityValidationData(entity.getType(), entity.getId());
122     String json =
123         schemaTemplateContext == SchemaTemplateContext.composition ? entity.getCompositionData()
124             : entity.getQuestionnaireData();
125     validationData.setErrors(JsonUtil.validate(
126         json == null ? JsonUtil.object2Json(new Object()) : json,
127         generateSchema(schemaTemplateContext, entity.getType(), schemaTemplateInput)));
128
129     mdcDataDebugMessage.debugExitMessage(null);
130     return validationData;
131   }
132
133   /**
134    * Add entity.
135    *
136    * @param entity              the entity
137    * @param schemaTemplateInput the schema template input
138    */
139   @Override
140   public void addEntity(CompositionEntity entity, SchemaTemplateInput schemaTemplateInput) {
141     if (entity == null) {
142       throw new CoreException(
143           new ErrorCode.ErrorCodeBuilder().withCategory(ErrorCategory.APPLICATION)
144               .withId(COMPOSITION_ENTITY_DATA_MANAGER_ERR).withMessage(
145               String.format(COMPOSITION_ENTITY_DATA_MANAGER_ERR_MSG, "composition entity"))
146               .build());
147     }
148     entities.put(entity.getCompositionEntityId(),
149         new CompositionEntityData(entity, schemaTemplateInput));
150   }
151
152   /**
153    * Validate entities questionnaire map.
154    *
155    * @return the map
156    */
157   @Override
158   public Map<CompositionEntityId, Collection<String>> validateEntitiesQuestionnaire() {
159     mdcDataDebugMessage.debugEntryMessage(null);
160
161     Map<CompositionEntityId, Collection<String>> errorsByEntityId = new HashMap<>();
162     entities.entrySet().forEach(entry -> {
163       Collection<String> errors = validateQuestionnaire(entry.getValue());
164       if (errors != null) {
165         errorsByEntityId.put(entry.getKey(), errors);
166       }
167     });
168
169     mdcDataDebugMessage.debugExitMessage(null);
170     return errorsByEntityId;
171   }
172
173   /**
174    * Build trees.
175    */
176   @Override
177   public void buildTrees() {
178     Map<CompositionEntityId, CompositionEntityValidationData> entitiesValidationData =
179         new HashMap<>();
180     entities.entrySet().forEach(
181         entry -> addValidationDataEntity(entitiesValidationData, entry.getKey(),
182             entry.getValue().entity));
183   }
184
185   public Collection<CompositionEntityValidationData> getTrees() {
186     return roots;
187   }
188
189   @Override
190   public void saveCompositionData(String vspId, Version version, CompositionData compositionData) {
191     mdcDataDebugMessage.debugEntryMessage(null);
192
193     if (Objects.isNull(compositionData)) {
194       return;
195     }
196
197     Map<String, String> networkIdByName = saveNetworks(vspId, version, compositionData);
198     saveComponents(vspId, version, compositionData, networkIdByName);
199
200     mdcDataDebugMessage.debugExitMessage(null);
201   }
202
203   @Override
204   public Set<CompositionEntityValidationData> getAllErrorsByVsp(String vspId) {
205     CompositionEntityValidationData matchVsp = null;
206     Set<CompositionEntityValidationData> entitiesWithErrors = new HashSet<>();
207     for (CompositionEntityValidationData root : roots) {
208       if (root.getEntityId().equals(vspId)) {
209         matchVsp = root;
210         break;
211       }
212     }
213
214     getEntityListWithErrors(matchVsp, entitiesWithErrors);
215     if (CollectionUtils.isNotEmpty(entitiesWithErrors)) {
216       updateValidationCompositionEntityName(entitiesWithErrors);
217       return entitiesWithErrors;
218     }
219
220     return null;
221   }
222
223   private boolean isThereErrorsInSubTree(CompositionEntityValidationData entity) {
224     if (Objects.isNull(entity)) {
225       return false;
226     }
227
228     if (CollectionUtils.isNotEmpty(entity.getErrors())) {
229       return true;
230     }
231
232     Collection<CompositionEntityValidationData> subEntitiesValidationData =
233         entity.getSubEntitiesValidationData();
234     return !CollectionUtils.isEmpty(subEntitiesValidationData) &&
235         checkForErrorsInChildren(subEntitiesValidationData);
236
237   }
238
239   private boolean checkForErrorsInChildren(
240       Collection<CompositionEntityValidationData> subEntitiesValidationData) {
241     boolean result = false;
242     for (CompositionEntityValidationData subEntity : subEntitiesValidationData) {
243       if (CollectionUtils.isNotEmpty(subEntity.getErrors())) {
244         return true;
245       }
246
247       result = result || isThereErrorsInSubTree(subEntity);
248       if (result) {
249         return true;
250       }
251     }
252     return false;
253   }
254
255   public void saveComponents(String vspId, Version version, CompositionData compositionData,
256                              Map<String, String> networkIdByName) {
257
258
259     mdcDataDebugMessage.debugEntryMessage(null);
260
261     if (CollectionUtils.isNotEmpty(compositionData.getComponents())) {
262       for (Component component : compositionData.getComponents()) {
263         ComponentEntity componentEntity = new ComponentEntity(vspId, version, null);
264         componentEntity.setComponentCompositionData(component.getData());
265
266         String componentId = createComponent(componentEntity).getId();
267
268         saveNicsByComponent(vspId, version, networkIdByName, component, componentId);
269       }
270     }
271
272     mdcDataDebugMessage.debugExitMessage(null);
273   }
274
275   public void saveNicsByComponent(String vspId, Version version,
276                                   Map<String, String> networkIdByName, Component component,
277                                   String componentId) {
278     if (CollectionUtils.isNotEmpty(component.getNics())) {
279       for (Nic nic : component.getNics()) {
280         if (nic.getNetworkName() != null && MapUtils.isNotEmpty(networkIdByName)) {
281           nic.setNetworkId(networkIdByName.get(nic.getNetworkName()));
282         }
283         nic.setNetworkName(null);
284
285         NicEntity nicEntity = new NicEntity(vspId, version, componentId, null);
286         nicEntity.setNicCompositionData(nic);
287         createNic(nicEntity);
288       }
289     }
290   }
291
292   public Map<String, String> saveNetworks(String vspId, Version version,
293                                           CompositionData compositionData) {
294     mdcDataDebugMessage.debugEntryMessage(null);
295
296     Map<String, String> networkIdByName = new HashMap<>();
297     if (CollectionUtils.isNotEmpty(compositionData.getNetworks())) {
298       for (Network network : compositionData.getNetworks()) {
299
300         NetworkEntity networkEntity = new NetworkEntity(vspId, version, null);
301         networkEntity.setNetworkCompositionData(network);
302
303         if (network.getName() != null) {
304           networkIdByName.put(network.getName(), createNetwork(networkEntity).getId());
305         }
306       }
307     }
308
309     mdcDataDebugMessage.debugExitMessage(null);
310     return networkIdByName;
311   }
312
313   @Override
314   public NetworkEntity createNetwork(NetworkEntity network) {
315     mdcDataDebugMessage.debugEntryMessage(null);
316
317     //network.setId(CommonMethods.nextUuId()); will be set by the dao
318     networkDao.create(network);
319     mdcDataDebugMessage.debugExitMessage(null);
320     return network;
321   }
322
323   @Override
324   public ComponentEntity createComponent(ComponentEntity component) {
325     mdcDataDebugMessage.debugEntryMessage(null);
326
327     //component.setId(CommonMethods.nextUuId()); will be set by the dao
328     component.setQuestionnaireData(
329         new JsonSchemaDataGenerator(
330             generateSchema(SchemaTemplateContext.questionnaire, CompositionEntityType.component,
331                 null))
332             .generateData());
333
334     componentDao.create(component);
335
336     mdcDataDebugMessage.debugExitMessage(null);
337     return component;
338   }
339
340   @Override
341   public NicEntity createNic(NicEntity nic) {
342     mdcDataDebugMessage.debugEntryMessage(null);
343
344     //nic.setId(CommonMethods.nextUuId()); will be set by the dao
345     nic.setQuestionnaireData(
346         new JsonSchemaDataGenerator(
347             generateSchema(SchemaTemplateContext.questionnaire, CompositionEntityType.nic, null))
348             .generateData());
349
350     nicDao.create(nic);
351
352     mdcDataDebugMessage.debugExitMessage(null);
353     return nic;
354   }
355
356
357   public void addErrorsToTrees(Map<CompositionEntityId, Collection<String>> errors) {
358     roots.forEach(root -> addErrorsToTree(root, null, errors));
359   }
360
361   /* *
362   * get a flat list of all questionnaire entities that have validation errors
363   * */
364   public Set<CompositionEntityValidationData> getEntityListWithErrors() {
365     mdcDataDebugMessage.debugEntryMessage(null);
366     Set<CompositionEntityValidationData> treeAsList = new HashSet<>();
367
368     for (CompositionEntityValidationData entity : roots) {
369       if (CollectionUtils.isNotEmpty(entity.getErrors())) {
370         addNodeWithErrors(entity, treeAsList);
371       }
372       getEntityListWithErrors(entity, treeAsList);
373     }
374
375     updateValidationCompositionEntityName(treeAsList);
376
377     mdcDataDebugMessage.debugExitMessage(null);
378     return treeAsList;
379   }
380
381   public void getEntityListWithErrors(CompositionEntityValidationData entity,
382                                       Set<CompositionEntityValidationData> compositionSet) {
383     Collection<CompositionEntityValidationData> childNodes =
384         entity.getSubEntitiesValidationData();
385
386     if (CollectionUtils.isEmpty(childNodes)) {
387       return;
388     }
389
390     for (CompositionEntityValidationData child : childNodes) {
391       if (CollectionUtils.isNotEmpty(child.getErrors())) {
392         addNodeWithErrors(child, compositionSet);
393       }
394       getEntityListWithErrors(child, compositionSet);
395     }
396   }
397
398
399   public void addNodeWithErrors(CompositionEntityValidationData node,
400                                 Set<CompositionEntityValidationData> entitiesWithErrors) {
401     CompositionEntityValidationData compositionNodeToAdd = new CompositionEntityValidationData(node
402         .getEntityType(), node.getEntityId());
403     compositionNodeToAdd.setErrors(node.getErrors());
404     compositionNodeToAdd.setSubEntitiesValidationData(null);
405
406     entitiesWithErrors.add(compositionNodeToAdd);
407   }
408
409   public void removeNodesWithoutErrors() {
410     roots.forEach(root -> removeNodesWithoutErrors(root, null));
411   }
412
413
414   private CompositionEntityData getCompositionEntityDataById(CompositionEntityValidationData
415                                                                  entity) {
416     for (Map.Entry<CompositionEntityId, CompositionEntityData> entityEntry : entities
417         .entrySet()) {
418       if (entityEntry.getKey().getId().equals(entity.getEntityId())) {
419         return entityEntry.getValue();
420       }
421     }
422     return null;
423   }
424
425
426   private void updateValidationCompositionEntityName(Set<CompositionEntityValidationData>
427                                                          compositionSet) {
428     for (CompositionEntityValidationData entity : compositionSet) {
429       String compositionData = getCompositionDataAsString(entity);
430       if (entity.getEntityType().equals(CompositionEntityType.vsp) ||
431           Objects.nonNull(compositionData)) {
432         entity.setEntityName(getEntityNameByEntityType(compositionData, entity));
433       }
434     }
435   }
436
437   private String getCompositionDataAsString(CompositionEntityValidationData entity) {
438     CompositionEntityData compositionEntityData = getCompositionEntityDataById(entity);
439     return compositionEntityData == null ? null : compositionEntityData.entity.getCompositionData();
440   }
441
442
443   private String getEntityNameByEntityType(String compositionData,
444                                            CompositionEntityValidationData entity) {
445     switch (entity.getEntityType()) {
446       case component:
447         ComponentData component = JsonUtil.json2Object(compositionData, ComponentData.class);
448         return component.getDisplayName();
449
450       case nic:
451         Nic nic = JsonUtil.json2Object(compositionData, Nic.class);
452         return nic.getName();
453
454       case network:
455         Network network = JsonUtil.json2Object(compositionData, Network.class);
456         return network.getName();
457
458       case vsp:
459         CompositionEntityData vspEntity = getCompositionEntityDataById(entity);
460         VspQuestionnaireEntity vspQuestionnaireEntity = (VspQuestionnaireEntity) vspEntity.entity;
461         VspDetails vspDetails =
462             vspInfoDao.get(new VspDetails(vspQuestionnaireEntity.getId(),
463                     vspQuestionnaireEntity.getVersion()));
464         return vspDetails.getName();
465     }
466
467     return null;
468   }
469
470   private void removeNodesWithoutErrors(CompositionEntityValidationData node,
471                                         CompositionEntityValidationData parent) {
472
473     if (Objects.isNull(node)) {
474       return;
475     }
476
477     if (hasChildren(node)) {
478       Collection<CompositionEntityValidationData> subNodes =
479           new ArrayList<>(node.getSubEntitiesValidationData());
480       subNodes.forEach(subNode -> removeNodesWithoutErrors(subNode, node));
481       node.setSubEntitiesValidationData(subNodes);
482
483       if (canNodeGetRemovedFromValidationDataTree(node)) {
484         removeNodeFromChildren(parent, node);
485       }
486     } else if (canNodeGetRemovedFromValidationDataTree(node)) {
487       removeNodeFromChildren(parent, node);
488     }
489   }
490
491   private void removeNodeFromChildren(CompositionEntityValidationData parent,
492                                       CompositionEntityValidationData childToRemove) {
493     if (!Objects.isNull(parent)) {
494       parent.getSubEntitiesValidationData().remove(childToRemove);
495     }
496   }
497
498   private boolean hasChildren(CompositionEntityValidationData node) {
499     return !CollectionUtils.isEmpty(node.getSubEntitiesValidationData());
500   }
501
502   private boolean canNodeGetRemovedFromValidationDataTree(CompositionEntityValidationData node) {
503     return !hasChildren(node) && CollectionUtils.isEmpty(node.getErrors());
504   }
505
506
507   private void addValidationDataEntity(
508       Map<CompositionEntityId, CompositionEntityValidationData> entitiesValidationData,
509       CompositionEntityId entityId, CompositionEntity entity) {
510     if (entitiesValidationData.containsKey(entityId)) {
511       return;
512     }
513
514     CompositionEntityValidationData validationData =
515         new CompositionEntityValidationData(entity.getType(), entity.getId());
516     entitiesValidationData.put(entityId, validationData);
517
518     CompositionEntityId parentEntityId = entityId.getParentId();
519     if (parentEntityId == null) {
520       roots.add(validationData);
521     } else {
522       CompositionEntityData parentEntity = entities.get(parentEntityId);
523       if (parentEntity == null) {
524         roots.add(validationData);
525       } else {
526         addValidationDataEntity(entitiesValidationData, parentEntityId, parentEntity.entity);
527         entitiesValidationData.get(parentEntityId).addSubEntityValidationData(validationData);
528       }
529     }
530   }
531
532   private void addErrorsToTree(CompositionEntityValidationData node,
533                                CompositionEntityId parentNodeId,
534                                Map<CompositionEntityId, Collection<String>> errors) {
535     if (node == null) {
536       return;
537     }
538     CompositionEntityId nodeId = new CompositionEntityId(node.getEntityId(), parentNodeId);
539     node.setErrors(errors.get(nodeId));
540
541     if (node.getSubEntitiesValidationData() != null) {
542       node.getSubEntitiesValidationData()
543           .forEach(subNode -> addErrorsToTree(subNode, nodeId, errors));
544     }
545   }
546
547   private Collection<String> validateQuestionnaire(CompositionEntityData compositionEntityData) {
548     return JsonUtil.validate(
549         compositionEntityData.entity.getQuestionnaireData() == null
550             ? JsonUtil.object2Json(new Object())
551             : compositionEntityData.entity.getQuestionnaireData(),
552         getSchema(compositionEntityData.entity.getType(), SchemaTemplateContext.questionnaire,
553             compositionEntityData.schemaTemplateInput));
554   }
555
556   private String getSchema(CompositionEntityType compositionEntityType,
557                            SchemaTemplateContext schemaTemplateContext,
558                            SchemaTemplateInput schemaTemplateInput) {
559     return schemaTemplateInput == null
560         ? nonDynamicSchemas.computeIfAbsent(compositionEntityType,
561         k -> generateSchema(schemaTemplateContext, compositionEntityType, null))
562         : generateSchema(schemaTemplateContext, compositionEntityType, schemaTemplateInput);
563   }
564
565   private static class CompositionEntityData {
566     private CompositionEntity entity;
567     private SchemaTemplateInput schemaTemplateInput;
568
569     CompositionEntityData(CompositionEntity entity, SchemaTemplateInput schemaTemplateInput) {
570       this.entity = entity;
571       this.schemaTemplateInput = schemaTemplateInput;
572     }
573
574   }
575
576   // todo - make SchemaGenerator non static and mock it in UT instead of mocking this method (and
577   // make the method private
578
579   protected String generateSchema(SchemaTemplateContext schemaTemplateContext,
580                                   CompositionEntityType compositionEntityType,
581                                   SchemaTemplateInput schemaTemplateInput) {
582     return SchemaGenerator
583         .generate(schemaTemplateContext, compositionEntityType, schemaTemplateInput);
584   }
585 }