bb0b07a63fddff34e18f637c23290a28ca5a8c0e
[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                     continueToProcess = false;
84                     break;
85                 case SOURCE:
86                     processSource();
87                     break;
88                 default:
89                     getCurrentLine().ifPresent(line -> reportInvalidLine());
90                     continueToProcess = false;
91                     break;
92             }
93         }
94     }
95
96     /**
97      * Processes the {@link ManifestTokenType#NON_MANO_ARTIFACT_SETS} entry.
98      */
99     private void processNonManoArtifactEntry() {
100         Optional<String> currentLine = readNextNonEmptyLine();
101         while (currentLine.isPresent()) {
102             final ManifestTokenType manifestTokenType = detectLineEntry().orElse(null);
103             if (manifestTokenType != null) {
104                 reportError(Messages.MANIFEST_INVALID_NON_MANO_KEY, manifestTokenType.getToken());
105                 continueToProcess = false;
106                 return;
107             }
108             final String nonManoKey = readCurrentEntryName().orElse(null);
109             if (nonManoKey == null) {
110                 reportError(Messages.MANIFEST_INVALID_NON_MANO_KEY, currentLine.get());
111                 continueToProcess = false;
112                 return;
113             }
114             readNextNonEmptyLine();
115             final List<String> nonManoSourceList = readNonManoSourceList();
116             if (!isValid()) {
117                 continueToProcess = false;
118                 return;
119             }
120             if (nonManoSourceList.isEmpty()) {
121                 reportError(Messages.MANIFEST_EMPTY_NON_MANO_KEY, nonManoKey);
122                 continueToProcess = false;
123                 return;
124             }
125             if (nonManoSources.get(nonManoKey) == null) {
126                 nonManoSources.put(nonManoKey, nonManoSourceList);
127             } else {
128                 nonManoSources.get(nonManoKey).addAll(nonManoSourceList);
129             }
130             currentLine = getCurrentLine();
131         }
132     }
133
134     /**
135      * Processes {@link ManifestTokenType#SOURCE} entries in {@link ManifestTokenType#NON_MANO_ARTIFACT_SETS}.
136      *
137      * @return A list of sources paths
138      */
139     private List<String> readNonManoSourceList() {
140         final List<String> nonManoSourceList = new ArrayList<>();
141         while (getCurrentLine().isPresent()) {
142             final ManifestTokenType manifestTokenType = detectLineEntry().orElse(null);
143             if (manifestTokenType != ManifestTokenType.SOURCE) {
144                 break;
145             }
146
147             final String value = readCurrentEntryValue().orElse(null);
148             if (!StringUtils.isEmpty(value)) {
149                 nonManoSourceList.add(value);
150             } else {
151                 reportError(Messages.MANIFEST_EMPTY_NON_MANO_SOURCE);
152                 break;
153             }
154
155             readNextNonEmptyLine();
156         }
157         return nonManoSourceList;
158     }
159
160     /**
161      * Reads a manifest CMS signature.
162      */
163     private void readCmsSignature() {
164         if (cmsSignature != null) {
165             reportError(Messages.MANIFEST_DUPLICATED_CMS_SIGNATURE);
166             continueToProcess = false;
167             return;
168         }
169         Optional<String> currentLine = readNextNonEmptyLine();
170         if(!getCurrentLine().isPresent()) {
171             return;
172         }
173         StringBuilder stringBuilder = new StringBuilder();
174         while (currentLine.isPresent() && detectLineEntry().orElse(null) != ManifestTokenType.CMS_END) {
175             stringBuilder.append(currentLine.get());
176             stringBuilder.append("\n");
177             currentLine = readNextNonEmptyLine();
178         }
179
180         if (currentLine.isPresent()) {
181             cmsSignature = stringBuilder.toString();
182             readNextNonEmptyLine();
183         }
184     }
185
186     /**
187      * Detects the current line manifest token.
188      *
189      * @return the current line manifest token.
190      */
191     private Optional<ManifestTokenType> detectLineEntry() {
192         final Optional<String> currentLine = getCurrentLine();
193         if (currentLine.isPresent()) {
194             final String line = currentLine.get();
195             final String entry = readEntryName(line).orElse(null);
196             if (entry == null) {
197                 return ManifestTokenType.parse(line);
198             } else {
199                 return ManifestTokenType.parse(entry);
200             }
201         }
202         return Optional.empty();
203     }
204
205     /**
206      * Validates the manifest metadata content, reporting errors found.
207      *
208      * @return {@code true} if the metadata content is valid, {@code false} otherwise.
209      */
210     private boolean validateMetadata() {
211         if (metadata.isEmpty()) {
212             reportError(Messages.MANIFEST_NO_METADATA);
213             return false;
214         }
215
216         final Entry<String, String> firstManifestEntry = metadata.entrySet().iterator().next();
217         final ManifestTokenType firstManifestEntryTokenType =
218             ManifestTokenType.parse(firstManifestEntry.getKey()).orElse(null);
219         if (firstManifestEntryTokenType == null) {
220             reportError(Messages.MANIFEST_METADATA_INVALID_ENTRY1, firstManifestEntry.getKey());
221             return false;
222         }
223         for (final Entry<String, String> manifestEntry : metadata.entrySet()) {
224             final ManifestTokenType manifestEntryTokenType = ManifestTokenType.parse(manifestEntry.getKey())
225                 .orElse(null);
226             if (manifestEntryTokenType == null) {
227                 reportError(Messages.MANIFEST_METADATA_INVALID_ENTRY1, manifestEntry.getKey());
228                 return false;
229             }
230             if ((firstManifestEntryTokenType.isMetadataVnfEntry() && !manifestEntryTokenType.isMetadataVnfEntry())
231                 || (firstManifestEntryTokenType.isMetadataPnfEntry() && !manifestEntryTokenType.isMetadataPnfEntry())) {
232                 reportError(Messages.MANIFEST_METADATA_UNEXPECTED_ENTRY_TYPE);
233                 return false;
234             }
235         }
236
237         if (metadata.entrySet().size() != MAX_ALLOWED_MANIFEST_META_ENTRIES) {
238             reportError(Messages.MANIFEST_METADATA_DOES_NOT_MATCH_LIMIT, MAX_ALLOWED_MANIFEST_META_ENTRIES);
239             return false;
240         }
241
242         return true;
243     }
244
245     /**
246      * Processes a Manifest {@link ManifestTokenType#SOURCE} entry.
247      */
248     private void processSource() {
249         final Optional<String> currentLine = getCurrentLine();
250         if (!currentLine.isPresent()) {
251             return;
252         }
253         final ManifestTokenType manifestTokenType = detectLineEntry().orElse(null);
254         if (manifestTokenType != ManifestTokenType.SOURCE) {
255             return;
256         }
257
258         final String sourceLine = currentLine.get();
259         final String sourcePath = readEntryValue(sourceLine).orElse(null);
260
261         if (sourcePath == null) {
262             reportError(Messages.MANIFEST_EXPECTED_SOURCE_PATH);
263             return;
264         }
265         sources.add(sourcePath);
266         readAlgorithmEntry(sourcePath);
267     }
268
269     /**
270      * Processes entries  {@link ManifestTokenType#ALGORITHM} and {@link ManifestTokenType#HASH} of a {@link
271      * ManifestTokenType#SOURCE} entry.
272      *
273      * @param sourcePath the source path related to the algorithm entry.
274      */
275     private void readAlgorithmEntry(final String sourcePath) {
276         Optional<String> currentLine = readNextNonEmptyLine();
277         if (!currentLine.isPresent()) {
278             return;
279         }
280         final ManifestTokenType manifestTokenType = detectLineEntry().orElse(null);
281         if (manifestTokenType == ManifestTokenType.HASH) {
282             reportError(Messages.MANIFEST_EXPECTED_ALGORITHM_BEFORE_HASH);
283             continueToProcess = false;
284             return;
285         }
286         if (manifestTokenType != ManifestTokenType.ALGORITHM) {
287             return;
288         }
289         final String algorithmLine = currentLine.get();
290         final String algorithmType = readEntryValue(algorithmLine).orElse(null);
291         if (algorithmType == null) {
292             reportError(Messages.MANIFEST_EXPECTED_ALGORITHM_VALUE);
293             continueToProcess = false;
294             return;
295         }
296
297         currentLine = readNextNonEmptyLine();
298         if (!currentLine.isPresent() || detectLineEntry().orElse(null) != ManifestTokenType.HASH) {
299             reportError(Messages.MANIFEST_EXPECTED_HASH_ENTRY);
300             continueToProcess = false;
301             return;
302         }
303
304         final String hashLine = currentLine.get();
305         final String hash = readEntryValue(hashLine).orElse(null);
306         if (hash == null) {
307             reportError(Messages.MANIFEST_EXPECTED_HASH_VALUE);
308             continueToProcess = false;
309             return;
310         }
311         sourceAndChecksumMap.put(sourcePath, new AlgorithmDigest(algorithmType, hash));
312         readNextNonEmptyLine();
313     }
314
315 }