2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6 * Copyright © 2017 European Software Marketing Ltd.
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
21 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
23 package org.onap.aai.babel.csar.extractor;
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.Enumeration;
29 import java.util.HashMap;
30 import java.util.HashSet;
31 import java.util.LinkedHashMap;
32 import java.util.List;
34 import java.util.regex.Pattern;
35 import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
36 import org.apache.commons.compress.archivers.zip.ZipFile;
37 import org.apache.commons.compress.utils.SeekableInMemoryByteChannel;
38 import org.apache.commons.io.IOUtils;
39 import org.apache.commons.lang3.StringUtils;
40 import org.onap.aai.babel.logging.ApplicationMsgs;
41 import org.onap.aai.babel.xml.generator.ModelGenerator;
42 import org.onap.aai.cl.api.Logger;
43 import org.onap.aai.cl.eelf.LoggerFactory;
44 import org.openecomp.sdc.generator.data.Artifact;
45 import org.yaml.snakeyaml.Yaml;
48 * The purpose of this class is to process a .csar file in the form of a byte array and extract yaml files from it.
50 * A .csar file is a compressed archive like a zip file and this class will treat the byte array as it if were a zip
53 public class YamlExtractor {
54 private static Logger logger = LoggerFactory.getInstance().getLogger(YamlExtractor.class);
56 private static final String TYPE = "type";
57 private static final Pattern YAMLFILE_EXTENSION_REGEX = Pattern.compile("(?i).*\\.ya?ml$");
58 private static final Set<String> INVALID_TYPES = new HashSet<>();
61 Collections.addAll(INVALID_TYPES, "CP", "VL", "VFC", "VFCMT", "ABSTRACT");
67 private YamlExtractor() {
68 throw new IllegalAccessError("Utility class");
72 * This method is responsible for filtering the contents of the supplied archive and returning a collection of
73 * {@link Artifact}s that represent the yml files that have been found in the archive.<br>
75 * If the archive contains no yml files it will return an empty list.<br>
77 * @param archive the zip file in the form of a byte array containing one or more yml files
78 * @param name the name of the archive file
79 * @param version the version of the archive file
80 * @return List<Artifact> collection of yml files found in the archive
81 * @throws InvalidArchiveException if an error occurs trying to extract the yml files from the archive, if the
82 * archive is not a zip file or there are no yml files
84 public static List<Artifact> extract(byte[] archive, String name, String version) throws InvalidArchiveException {
85 validateRequest(archive, name, version);
87 logger.info(ApplicationMsgs.DISTRIBUTION_EVENT, "Extracting CSAR archive: " + name);
89 List<Artifact> ymlFiles = new ArrayList<>();
90 try (SeekableInMemoryByteChannel inMemoryByteChannel = new SeekableInMemoryByteChannel(archive);
91 ZipFile zipFile = new ZipFile(inMemoryByteChannel)) {
92 for (Enumeration<ZipArchiveEntry> enumeration = zipFile.getEntries(); enumeration.hasMoreElements();) {
93 ZipArchiveEntry entry = enumeration.nextElement();
94 if (fileShouldBeExtracted(zipFile, entry)) {
95 ymlFiles.add(ModelGenerator.createArtifact(IOUtils.toByteArray(zipFile.getInputStream(entry)),
96 entry.getName(), version));
99 if (ymlFiles.isEmpty()) {
100 throw new InvalidArchiveException("No valid yml files were found in the csar file.");
102 } catch (IOException e) {
103 throw new InvalidArchiveException(
104 "An error occurred trying to create a ZipFile. Is the content being converted really a csar file?",
108 logger.debug(ApplicationMsgs.DISTRIBUTION_EVENT, ymlFiles.size() + " YAML files extracted.");
113 private static void validateRequest(byte[] archive, String name, String version) throws InvalidArchiveException {
114 if (archive == null || archive.length == 0) {
115 throw new InvalidArchiveException("An archive must be supplied for processing.");
116 } else if (StringUtils.isBlank(name)) {
117 throw new InvalidArchiveException("The name of the archive must be supplied for processing.");
118 } else if (StringUtils.isBlank(version)) {
119 throw new InvalidArchiveException("The version must be supplied for processing.");
123 @SuppressWarnings("unchecked")
124 private static boolean fileShouldBeExtracted(ZipFile zipFile, ZipArchiveEntry entry) throws IOException {
125 logger.debug(ApplicationMsgs.DISTRIBUTION_EVENT, "Checking if " + entry.getName() + " should be extracted...");
127 boolean extractFile = false;
128 if (YAMLFILE_EXTENSION_REGEX.matcher(entry.getName()).matches()) {
130 Yaml yamlParser = new Yaml();
131 HashMap<String, Object> yaml =
132 (LinkedHashMap<String, Object>) yamlParser.load(zipFile.getInputStream(entry));
133 HashMap<String, Object> metadata = (LinkedHashMap<String, Object>) yaml.get("metadata");
135 extractFile = metadata != null && metadata.containsKey(TYPE)
136 && !INVALID_TYPES.contains(metadata.get(TYPE).toString().toUpperCase())
137 && !metadata.get(TYPE).toString().isEmpty();
138 } catch (Exception e) {
139 logger.error(ApplicationMsgs.DISTRIBUTION_EVENT,
140 "Unable to verify " + entry.getName() + " contains a valid resource type: " + e.getMessage());
144 logger.debug(ApplicationMsgs.DISTRIBUTION_EVENT, "Keeping file: " + entry.getName() + "? : " + extractFile);