e1807bafad4c49be215a9700a731b15a9261bc13
[sdc.git] /
1 /*
2  * Copyright © 2018 European Support Limited
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package org.openecomp.sdc.healing.healers;
18
19 import com.amdocs.zusammen.adaptor.inbound.api.types.item.Element;
20 import com.amdocs.zusammen.adaptor.inbound.api.types.item.ElementInfo;
21 import com.amdocs.zusammen.adaptor.inbound.api.types.item.ZusammenElement;
22 import com.amdocs.zusammen.datatypes.Id;
23 import com.amdocs.zusammen.datatypes.SessionContext;
24 import com.amdocs.zusammen.datatypes.item.Action;
25 import com.amdocs.zusammen.datatypes.item.ElementContext;
26 import com.amdocs.zusammen.utils.fileutils.FileUtils;
27 import org.apache.commons.io.IOUtils;
28 import org.apache.commons.lang.ArrayUtils;
29 import org.apache.commons.lang.StringUtils;
30 import org.openecomp.core.utilities.file.FileContentHandler;
31 import org.openecomp.core.utilities.orchestration.OnboardingTypesEnum;
32 import org.openecomp.core.zusammen.api.ZusammenAdaptor;
33 import org.openecomp.core.zusammen.api.ZusammenAdaptorFactory;
34 import org.openecomp.sdc.common.errors.CoreException;
35 import org.openecomp.sdc.common.errors.ErrorCode;
36 import org.openecomp.sdc.common.utils.CommonUtil;
37 import org.openecomp.sdc.datatypes.error.ErrorLevel;
38 import org.openecomp.sdc.datatypes.model.ElementType;
39 import org.openecomp.sdc.healing.interfaces.Healer;
40 import org.openecomp.sdc.vendorsoftwareproduct.dao.VendorSoftwareProductInfoDao;
41 import org.openecomp.sdc.vendorsoftwareproduct.dao.VendorSoftwareProductInfoDaoFactory;
42 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.OnboardingMethod;
43 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.OrchestrationTemplateCandidateData;
44 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.OrchestrationTemplateEntity;
45 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspDetails;
46 import org.openecomp.sdc.vendorsoftwareproduct.factory.CandidateServiceFactory;
47 import org.openecomp.sdc.vendorsoftwareproduct.services.filedatastructuremodule.CandidateService;
48 import org.openecomp.sdc.vendorsoftwareproduct.services.utils.CandidateEntityBuilder;
49 import org.openecomp.sdc.versioning.dao.types.Version;
50
51 import java.io.ByteArrayInputStream;
52 import java.io.IOException;
53 import java.io.InputStream;
54 import java.nio.ByteBuffer;
55 import java.util.Collection;
56 import java.util.Objects;
57
58 import static org.openecomp.core.zusammen.api.ZusammenUtil.*;
59
60 public class NetworkPackageHealer implements Healer {
61
62   private static final byte[] EMPTY_DATA_BYTES = "{}".getBytes();
63   private static final String MISSING_ORCHESTRATION_TEMPLATE_CANDIDATE_ERROR =
64       "Vsp with invalid structure: does not contain element OrchestrationTemplateCandidate";
65   private static final String MISSING_ORCHESTRATION_TEMPLATE_CANDIDATE_CONTENT_ERROR =
66       "Vsp with invalid structure: does not contain element OrchestrationTemplateCandidateContent"
67           + " under OrchestrationTemplateCandidate";
68
69   private static final String MISSING_VSP_MODEL_ERROR =
70       "Vsp with invalid structure: does not contain element VspModel";
71   private static final String MISSING_ORCHESTRATION_TEMPLATE_ERROR =
72       "Vsp with invalid structure: does not contain element OrchestrationTemplate"
73           + " under VspModel element";
74   private static final String MISSING_ORCHESTRATION_TEMPLATE_VALIDATE_DATA_ERROR =
75       "Vsp with invalid structure: does not contain element OrchestrationTemplateValidationData"
76           + " under OrchestrationTemplate element";
77
78   private final VendorSoftwareProductInfoDao vspInfoDao;
79   private final ZusammenAdaptor zusammenAdaptor;
80   private final CandidateService candidateService;
81
82   public NetworkPackageHealer() {
83     this(VendorSoftwareProductInfoDaoFactory.getInstance().createInterface(),
84         ZusammenAdaptorFactory.getInstance().createInterface(), CandidateServiceFactory
85             .getInstance().createInterface());
86   }
87
88   public NetworkPackageHealer(VendorSoftwareProductInfoDao vspInfoDao,
89                               ZusammenAdaptor zusammenAdaptor,
90                               CandidateService candidateService) {
91     this.vspInfoDao = vspInfoDao;
92     this.zusammenAdaptor = zusammenAdaptor;
93     this.candidateService = candidateService;
94   }
95
96   @Override
97   public boolean isHealingNeeded(String itemId, Version version) {
98     return OnboardingMethod.NetworkPackage.name()
99         .equals(vspInfoDao.get(new VspDetails(itemId, version)).getOnboardingMethod()) &&
100         isVspMissingAddedElements(itemId, version);
101   }
102
103   @Override
104   public void heal(String itemId, Version version) throws Exception {
105     SessionContext context = createSessionContext();
106     ElementContext elementContext = new ElementContext(itemId, version.getId());
107
108     Element candidateElement =
109         getElement(context, elementContext, null, ElementType.OrchestrationTemplateCandidate,
110             MISSING_ORCHESTRATION_TEMPLATE_CANDIDATE_ERROR);
111
112     Collection<Element> candidateSubs =
113         zusammenAdaptor.listElementData(context, elementContext, candidateElement.getElementId());
114
115     Id candidateValidationElementId =
116         creatIfAbsentCandidateValidationElementId(candidateSubs, context,
117         elementContext, candidateElement);
118
119     Element orchestrationTemplateElement = getOrchestrationTemplateElement(context, elementContext);
120
121     Collection<Element> orchestrationTemplateSubs = zusammenAdaptor
122         .listElementData(context, elementContext, orchestrationTemplateElement.getElementId());
123
124     Id structureElementId = createIfAbsentStructureElementId(orchestrationTemplateSubs, context,
125         elementContext, orchestrationTemplateElement);
126
127     Element orchestrationTemplateValidationElement = getOrchestrationTemplateValidationElement
128         (orchestrationTemplateSubs);
129
130     OrchestrationTemplateEntity orchestrationTemplateEntity =
131         getOrchestrationTemplateEntity(orchestrationTemplateElement,
132             orchestrationTemplateValidationElement);
133
134     if (StringUtils.isEmpty(orchestrationTemplateEntity.getFileSuffix())) {
135       return;
136     }
137
138     Element candidateContentElement = getCandidateContentElement(candidateSubs);
139
140     VspDetails vspDetails = vspInfoDao.get(new VspDetails(itemId, version));
141     if (isEqual(orchestrationTemplateEntity,
142         getCandidateData(candidateElement, candidateContentElement))) {
143
144       if (isProcessedEntityValid(orchestrationTemplateEntity)) {
145         emptyStructureElementAndSub(context, elementContext, candidateElement.getElementId(),
146             ElementType.OrchestrationTemplateCandidate, candidateContentElement.getElementId(),
147             ElementType.OrchestrationTemplateCandidateContent);
148
149         populateOrchestrationTemplateStructure(orchestrationTemplateElement.getData(),
150             structureElementId, vspDetails, context, elementContext);
151       } else {
152         emptyStructureElementAndSub(context, elementContext,
153             orchestrationTemplateElement.getElementId(), ElementType.OrchestrationTemplate,
154             orchestrationTemplateValidationElement.getElementId(),
155             ElementType.OrchestrationTemplateValidationData);
156
157         populateCandidateValidationData(context, elementContext, candidateValidationElementId,
158             orchestrationTemplateEntity.getValidationData());
159       }
160     } else {
161       populateOrchestrationTemplateStructure(orchestrationTemplateElement.getData(),
162           structureElementId, vspDetails, context, elementContext);
163     }
164   }
165
166   private boolean isVspMissingAddedElements(String vspId, Version version) {
167     SessionContext context = createSessionContext();
168     ElementContext elementContext = new ElementContext(vspId, version.getId());
169
170     return zusammenAdaptor.listElementsByName(context, elementContext, null,
171         ElementType.OrchestrationTemplateCandidate.name()).stream()
172         .noneMatch(candidateSub -> ElementType.OrchestrationTemplateCandidateValidationData.name()
173             .equals(candidateSub.getInfo().getName()));
174   }
175
176   private boolean isEqual(OrchestrationTemplateEntity orchestrationTemplateEntity,
177                           OrchestrationTemplateCandidateData orchestrationTemplateCandidateData) {
178     return orchestrationTemplateEntity.getFileName()
179         .equals(orchestrationTemplateCandidateData.getFileName()) &&
180         orchestrationTemplateEntity.getFileSuffix()
181             .equals(orchestrationTemplateCandidateData.getFileSuffix());
182   }
183
184   private boolean isProcessedEntityValid(OrchestrationTemplateEntity orchestrationTemplateEntity) {
185     return !orchestrationTemplateEntity.getValidationData().contains(ErrorLevel.ERROR.name());
186   }
187
188   private void populateCandidateValidationData(SessionContext context,
189                                                ElementContext elementContext,
190                                                Id candidateValidationElementId,
191                                                String validationData) {
192     ZusammenElement candidateValidationElement =
193         buildStructuralElement(ElementType.OrchestrationTemplateCandidateValidationData,
194             Action.UPDATE);
195     candidateValidationElement.setElementId(candidateValidationElementId);
196     candidateValidationElement.setData(new ByteArrayInputStream(validationData.getBytes()));
197
198     zusammenAdaptor.saveElement(context, elementContext, candidateValidationElement,
199         "Healed Orchestration Template Candidate Validation data");
200   }
201
202   private void populateOrchestrationTemplateStructure(InputStream processedFile,
203                                                       Id structureElementId, VspDetails vspDetails,
204                                                       SessionContext context,
205                                                       ElementContext elementContext)
206       throws Exception {
207     byte[] byteData = FileUtils.toByteArray(processedFile);
208     FileContentHandler contentMap =
209         CommonUtil.validateAndUploadFileContent(OnboardingTypesEnum.ZIP, byteData);
210     OrchestrationTemplateCandidateData orchestrationTemplateEntityData =
211         new CandidateEntityBuilder(candidateService)
212             .buildCandidateEntityFromZip(vspDetails, byteData, contentMap, null);
213     String fileDataStructure = orchestrationTemplateEntityData.getFilesDataStructure();
214
215     ZusammenElement orchestrationTemplateStructure =
216         buildStructuralElement(ElementType.OrchestrationTemplateStructure, Action.UPDATE);
217     orchestrationTemplateStructure.setElementId(structureElementId);
218     orchestrationTemplateStructure.setData(new ByteArrayInputStream(fileDataStructure.getBytes()));
219
220     zusammenAdaptor.saveElement(context, elementContext, orchestrationTemplateStructure,
221         "Healed Orchestration Template Structure");
222   }
223
224   private Element getOrchestrationTemplateElement(SessionContext context,
225                                                   ElementContext elementContext) {
226     ElementInfo vspModelElement = zusammenAdaptor
227         .getElementInfoByName(context, elementContext, null, ElementType.VspModel.name())
228         .orElseThrow(() -> new CoreException(new ErrorCode.ErrorCodeBuilder()
229             .withMessage(MISSING_VSP_MODEL_ERROR).build()));
230
231     return getElement(context, elementContext, vspModelElement.getId(),
232         ElementType.OrchestrationTemplate, MISSING_ORCHESTRATION_TEMPLATE_ERROR);
233   }
234
235   private Element getOrchestrationTemplateValidationElement(
236       Collection<Element> orchestrationTemplateSubs) {
237     return orchestrationTemplateSubs.stream()
238         .filter(orchestrationTemplateSub -> ElementType.OrchestrationTemplateValidationData.name()
239             .equals(orchestrationTemplateSub.getInfo().getName()))
240         .findFirst()
241         .orElseThrow(() -> new CoreException(new ErrorCode.ErrorCodeBuilder()
242             .withMessage(MISSING_ORCHESTRATION_TEMPLATE_VALIDATE_DATA_ERROR).build()));
243
244   }
245
246   private Element getCandidateContentElement(Collection<Element> candidateSubs) {
247     return candidateSubs.stream()
248         .filter(candidateSub -> ElementType.OrchestrationTemplateCandidateContent.name()
249             .equals(candidateSub.getInfo().getName()))
250         .findFirst()
251         .orElseThrow(() -> new CoreException(new ErrorCode.ErrorCodeBuilder()
252             .withMessage(MISSING_ORCHESTRATION_TEMPLATE_CANDIDATE_CONTENT_ERROR).build()));
253   }
254
255   private Id createIfAbsentStructureElementId(Collection<Element> orchestrationTemplateSubs,
256                                               SessionContext context, ElementContext elementContext,
257                                               Element orchestrationTemplateElement) {
258     return orchestrationTemplateSubs.stream()
259         .filter(orchestrationTemplateSub -> ElementType.OrchestrationTemplateStructure.name()
260             .equals(orchestrationTemplateSub.getInfo().getName()))
261         .findFirst().map(Element::getElementId)
262         .orElse(addStructureSubElement(context, elementContext,
263             ElementType.OrchestrationTemplateStructure,
264             orchestrationTemplateElement.getElementId()));
265   }
266
267   private Id creatIfAbsentCandidateValidationElementId(Collection<Element> candidateSubs,
268                                                        SessionContext context, ElementContext
269                                                  elementContext, Element candidateElement) {
270     return candidateSubs.stream()
271         .filter(candidateSub -> ElementType.OrchestrationTemplateCandidateValidationData.name()
272             .equals(candidateSub.getInfo().getName()))
273         .findFirst().map(Element::getElementId)
274         .orElse(addStructureSubElement(context, elementContext,
275             ElementType.OrchestrationTemplateCandidateValidationData,
276             candidateElement.getElementId()));
277   }
278
279   private Element getElement(SessionContext context, ElementContext elementContext,
280                              Id parentElementId, ElementType elementType, String errorMessage) {
281     return zusammenAdaptor
282         .getElementByName(context, elementContext, parentElementId, elementType.name())
283         .orElseThrow(() -> new CoreException(
284             new ErrorCode.ErrorCodeBuilder().withMessage(errorMessage).build()));
285   }
286
287   private OrchestrationTemplateEntity getOrchestrationTemplateEntity(
288       Element orchestrationTemplateElement, Element validationDataElement) {
289     OrchestrationTemplateEntity orchestrationTemplateEntity = new OrchestrationTemplateEntity();
290
291     if (isNotEmpty(orchestrationTemplateElement.getData())) {
292       orchestrationTemplateEntity.setContentData(
293           ByteBuffer.wrap(FileUtils.toByteArray(orchestrationTemplateElement.getData())));
294     }
295     orchestrationTemplateEntity.setFileSuffix(
296         validationDataElement.getInfo().getProperty(InfoPropertyName.FILE_SUFFIX.getVal()));
297     orchestrationTemplateEntity.setFileName(
298         validationDataElement.getInfo().getProperty(InfoPropertyName.FILE_NAME.getVal()));
299     if (isNotEmpty(validationDataElement.getData())) {
300       orchestrationTemplateEntity
301           .setValidationData(new String(FileUtils.toByteArray(validationDataElement.getData())));
302     }
303     return orchestrationTemplateEntity;
304   }
305
306   private OrchestrationTemplateCandidateData getCandidateData(Element candidateElement,
307                                                               Element candidateContentElement) {
308     OrchestrationTemplateCandidateData candidateData = new OrchestrationTemplateCandidateData();
309     candidateData
310         .setFilesDataStructure(new String(FileUtils.toByteArray(candidateElement.getData())));
311     candidateData
312         .setContentData(ByteBuffer.wrap(FileUtils.toByteArray(candidateContentElement.getData())));
313     candidateData.setFileSuffix(
314         candidateContentElement.getInfo().getProperty(InfoPropertyName.FILE_SUFFIX.getVal()));
315     candidateData.setFileName(
316         candidateContentElement.getInfo().getProperty(InfoPropertyName.FILE_NAME.getVal()));
317     return candidateData;
318   }
319
320   private Id addStructureSubElement(SessionContext context, ElementContext elementContext,
321                                     ElementType elementType, Id parentElementId) {
322     ZusammenElement newElement = buildStructuralElement(elementType, Action.CREATE);
323
324     ZusammenElement parentElement = buildElement(parentElementId, Action.IGNORE);
325     parentElement.addSubElement(newElement);
326
327     return zusammenAdaptor.saveElement(context, elementContext, parentElement,
328         String.format("Add element %s under element id %s", elementType.name(), parentElementId))
329         .getSubElements().iterator().next().getElementId();
330   }
331
332   private void emptyStructureElementAndSub(SessionContext context, ElementContext elementContext,
333                                            Id elementId, ElementType elementType, Id subElementId,
334                                            ElementType subElementType) {
335     ZusammenElement subElement = buildStructuralElement(subElementType, Action.UPDATE);
336     subElement.setElementId(subElementId);
337     subElement.setData(new ByteArrayInputStream(EMPTY_DATA_BYTES));
338
339     ZusammenElement element = buildStructuralElement(elementType, Action.UPDATE);
340     element.setElementId(elementId);
341     element.setData(new ByteArrayInputStream(EMPTY_DATA_BYTES));
342     element.addSubElement(subElement);
343
344     zusammenAdaptor.saveElement(context, elementContext, element,
345         String.format("Empty element %s and its sub element %s", elementType.name(),
346             subElementType.name()));
347   }
348
349   public enum InfoPropertyName {
350     FILE_SUFFIX("fileSuffix"),
351     FILE_NAME("fileName");
352
353     private String val;
354
355     InfoPropertyName(String val) {
356       this.val = val;
357     }
358
359     private String getVal() {
360       return val;
361     }
362   }
363
364   private boolean isNotEmpty(InputStream elementData) {
365     byte[] byteElementData;
366     if (Objects.isNull(elementData)) {
367       return false;
368     }
369     try {
370       byteElementData = IOUtils.toByteArray(elementData);
371     } catch (IOException e) {
372       return true;
373     }
374     return !ArrayUtils.isEmpty(byteElementData);
375   }
376 }