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