8e67d7b5de06c163b04a8b5c66a54a64601ec138
[sdc.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2019 Nordix Foundation.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.openecomp.sdc.tosca.csar;
22
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.Map.Entry;
26 import java.util.Optional;
27 import org.apache.commons.lang.StringUtils;
28 import org.openecomp.sdc.common.errors.Messages;
29
30 /**
31  * Processes a SOL004 Manifest.
32  */
33 public class SOL004ManifestOnboarding extends AbstractOnboardingManifest {
34
35     @Override
36     protected void processMetadata() {
37         Optional<String> currentLine = getCurrentLine();
38         //SOL004 #4.3.2: The manifest file shall start with the package metadata
39         if (!currentLine.isPresent() || !isMetadata(currentLine.get())) {
40             reportError(Messages.MANIFEST_START_METADATA);
41             continueToProcess = false;
42             return;
43         }
44         while (continueToProcess) {
45             currentLine = readNextNonEmptyLine();
46             if (!currentLine.isPresent()) {
47                 continueToProcess = validateMetadata();
48                 return;
49             }
50             final String metadataLine = currentLine.get();
51             final String metadataEntry = readEntryName(metadataLine).orElse(null);
52             if (!isMetadataEntry(metadataEntry)) {
53                 if (metadata.size() < MAX_ALLOWED_MANIFEST_META_ENTRIES) {
54                     reportError(Messages.MANIFEST_METADATA_INVALID_ENTRY1, metadataLine);
55                     continueToProcess = false;
56                     return;
57                 }
58                 continueToProcess = validateMetadata();
59                 return;
60             }
61             final String metadataValue = readEntryValue(metadataLine).orElse(null);
62             addToMetadata(metadataEntry, metadataValue);
63             continueToProcess = isValid();
64         }
65         readNextNonEmptyLine();
66     }
67
68     @Override
69     protected void processBody() {
70         while (continueToProcess) {
71             final ManifestTokenType manifestTokenType = detectLineEntry().orElse(null);
72             if (manifestTokenType == null) {
73                 getCurrentLine().ifPresent(line -> reportInvalidLine());
74                 break;
75             }
76
77             switch (manifestTokenType) {
78                 case CMS_BEGIN:
79                     readCmsSignature();
80                     break;
81                 case NON_MANO_ARTIFACT_SETS:
82                     processNonManoArtifactEntry();
83                     break;
84                 case SOURCE:
85                     processSource();
86                     break;
87                 default:
88                     getCurrentLine().ifPresent(line -> reportInvalidLine());
89                     continueToProcess = false;
90                     break;
91             }
92         }
93     }
94
95     /**
96      * Processes the {@link ManifestTokenType#NON_MANO_ARTIFACT_SETS} entry.
97      */
98     private void processNonManoArtifactEntry() {
99         Optional<String> currentLine = readNextNonEmptyLine();
100         while (currentLine.isPresent()) {
101             final ManifestTokenType manifestTokenType = detectLineEntry().orElse(null);
102             if (manifestTokenType == ManifestTokenType.CMS_BEGIN) {
103                 return;
104             }
105             if (manifestTokenType != null) {
106                 reportError(Messages.MANIFEST_INVALID_NON_MANO_KEY, manifestTokenType.getToken());
107                 continueToProcess = false;
108                 return;
109             }
110             final String nonManoKey = readCurrentEntryName().orElse(null);
111             if (nonManoKey == null) {
112                 reportError(Messages.MANIFEST_INVALID_NON_MANO_KEY, currentLine.get());
113                 continueToProcess = false;
114                 return;
115             }
116             readNextNonEmptyLine();
117             final List<String> nonManoSourceList = readNonManoSourceList();
118             if (!isValid()) {
119                 continueToProcess = false;
120                 return;
121             }
122             if (nonManoSourceList.isEmpty()) {
123                 reportError(Messages.MANIFEST_EMPTY_NON_MANO_KEY, nonManoKey);
124                 continueToProcess = false;
125                 return;
126             }
127             if (nonManoSources.get(nonManoKey) == null) {
128                 nonManoSources.put(nonManoKey, nonManoSourceList);
129             } else {
130                 nonManoSources.get(nonManoKey).addAll(nonManoSourceList);
131             }
132             currentLine = getCurrentLine();
133         }
134     }
135
136     /**
137      * Processes {@link ManifestTokenType#SOURCE} entries in {@link ManifestTokenType#NON_MANO_ARTIFACT_SETS}.
138      *
139      * @return A list of sources paths
140      */
141     private List<String> readNonManoSourceList() {
142         final List<String> nonManoSourceList = new ArrayList<>();
143         while (getCurrentLine().isPresent()) {
144             final ManifestTokenType manifestTokenType = detectLineEntry().orElse(null);
145             if (manifestTokenType != ManifestTokenType.SOURCE) {
146                 break;
147             }
148
149             final String value = readCurrentEntryValue().orElse(null);
150             if (!StringUtils.isEmpty(value)) {
151                 nonManoSourceList.add(value);
152             } else {
153                 reportError(Messages.MANIFEST_EMPTY_NON_MANO_SOURCE);
154                 break;
155             }
156
157             readNextNonEmptyLine();
158         }
159         return nonManoSourceList;
160     }
161
162     /**
163      * Reads a manifest CMS signature.
164      */
165     private void readCmsSignature() {
166         if (cmsSignature != null) {
167             reportError(Messages.MANIFEST_SIGNATURE_DUPLICATED);
168             continueToProcess = false;
169             return;
170         }
171         final StringBuilder cmsSignatureBuilder = new StringBuilder();
172
173         cmsSignatureBuilder.append(currentLine).append("\n");
174         Optional<String> currentLine = readNextNonEmptyLine();
175         if(!getCurrentLine().isPresent()) {
176             return;
177         }
178         while (currentLine.isPresent()) {
179             if (detectLineEntry().orElse(null) == ManifestTokenType.CMS_END) {
180                 cmsSignatureBuilder.append(currentLine.get());
181                 break;
182             }
183             cmsSignatureBuilder.append(currentLine.get()).append("\n");
184             currentLine = readNextNonEmptyLine();
185         }
186
187         if (currentLine.isPresent()) {
188             cmsSignature = cmsSignatureBuilder.toString();
189             readNextNonEmptyLine();
190         }
191
192         if (getCurrentLine().isPresent()) {
193             reportError(Messages.MANIFEST_SIGNATURE_LAST_ENTRY);
194             continueToProcess = false;
195         }
196     }
197
198     /**
199      * Detects the current line manifest token.
200      *
201      * @return the current line manifest token.
202      */
203     private Optional<ManifestTokenType> detectLineEntry() {
204         final Optional<String> currentLine = getCurrentLine();
205         if (currentLine.isPresent()) {
206             final String line = currentLine.get();
207             final String entry = readEntryName(line).orElse(null);
208             if (entry == null) {
209                 return ManifestTokenType.parse(line);
210             } else {
211                 return ManifestTokenType.parse(entry);
212             }
213         }
214         return Optional.empty();
215     }
216
217     /**
218      * Validates the manifest metadata content, reporting errors found.
219      *
220      * @return {@code true} if the metadata content is valid, {@code false} otherwise.
221      */
222     private boolean validateMetadata() {
223         if (metadata.isEmpty()) {
224             reportError(Messages.MANIFEST_NO_METADATA);
225             return false;
226         }
227
228         final Entry<String, String> firstManifestEntry = metadata.entrySet().iterator().next();
229         final ManifestTokenType firstManifestEntryTokenType =
230             ManifestTokenType.parse(firstManifestEntry.getKey()).orElse(null);
231         if (firstManifestEntryTokenType == null) {
232             reportError(Messages.MANIFEST_METADATA_INVALID_ENTRY1, firstManifestEntry.getKey());
233             return false;
234         }
235         for (final Entry<String, String> manifestEntry : metadata.entrySet()) {
236             final ManifestTokenType manifestEntryTokenType = ManifestTokenType.parse(manifestEntry.getKey())
237                 .orElse(null);
238             if (manifestEntryTokenType == null) {
239                 reportError(Messages.MANIFEST_METADATA_INVALID_ENTRY1, manifestEntry.getKey());
240                 return false;
241             }
242             if ((firstManifestEntryTokenType.isMetadataVnfEntry() && !manifestEntryTokenType.isMetadataVnfEntry())
243                 || (firstManifestEntryTokenType.isMetadataPnfEntry() && !manifestEntryTokenType.isMetadataPnfEntry())) {
244                 reportError(Messages.MANIFEST_METADATA_UNEXPECTED_ENTRY_TYPE);
245                 return false;
246             }
247         }
248
249         if (metadata.entrySet().size() != MAX_ALLOWED_MANIFEST_META_ENTRIES) {
250             reportError(Messages.MANIFEST_METADATA_DOES_NOT_MATCH_LIMIT, MAX_ALLOWED_MANIFEST_META_ENTRIES);
251             return false;
252         }
253
254         return true;
255     }
256
257     /**
258      * Processes a Manifest {@link ManifestTokenType#SOURCE} entry.
259      */
260     private void processSource() {
261         final Optional<String> currentLine = getCurrentLine();
262         if (!currentLine.isPresent()) {
263             return;
264         }
265         final ManifestTokenType manifestTokenType = detectLineEntry().orElse(null);
266         if (manifestTokenType != ManifestTokenType.SOURCE) {
267             return;
268         }
269
270         final String sourceLine = currentLine.get();
271         final String sourcePath = readEntryValue(sourceLine).orElse(null);
272
273         if (sourcePath == null) {
274             reportError(Messages.MANIFEST_EXPECTED_SOURCE_PATH);
275             return;
276         }
277         sources.add(sourcePath);
278         readAlgorithmEntry(sourcePath);
279     }
280
281     /**
282      * Processes entries  {@link ManifestTokenType#ALGORITHM} and {@link ManifestTokenType#HASH} of a {@link
283      * ManifestTokenType#SOURCE} entry.
284      *
285      * @param sourcePath the source path related to the algorithm entry.
286      */
287     private void readAlgorithmEntry(final String sourcePath) {
288         Optional<String> currentLine = readNextNonEmptyLine();
289         if (!currentLine.isPresent()) {
290             return;
291         }
292         final ManifestTokenType manifestTokenType = detectLineEntry().orElse(null);
293         if (manifestTokenType == ManifestTokenType.HASH) {
294             reportError(Messages.MANIFEST_EXPECTED_ALGORITHM_BEFORE_HASH);
295             continueToProcess = false;
296             return;
297         }
298         if (manifestTokenType != ManifestTokenType.ALGORITHM) {
299             return;
300         }
301         final String algorithmLine = currentLine.get();
302         final String algorithmType = readEntryValue(algorithmLine).orElse(null);
303         if (algorithmType == null) {
304             reportError(Messages.MANIFEST_EXPECTED_ALGORITHM_VALUE);
305             continueToProcess = false;
306             return;
307         }
308
309         currentLine = readNextNonEmptyLine();
310         if (!currentLine.isPresent() || detectLineEntry().orElse(null) != ManifestTokenType.HASH) {
311             reportError(Messages.MANIFEST_EXPECTED_HASH_ENTRY);
312             continueToProcess = false;
313             return;
314         }
315
316         final String hashLine = currentLine.get();
317         final String hash = readEntryValue(hashLine).orElse(null);
318         if (hash == null) {
319             reportError(Messages.MANIFEST_EXPECTED_HASH_VALUE);
320             continueToProcess = false;
321             return;
322         }
323         sourceAndChecksumMap.put(sourcePath, new AlgorithmDigest(algorithmType, hash));
324         readNextNonEmptyLine();
325     }
326
327 }