c5b7c9d933b3618014fccc325f5f879fb68ef692
[vfc/nfvo/wfengine.git] / winery / org.eclipse.winery.model.csar.toscametafile / src / main / java / org / eclipse / winery / model / csar / toscametafile / TOSCAMetaFileParser.java
1 /*******************************************************************************
2  * Copyright (c) 2013 Rene Trefft.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * and the Apache License 2.0 which both accompany this distribution,
6  * and are available at http://www.eclipse.org/legal/epl-v10.html
7  * and http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Contributors:
10  *    Rene Trefft - initial API and implementation and/or initial documentation
11  *******************************************************************************/
12 package org.eclipse.winery.model.csar.toscametafile;
13
14 import java.io.FileNotFoundException;
15 import java.io.FileReader;
16 import java.io.IOException;
17 import java.nio.file.Path;
18 import java.util.List;
19 import java.util.Map;
20
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23
24 import com.springsource.util.parser.manifest.ManifestContents;
25 import com.springsource.util.parser.manifest.ManifestParser;
26 import com.springsource.util.parser.manifest.ManifestProblem;
27 import com.springsource.util.parser.manifest.RecoveringManifestParser;
28
29 /**
30  * Parses and validates a TOSCA meta file.<br />
31  * <br />
32  * Copyright 2013 IAAS University of Stuttgart <br />
33  * <br />
34  * 
35  * @author Rene Trefft - rene.trefft@developers.opentosca.org
36  * 
37  */
38 public class TOSCAMetaFileParser {
39         
40         final private static Logger LOG = LoggerFactory.getLogger(TOSCAMetaFileParser.class);
41         
42         
43         /**
44          * Parses and validates the <code>toscaMetaFile</code>.<br />
45          * <br />
46          * 
47          * @param toscaMetaFile to process
48          * @return <code>TOSCAMetaFile</code> that gives access to the content of
49          *         the TOSCA meta file. If the given file doesn't exist or is
50          *         invalid <code>null</code>.
51          */
52         public TOSCAMetaFile parse(Path toscaMetaFile) {
53                 
54                 // counts the errors during parsing
55                 int numErrors = 0;
56                 
57                 FileReader reader = null;
58                 ManifestParser parser = null;
59                 ManifestContents manifestContent = null;
60                 TOSCAMetaFile toscaMetaFileContent = null;
61                 
62                 try {
63                         
64                         parser = new RecoveringManifestParser();
65                         reader = new FileReader(toscaMetaFile.toFile());
66                         TOSCAMetaFileParser.LOG.debug("Parsing TOSCA meta file \"{}\"...", toscaMetaFile.getFileName().toString());
67                         manifestContent = parser.parse(reader);
68                         reader.close();
69                         
70                         for (ManifestProblem problem : parser.getProblems()) {
71                                 this.logManifestProblem(problem);
72                                 numErrors++;
73                         }
74                         
75                         numErrors += this.validateBlock0(manifestContent);
76                         numErrors += this.validateFileBlocks(manifestContent);
77                         
78                         if (numErrors == 0) {
79                                 TOSCAMetaFileParser.LOG.debug("Parsing TOSCA meta file \"{}\" completed without errors. TOSCA meta file is valid.", toscaMetaFile.getFileName().toString());
80                                 toscaMetaFileContent = new TOSCAMetaFile(manifestContent);
81                         } else {
82                                 TOSCAMetaFileParser.LOG.error("Parsing TOSCA meta file \"{}\" failed - {} error(s) occured. TOSCA meta file is invalid.", toscaMetaFile.getFileName().toString(), numErrors);
83                         }
84                         
85                 } catch (FileNotFoundException exc) {
86                         TOSCAMetaFileParser.LOG.error("\"{}\" doesn't exist or is not a file.", toscaMetaFile, exc);
87                 } catch (IOException exc) {
88                         TOSCAMetaFileParser.LOG.error("An IO Exception occured.", exc);
89                 } finally {
90                         if (reader != null) {
91                                 try {
92                                         reader.close();
93                                 } catch (IOException exc) {
94                                         TOSCAMetaFileParser.LOG.warn("An IOException occured.", exc);
95                                 }
96                         }
97                 }
98                 
99                 return toscaMetaFileContent;
100                 
101         }
102         
103         /**
104          * Validates block 0 of the TOSCA meta file.<br />
105          * <br />
106          * Required attributes in block 0:
107          * <ul>
108          * <li><code>TOSCA-Meta-Version</code> (value must be <code>1.0</code>)</li>
109          * <li><code>CSAR-Version</code> (value must be <code>1.0</code>)</li>
110          * <li><code>Created-By</code></li>
111          * </ul>
112          * Optional attributes in block 0:
113          * <ul>
114          * <li><code>Entry-Definitions</code></li>
115          * <li><code>Description</code></li>
116          * <li><code>Topology</code></li>
117          * </ul>
118          * 
119          * Further, arbitrary attributes are also allowed.<br />
120          * <br />
121          * 
122          * @param mf to validate
123          * @return Number of errors occurred during validation.
124          */
125         private int validateBlock0(ManifestContents mf) {
126                 
127                 int numErrors = 0;
128                 
129                 String metaFileVersion = null;
130                 String csarVersion = null;
131                 String createdBy = null;
132                 String entryDefinitions = null;
133                 String description = null;
134                 String topology = null;
135                 
136                 Map<String, String> mainAttr = mf.getMainAttributes();
137                 
138                 metaFileVersion = mainAttr.get(TOSCAMetaFileAttributes.TOSCA_META_VERSION);
139                 
140                 if (metaFileVersion == null) {
141                         this.logAttrMissing(TOSCAMetaFileAttributes.TOSCA_META_VERSION, 0);
142                         numErrors++;
143                 } else if (!(metaFileVersion = metaFileVersion.trim()).equals(TOSCAMetaFileAttributes.TOSCA_META_VERSION_VALUE)) {
144                         this.logAttrWrongVal(TOSCAMetaFileAttributes.TOSCA_META_VERSION, 0, TOSCAMetaFileAttributes.TOSCA_META_VERSION_VALUE);
145                         numErrors++;
146                 }
147                 
148                 csarVersion = mainAttr.get(TOSCAMetaFileAttributes.CSAR_VERSION);
149                 
150                 if (csarVersion == null) {
151                         this.logAttrMissing(TOSCAMetaFileAttributes.CSAR_VERSION, 0);
152                         numErrors++;
153                 } else if (!(csarVersion = csarVersion.trim()).equals(TOSCAMetaFileAttributes.TOSCA_META_VERSION_VALUE)) {
154                         this.logAttrWrongVal(TOSCAMetaFileAttributes.CSAR_VERSION, 0, TOSCAMetaFileAttributes.CSAR_VERSION_VALUE);
155                         numErrors++;
156                 }
157                 
158                 createdBy = mainAttr.get(TOSCAMetaFileAttributes.CREATED_BY);
159                 
160                 if (createdBy == null) {
161                         this.logAttrMissing(TOSCAMetaFileAttributes.CREATED_BY, 0);
162                         numErrors++;
163                 } else if ((createdBy = createdBy.trim()).isEmpty()) {
164                         this.logAttrValEmpty(TOSCAMetaFileAttributes.CREATED_BY, 0);
165                         numErrors++;
166                 }
167                 
168                 entryDefinitions = mainAttr.get(TOSCAMetaFileAttributes.ENTRY_DEFINITIONS);
169                 
170                 if ((entryDefinitions != null) && entryDefinitions.trim().isEmpty()) {
171                         this.logAttrValEmpty(TOSCAMetaFileAttributes.ENTRY_DEFINITIONS, 0);
172                         numErrors++;
173                 }
174                 
175                 description = mainAttr.get(TOSCAMetaFileAttributes.DESCRIPTION);
176                 
177                 if ((description != null) && description.trim().isEmpty()) {
178                         this.logAttrValEmpty(TOSCAMetaFileAttributes.DESCRIPTION, 0);
179                         numErrors++;
180                 }
181                 
182                 topology = mainAttr.get(TOSCAMetaFileAttributes.TOPOLOGY);
183                 
184                 if ((topology != null) && topology.trim().isEmpty()) {
185                         this.logAttrValEmpty(TOSCAMetaFileAttributes.TOPOLOGY, 0);
186                         numErrors++;
187                 }
188                 
189                 return numErrors;
190                 
191         }
192         
193         /**
194          * Validates the file blocks (block 1 to last block) of the TOSCA meta file.<br />
195          * <br />
196          * Each file block has the following required attributes:
197          * <ul>
198          * <li><code>Name</code></li>
199          * <li><code>Content-Type</code> (will be checked for correct syntax)</li>
200          * </ul>
201          * 
202          * Further, arbitrary attributes are also allowed in a file block.<br />
203          * <br />
204          * 
205          * @param mf to validate.
206          * @return Number of errors occurred during validation.
207          */
208         private int validateFileBlocks(ManifestContents mf) {
209                 
210                 int blockNr = 0;
211                 int numErrors = 0;
212                 
213                 String contentType;
214                 
215                 List<String> names = mf.getSectionNames();
216                 
217                 for (String name : names) {
218                         
219                         blockNr++;
220                         
221                         if ((name != null) && name.trim().isEmpty()) {
222                                 this.logAttrValEmpty(name, blockNr);
223                                 numErrors++;
224                         }
225                         
226                         Map<String, String> attr = mf.getAttributesForSection(name);
227                         contentType = attr.get(TOSCAMetaFileAttributes.CONTENT_TYPE);
228                         
229                         if (contentType == null) {
230                                 this.logAttrMissing(TOSCAMetaFileAttributes.CONTENT_TYPE, blockNr);
231                                 numErrors++;
232                         } else if (!contentType.trim().matches("^[-\\w\\+\\.]+/[-\\w\\+\\.]+$")) {
233                                 this.logAttrWrongVal(TOSCAMetaFileAttributes.CONTENT_TYPE, blockNr);
234                                 numErrors++;
235                         }
236                         
237                 }
238                 
239                 return numErrors;
240                 
241         }
242         
243         /**
244          * Logs that attribute <code>attributeName</code> in block
245          * <code>blockNr</code> is missing.
246          * 
247          * @param attributeName
248          * @param blockNr
249          */
250         private void logAttrMissing(String attributeName, int blockNr) {
251                 TOSCAMetaFileParser.LOG.warn("Required attribute {} in block {} is missing.", attributeName, blockNr);
252         }
253         
254         /**
255          * Logs that attribute <code>attributeName</code> in block
256          * <code>blockNr</code> has an invalid value. Correct is
257          * <code>correctValue</code>.
258          * 
259          * @param attributeName
260          * @param blockNr
261          * @param correctValue
262          */
263         private void logAttrWrongVal(String attributeName, int blockNr, String correctValue) {
264                 TOSCAMetaFileParser.LOG.warn("Attribute {} in block {} has an invalid value. Must be {}.", attributeName, blockNr, correctValue);
265         }
266         
267         /**
268          * Logs that attribute <code>attributeName</code> in block
269          * <code>blockNr</code> has an invalid value.
270          * 
271          * @param attributeName
272          * @param blockNr
273          */
274         private void logAttrWrongVal(String attributeName, int blockNr) {
275                 TOSCAMetaFileParser.LOG.warn("Attribute {} in block {} has an invalid value.", attributeName, blockNr);
276         }
277         
278         /**
279          * Logs that attribute <code>attributeName</code> in block
280          * <code>blockNr</code> has an empty value.
281          * 
282          * @param attributeName
283          * @param blockNr
284          */
285         private void logAttrValEmpty(String attributeName, int blockNr) {
286                 TOSCAMetaFileParser.LOG.warn("Attribute {} in block {} has a empty value.", attributeName, blockNr);
287         }
288         
289         /**
290          * Logs the ManifestProblem <code>problem</code>.
291          * 
292          * @param problem
293          */
294         private void logManifestProblem(ManifestProblem problem) {
295                 TOSCAMetaFileParser.LOG.warn(problem.toString());
296         }
297         
298 }