2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2019 Nordix Foundation.
4 * Modification Copyright (C) 2021 Nokia.
5 * ================================================================================
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 * SPDX-License-Identifier: Apache-2.0
19 * ============LICENSE_END=========================================================
22 package org.openecomp.sdc.tosca.csar;
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.Map.Entry;
27 import java.util.Optional;
28 import org.apache.commons.lang.StringUtils;
29 import org.openecomp.sdc.common.errors.Messages;
32 * Processes a SOL004 Manifest.
34 public class SOL004ManifestOnboarding extends AbstractOnboardingManifest {
37 protected void processMetadata() {
38 Optional<String> currentLine = getCurrentLine();
39 //SOL004 #4.3.2: The manifest file shall start with the package metadata
40 if (!currentLine.isPresent() || !isMetadata(currentLine.get())) {
41 reportError(Messages.MANIFEST_START_METADATA);
42 continueToProcess = false;
45 while (continueToProcess) {
46 currentLine = readNextNonEmptyLine();
47 if (!currentLine.isPresent()) {
48 continueToProcess = validateMetadata();
51 final String metadataLine = currentLine.get();
52 final String metadataEntry = readEntryName(metadataLine).orElse(null);
53 if (!isMetadataEntry(metadataEntry)) {
54 if (metadata.size() < MAX_ALLOWED_MANIFEST_META_ENTRIES) {
55 reportError(Messages.MANIFEST_METADATA_INVALID_ENTRY1, metadataLine);
56 continueToProcess = false;
59 continueToProcess = validateMetadata();
62 final String metadataValue = readEntryValue(metadataLine).orElse(null);
63 addToMetadata(metadataEntry, metadataValue);
64 continueToProcess = isValid();
66 readNextNonEmptyLine();
70 protected void processBody() {
71 while (continueToProcess) {
72 final ManifestTokenType manifestTokenType = detectLineEntry().orElse(null);
73 if (manifestTokenType == null) {
74 getCurrentLine().ifPresent(line -> reportInvalidLine());
78 switch (manifestTokenType) {
82 case NON_MANO_ARTIFACT_SETS:
83 processNonManoArtifactEntry();
89 getCurrentLine().ifPresent(line -> reportInvalidLine());
90 continueToProcess = false;
97 * Processes the {@link ManifestTokenType#NON_MANO_ARTIFACT_SETS} entry.
99 private void processNonManoArtifactEntry() {
100 Optional<String> currentLine = readNextNonEmptyLine();
101 while (currentLine.isPresent()) {
102 final ManifestTokenType manifestTokenType = detectLineEntry().orElse(null);
103 if (manifestTokenType == ManifestTokenType.CMS_BEGIN) {
106 if (manifestTokenType != null) {
107 reportError(Messages.MANIFEST_INVALID_NON_MANO_KEY, manifestTokenType.getToken());
108 continueToProcess = false;
111 final String nonManoKey = readCurrentEntryName().orElse(null);
112 if (nonManoKey == null) {
113 reportError(Messages.MANIFEST_INVALID_NON_MANO_KEY, currentLine.get());
114 continueToProcess = false;
117 readNextNonEmptyLine();
118 final List<String> nonManoSourceList = readNonManoSourceList();
120 continueToProcess = false;
123 if (nonManoSourceList.isEmpty()) {
124 reportError(Messages.MANIFEST_EMPTY_NON_MANO_KEY, nonManoKey);
125 continueToProcess = false;
128 if (nonManoSources.get(nonManoKey) == null) {
129 nonManoSources.put(nonManoKey, nonManoSourceList);
131 nonManoSources.get(nonManoKey).addAll(nonManoSourceList);
133 currentLine = getCurrentLine();
138 * Processes {@link ManifestTokenType#SOURCE} entries in {@link ManifestTokenType#NON_MANO_ARTIFACT_SETS}.
140 * @return A list of sources paths
142 private List<String> readNonManoSourceList() {
143 final List<String> nonManoSourceList = new ArrayList<>();
144 while (getCurrentLine().isPresent()) {
145 final ManifestTokenType manifestTokenType = detectLineEntry().orElse(null);
146 if (manifestTokenType != ManifestTokenType.SOURCE) {
150 final String value = readCurrentEntryValue().orElse(null);
151 if (!StringUtils.isEmpty(value)) {
152 nonManoSourceList.add(value);
154 reportError(Messages.MANIFEST_EMPTY_NON_MANO_SOURCE);
158 readNextNonEmptyLine();
160 return nonManoSourceList;
164 * Reads a manifest CMS signature.
166 private void readCmsSignature() {
167 if (cmsSignature != null) {
168 reportError(Messages.MANIFEST_SIGNATURE_DUPLICATED);
169 continueToProcess = false;
172 final StringBuilder cmsSignatureBuilder = new StringBuilder();
174 cmsSignatureBuilder.append(currentLine).append("\n");
175 Optional<String> currentLine = readNextNonEmptyLine();
176 if(!getCurrentLine().isPresent()) {
179 while (currentLine.isPresent()) {
180 if (detectLineEntry().orElse(null) == ManifestTokenType.CMS_END) {
181 cmsSignatureBuilder.append(currentLine.get());
184 cmsSignatureBuilder.append(currentLine.get()).append("\n");
185 currentLine = readNextNonEmptyLine();
188 if (currentLine.isPresent()) {
189 cmsSignature = cmsSignatureBuilder.toString();
190 readNextNonEmptyLine();
193 if (getCurrentLine().isPresent()) {
194 reportError(Messages.MANIFEST_SIGNATURE_LAST_ENTRY);
195 continueToProcess = false;
200 * Detects the current line manifest token.
202 * @return the current line manifest token.
204 private Optional<ManifestTokenType> detectLineEntry() {
205 final Optional<String> currentLine = getCurrentLine();
206 if (currentLine.isPresent()) {
207 final String line = currentLine.get();
208 final String entry = readEntryName(line).orElse(null);
210 return ManifestTokenType.parse(line);
212 return ManifestTokenType.parse(entry);
215 return Optional.empty();
219 * Validates the manifest metadata content, reporting errors found.
221 * @return {@code true} if the metadata content is valid, {@code false} otherwise.
223 private boolean validateMetadata() {
224 if (metadata.isEmpty()) {
225 reportError(Messages.MANIFEST_NO_METADATA);
229 final Entry<String, String> firstManifestEntry = metadata.entrySet().iterator().next();
230 final ManifestTokenType firstManifestEntryTokenType =
231 ManifestTokenType.parse(firstManifestEntry.getKey()).orElse(null);
232 if (firstManifestEntryTokenType == null) {
233 reportError(Messages.MANIFEST_METADATA_INVALID_ENTRY1, firstManifestEntry.getKey());
236 for (final Entry<String, String> manifestEntry : metadata.entrySet()) {
237 final ManifestTokenType manifestEntryTokenType = ManifestTokenType.parse(manifestEntry.getKey())
239 if (manifestEntryTokenType == null) {
240 reportError(Messages.MANIFEST_METADATA_INVALID_ENTRY1, manifestEntry.getKey());
243 if ((firstManifestEntryTokenType.isMetadataVnfEntry() && !manifestEntryTokenType.isMetadataVnfEntry())
244 || (firstManifestEntryTokenType.isMetadataPnfEntry() && !manifestEntryTokenType.isMetadataPnfEntry())) {
245 reportError(Messages.MANIFEST_METADATA_UNEXPECTED_ENTRY_TYPE);
250 if (metadata.entrySet().size() != MAX_ALLOWED_MANIFEST_META_ENTRIES) {
251 reportError(Messages.MANIFEST_METADATA_DOES_NOT_MATCH_LIMIT, MAX_ALLOWED_MANIFEST_META_ENTRIES);
259 * Processes a Manifest {@link ManifestTokenType#SOURCE} entry.
261 private void processSource() {
262 final Optional<String> currentLine = getCurrentLine();
263 if (!currentLine.isPresent()) {
266 final ManifestTokenType manifestTokenType = detectLineEntry().orElse(null);
267 if (manifestTokenType != ManifestTokenType.SOURCE) {
271 final String sourceLine = currentLine.get();
272 final String sourcePath = readEntryValue(sourceLine).orElse(null);
274 if (sourcePath == null) {
275 reportError(Messages.MANIFEST_EXPECTED_SOURCE_PATH);
278 sources.add(sourcePath);
279 readNextNonEmptyLine();
280 readAlgorithmEntry(sourcePath);
281 readSignatureEntry(sourcePath);
285 * Processes entries {@link ManifestTokenType#ALGORITHM} and {@link ManifestTokenType#HASH} of a {@link
286 * ManifestTokenType#SOURCE} entry.
288 * @param sourcePath the source path related to the algorithm entry.
290 private void readAlgorithmEntry(final String sourcePath) {
291 Optional<String> currentLine = getCurrentLine();
292 if (!currentLine.isPresent()) {
295 final ManifestTokenType manifestTokenType = detectLineEntry().orElse(null);
296 if (manifestTokenType == ManifestTokenType.HASH) {
297 reportError(Messages.MANIFEST_EXPECTED_ALGORITHM_BEFORE_HASH);
298 continueToProcess = false;
301 if (manifestTokenType != ManifestTokenType.ALGORITHM) {
304 final String algorithmLine = currentLine.get();
305 final String algorithmType = readEntryValue(algorithmLine).orElse(null);
306 if (algorithmType == null) {
307 reportError(Messages.MANIFEST_EXPECTED_ALGORITHM_VALUE);
308 continueToProcess = false;
312 currentLine = readNextNonEmptyLine();
313 if (!currentLine.isPresent() || detectLineEntry().orElse(null) != ManifestTokenType.HASH) {
314 reportError(Messages.MANIFEST_EXPECTED_HASH_ENTRY);
315 continueToProcess = false;
319 final String hashLine = currentLine.get();
320 final String hash = readEntryValue(hashLine).orElse(null);
322 reportError(Messages.MANIFEST_EXPECTED_HASH_VALUE);
323 continueToProcess = false;
326 sourceAndChecksumMap.put(sourcePath, new AlgorithmDigest(algorithmType, hash));
327 readNextNonEmptyLine();
331 * Processes entries {@link ManifestTokenType#SIGNATURE} and {@link ManifestTokenType#CERTIFICATE} of a {@link
332 * ManifestTokenType#SOURCE} entry.
334 * @param sourcePath the source path related to the algorithm entry.
336 private void readSignatureEntry(final String sourcePath) {
337 Optional<String> currentLine = getCurrentLine();
338 if (!currentLine.isPresent()) {
341 final ManifestTokenType manifestTokenType = detectLineEntry().orElse(null);
342 if (manifestTokenType == ManifestTokenType.CERTIFICATE) {
343 reportError(Messages.MANIFEST_EXPECTED_SIGNATURE_BEFORE_CERTIFICATE);
344 continueToProcess = false;
347 if (manifestTokenType != ManifestTokenType.SIGNATURE) {
350 final String signatureLine = currentLine.get();
351 final String signatureFile = readEntryValue(signatureLine).orElse(null);
352 if (signatureFile == null) {
353 reportError(Messages.MANIFEST_EXPECTED_SIGNATURE_VALUE);
354 continueToProcess = false;
358 currentLine = readNextNonEmptyLine();
359 if (!currentLine.isPresent() || detectLineEntry().orElse(null) != ManifestTokenType.CERTIFICATE) {
360 sourceAndSignatureMap.put(sourcePath, new SignatureData(signatureFile, null));
364 final String certLine = currentLine.get();
365 final String certFile = readEntryValue(certLine).orElse(null);
366 if (certFile == null) {
367 reportError(Messages.MANIFEST_EXPECTED_CERTIFICATE_VALUE);
368 continueToProcess = false;
371 sourceAndSignatureMap.put(sourcePath, new SignatureData(signatureFile, certFile));
372 readNextNonEmptyLine();