2 * Copyright © 2016-2017 European Support Limited
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package org.openecomp.sdc.tosca.csar;
19 import com.google.common.collect.ImmutableList;
20 import com.google.common.collect.ImmutableMap;
21 import org.openecomp.sdc.common.errors.Messages;
22 import org.openecomp.sdc.logging.api.Logger;
23 import org.openecomp.sdc.logging.api.LoggerFactory;
25 import java.io.BufferedReader;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.InputStreamReader;
29 import java.nio.charset.StandardCharsets;
30 import java.util.ArrayList;
31 import java.util.Collections;
32 import java.util.HashMap;
33 import java.util.Iterator;
34 import java.util.List;
37 import static org.openecomp.core.validation.errors.ErrorMessagesFormatBuilder.getErrorWithParameters;
38 import static org.openecomp.sdc.tosca.csar.CSARConstants.METADATA_MF_ATTRIBUTE;
39 import static org.openecomp.sdc.tosca.csar.CSARConstants.NON_MANO_MF_ATTRIBUTE;
40 import static org.openecomp.sdc.tosca.csar.CSARConstants.SEPERATOR_MF_ATTRIBUTE;
41 import static org.openecomp.sdc.tosca.csar.CSARConstants.SOURCE_MF_ATTRIBUTE;
43 public class OnboardingManifest implements Manifest{
44 private static final Logger LOGGER = LoggerFactory.getLogger(OnboardingManifest.class);
45 private Map<String, String> metadata;
46 private List<String> sources;
47 private List<String> errors;
48 private Map<String, List<String>> nonManoSources;
50 private OnboardingManifest() {
51 errors = new ArrayList<>();
52 sources = new ArrayList<>();
53 metadata = new HashMap<>();
54 nonManoSources = new HashMap<>();
58 * This Method will parse manifest, extracting fields mandatory/non-mandatory,
59 * if error occurred it's recorded and will be used for deciding if manifest is valid
60 * @param is manifest file input stream
61 * @return Manifest object
63 public static Manifest parse(InputStream is) {
64 OnboardingManifest manifest = new OnboardingManifest();
66 ImmutableList<String> lines = manifest.readAllLines(is);
67 manifest.processManifest(lines);
68 } catch (IOException e){
69 LOGGER.error(e.getMessage(),e);
70 manifest.errors.add(Messages.MANIFEST_PARSER_INTERNAL.getErrorMessage());
75 private void processManifest(ImmutableList<String> lines) {
76 if(lines == null || lines.isEmpty()){
77 errors.add(Messages.MANIFEST_EMPTY.getErrorMessage());
80 Iterator<String> iterator = lines.iterator();
81 //SOL004 #4.3.2: The manifest file shall start with the package metadata
82 String line = iterator.next();
83 if(!line.trim().equals(METADATA_MF_ATTRIBUTE + SEPERATOR_MF_ATTRIBUTE)){
88 processMetadata(iterator);
90 if (errors.isEmpty()) {
91 if (metadata.isEmpty()) {
92 errors.add(Messages.MANIFEST_NO_METADATA.getErrorMessage());
94 if (sources.isEmpty()) {
95 errors.add(Messages.MANIFEST_NO_SOURCES.getErrorMessage());
100 private void processSourcesAndNonManoSources(Iterator<String> iterator, String prevLine) {
101 if(prevLine.isEmpty()){
102 if(iterator.hasNext()){
103 processSourcesAndNonManoSources(iterator, iterator.next());
105 }else if(prevLine.startsWith(SOURCE_MF_ATTRIBUTE+SEPERATOR_MF_ATTRIBUTE)){
106 processSource(iterator, prevLine);
107 } else if(prevLine.startsWith(NON_MANO_MF_ATTRIBUTE+SEPERATOR_MF_ATTRIBUTE)){
108 //non mano should be the last bit in manifest file,
109 // all sources after non mano will be placed to the last non mano
110 // key, if any other structure met error reported
111 processNonManoInputs(iterator, iterator.next());
113 reportError(prevLine);
117 private void processSource(Iterator<String> iterator, String prevLine) {
118 String value = prevLine.substring((SOURCE_MF_ATTRIBUTE + SEPERATOR_MF_ATTRIBUTE).length()).trim();
120 if(iterator.hasNext()) {
121 processSourcesAndNonManoSources(iterator, iterator.next());
125 private void processMetadata(Iterator<String> iterator) {
126 if(!iterator.hasNext()){
129 String line = iterator.next();
131 processMetadata(iterator);
134 String[] metaSplit = line.split(SEPERATOR_MF_ATTRIBUTE);
135 if (metaSplit.length < 2){
139 if (!metaSplit[0].equals(SOURCE_MF_ATTRIBUTE) && !metaSplit[0].equals(NON_MANO_MF_ATTRIBUTE)){
140 String value = line.substring((metaSplit[0] + SEPERATOR_MF_ATTRIBUTE).length()).trim();
141 metadata.put(metaSplit[0].trim(),value.trim());
142 processMetadata(iterator);
145 processSourcesAndNonManoSources(iterator, line);
149 private void processNonManoInputs(Iterator<String> iterator, String prevLine) {
150 //Non Mano input should always start with key, if no key available report an error
151 if(prevLine.trim().equals(SOURCE_MF_ATTRIBUTE + SEPERATOR_MF_ATTRIBUTE)){
152 reportError(prevLine);
155 //key should contain : separator
156 if(!prevLine.contains(SEPERATOR_MF_ATTRIBUTE)){
157 reportError(prevLine);
160 //key shouldn't have value in the same line
161 String[] metaSplit = prevLine.trim().split(SEPERATOR_MF_ATTRIBUTE);
162 if (metaSplit.length > 1){
163 reportError(prevLine);
166 int index = prevLine.indexOf(':');
168 prevLine = prevLine.substring(0, index);
170 processNonManoSource(iterator, prevLine, new ArrayList<>());
174 private void processNonManoSource(Iterator<String> iterator, String key, List<String> sources) {
175 if(!iterator.hasNext()){
178 String line = iterator.next();
180 processNonManoSource(iterator, key, sources);
181 }else if(line.trim().startsWith(SOURCE_MF_ATTRIBUTE + SEPERATOR_MF_ATTRIBUTE)){
182 String value = line.replace(SOURCE_MF_ATTRIBUTE + SEPERATOR_MF_ATTRIBUTE, "").trim();
184 processNonManoSource(iterator, key, sources);
186 processNonManoInputs(iterator, line);
188 nonManoSources.put(key.trim(), sources);
191 private void reportError(String line) {
192 errors.add(getErrorWithParameters(Messages.MANIFEST_INVALID_LINE.getErrorMessage(), line));
195 private ImmutableList<String> readAllLines(InputStream is) throws IOException {
197 throw new IOException("Input Stream cannot be null!");
199 ImmutableList.Builder<String> builder = ImmutableList.<String> builder();
200 try (BufferedReader bufferedReader = new BufferedReader(
201 new InputStreamReader(is, StandardCharsets.UTF_8.newDecoder()))) {
202 bufferedReader.lines().forEach(builder::add);
204 return builder.build();
207 public Map<String, String> getMetadata() {
209 return Collections.emptyMap();
211 return ImmutableMap.copyOf(metadata);
214 public List<String> getSources() {
216 return Collections.emptyList();
218 return ImmutableList.copyOf(sources);
221 public List<String> getErrors() {
222 return ImmutableList.copyOf(errors);
225 public boolean isValid() {
226 return errors.isEmpty();
229 public Map<String, List<String>> getNonManoSources() {
231 return Collections.emptyMap();
233 return ImmutableMap.copyOf(nonManoSources);