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
 
  10  *    Rene Trefft - initial API and implementation and/or initial documentation
 
  11  *******************************************************************************/
 
  12 package org.eclipse.winery.model.csar.toscametafile;
 
  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;
 
  21 import org.slf4j.Logger;
 
  22 import org.slf4j.LoggerFactory;
 
  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;
 
  30  * Parses and validates a TOSCA meta file.<br />
 
  32  * Copyright 2013 IAAS University of Stuttgart <br />
 
  35  * @author Rene Trefft - rene.trefft@developers.opentosca.org
 
  38 public class TOSCAMetaFileParser {
 
  40         final private static Logger LOG = LoggerFactory.getLogger(TOSCAMetaFileParser.class);
 
  44          * Parses and validates the <code>toscaMetaFile</code>.<br />
 
  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>.
 
  52         public TOSCAMetaFile parse(Path toscaMetaFile) {
 
  54                 // counts the errors during parsing
 
  57                 FileReader reader = null;
 
  58                 ManifestParser parser = null;
 
  59                 ManifestContents manifestContent = null;
 
  60                 TOSCAMetaFile toscaMetaFileContent = null;
 
  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);
 
  70                         for (ManifestProblem problem : parser.getProblems()) {
 
  71                                 this.logManifestProblem(problem);
 
  75                         numErrors += this.validateBlock0(manifestContent);
 
  76                         numErrors += this.validateFileBlocks(manifestContent);
 
  79                                 TOSCAMetaFileParser.LOG.debug("Parsing TOSCA meta file \"{}\" completed without errors. TOSCA meta file is valid.", toscaMetaFile.getFileName().toString());
 
  80                                 toscaMetaFileContent = new TOSCAMetaFile(manifestContent);
 
  82                                 TOSCAMetaFileParser.LOG.error("Parsing TOSCA meta file \"{}\" failed - {} error(s) occured. TOSCA meta file is invalid.", toscaMetaFile.getFileName().toString(), numErrors);
 
  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);
 
  93                                 } catch (IOException exc) {
 
  94                                         TOSCAMetaFileParser.LOG.warn("An IOException occured.", exc);
 
  99                 return toscaMetaFileContent;
 
 104          * Validates block 0 of the TOSCA meta file.<br />
 
 106          * Required attributes in block 0:
 
 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>
 
 112          * Optional attributes in block 0:
 
 114          * <li><code>Entry-Definitions</code></li>
 
 115          * <li><code>Description</code></li>
 
 116          * <li><code>Topology</code></li>
 
 119          * Further, arbitrary attributes are also allowed.<br />
 
 122          * @param mf to validate
 
 123          * @return Number of errors occurred during validation.
 
 125         private int validateBlock0(ManifestContents mf) {
 
 129                 String metaFileVersion = null;
 
 130                 String csarVersion = null;
 
 131                 String createdBy = null;
 
 132                 String entryDefinitions = null;
 
 133                 String description = null;
 
 134                 String topology = null;
 
 136                 Map<String, String> mainAttr = mf.getMainAttributes();
 
 138                 metaFileVersion = mainAttr.get(TOSCAMetaFileAttributes.TOSCA_META_VERSION);
 
 140                 if (metaFileVersion == null) {
 
 141                         this.logAttrMissing(TOSCAMetaFileAttributes.TOSCA_META_VERSION, 0);
 
 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);
 
 148                 csarVersion = mainAttr.get(TOSCAMetaFileAttributes.CSAR_VERSION);
 
 150                 if (csarVersion == null) {
 
 151                         this.logAttrMissing(TOSCAMetaFileAttributes.CSAR_VERSION, 0);
 
 153                 } else if (!(csarVersion = csarVersion.trim()).equals(TOSCAMetaFileAttributes.TOSCA_META_VERSION_VALUE)) {
 
 154                         this.logAttrWrongVal(TOSCAMetaFileAttributes.CSAR_VERSION, 0, TOSCAMetaFileAttributes.CSAR_VERSION_VALUE);
 
 158                 createdBy = mainAttr.get(TOSCAMetaFileAttributes.CREATED_BY);
 
 160                 if (createdBy == null) {
 
 161                         this.logAttrMissing(TOSCAMetaFileAttributes.CREATED_BY, 0);
 
 163                 } else if ((createdBy = createdBy.trim()).isEmpty()) {
 
 164                         this.logAttrValEmpty(TOSCAMetaFileAttributes.CREATED_BY, 0);
 
 168                 entryDefinitions = mainAttr.get(TOSCAMetaFileAttributes.ENTRY_DEFINITIONS);
 
 170                 if ((entryDefinitions != null) && entryDefinitions.trim().isEmpty()) {
 
 171                         this.logAttrValEmpty(TOSCAMetaFileAttributes.ENTRY_DEFINITIONS, 0);
 
 175                 description = mainAttr.get(TOSCAMetaFileAttributes.DESCRIPTION);
 
 177                 if ((description != null) && description.trim().isEmpty()) {
 
 178                         this.logAttrValEmpty(TOSCAMetaFileAttributes.DESCRIPTION, 0);
 
 182                 topology = mainAttr.get(TOSCAMetaFileAttributes.TOPOLOGY);
 
 184                 if ((topology != null) && topology.trim().isEmpty()) {
 
 185                         this.logAttrValEmpty(TOSCAMetaFileAttributes.TOPOLOGY, 0);
 
 194          * Validates the file blocks (block 1 to last block) of the TOSCA meta file.<br />
 
 196          * Each file block has the following required attributes:
 
 198          * <li><code>Name</code></li>
 
 199          * <li><code>Content-Type</code> (will be checked for correct syntax)</li>
 
 202          * Further, arbitrary attributes are also allowed in a file block.<br />
 
 205          * @param mf to validate.
 
 206          * @return Number of errors occurred during validation.
 
 208         private int validateFileBlocks(ManifestContents mf) {
 
 215                 List<String> names = mf.getSectionNames();
 
 217                 for (String name : names) {
 
 221                         if ((name != null) && name.trim().isEmpty()) {
 
 222                                 this.logAttrValEmpty(name, blockNr);
 
 226                         Map<String, String> attr = mf.getAttributesForSection(name);
 
 227                         contentType = attr.get(TOSCAMetaFileAttributes.CONTENT_TYPE);
 
 229                         if (contentType == null) {
 
 230                                 this.logAttrMissing(TOSCAMetaFileAttributes.CONTENT_TYPE, blockNr);
 
 232                         } else if (!contentType.trim().matches("^[-\\w\\+\\.]+/[-\\w\\+\\.]+$")) {
 
 233                                 this.logAttrWrongVal(TOSCAMetaFileAttributes.CONTENT_TYPE, blockNr);
 
 244          * Logs that attribute <code>attributeName</code> in block
 
 245          * <code>blockNr</code> is missing.
 
 247          * @param attributeName
 
 250         private void logAttrMissing(String attributeName, int blockNr) {
 
 251                 TOSCAMetaFileParser.LOG.warn("Required attribute {} in block {} is missing.", attributeName, blockNr);
 
 255          * Logs that attribute <code>attributeName</code> in block
 
 256          * <code>blockNr</code> has an invalid value. Correct is
 
 257          * <code>correctValue</code>.
 
 259          * @param attributeName
 
 261          * @param correctValue
 
 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);
 
 268          * Logs that attribute <code>attributeName</code> in block
 
 269          * <code>blockNr</code> has an invalid value.
 
 271          * @param attributeName
 
 274         private void logAttrWrongVal(String attributeName, int blockNr) {
 
 275                 TOSCAMetaFileParser.LOG.warn("Attribute {} in block {} has an invalid value.", attributeName, blockNr);
 
 279          * Logs that attribute <code>attributeName</code> in block
 
 280          * <code>blockNr</code> has an empty value.
 
 282          * @param attributeName
 
 285         private void logAttrValEmpty(String attributeName, int blockNr) {
 
 286                 TOSCAMetaFileParser.LOG.warn("Attribute {} in block {} has a empty value.", attributeName, blockNr);
 
 290          * Logs the ManifestProblem <code>problem</code>.
 
 294         private void logManifestProblem(ManifestProblem problem) {
 
 295                 TOSCAMetaFileParser.LOG.warn(problem.toString());