io.cloudslang.lang.compiler.parser.MetadataParser.java Source code

Java tutorial

Introduction

Here is the source code for io.cloudslang.lang.compiler.parser.MetadataParser.java

Source

/*******************************************************************************
 * (c) Copyright 2016 Hewlett-Packard Development Company, L.P.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Apache License v2.0 which accompany this distribution.
 *
 * The Apache License is available at
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 *******************************************************************************/
package io.cloudslang.lang.compiler.parser;

import io.cloudslang.lang.compiler.SlangSource;
import io.cloudslang.lang.compiler.parser.model.ParsedDescriptionData;
import io.cloudslang.lang.compiler.parser.utils.ParserExceptionHandler;
import io.cloudslang.lang.compiler.utils.MetadataUtils;
import io.cloudslang.lang.compiler.utils.SlangSourceUtils;
import io.cloudslang.lang.compiler.validator.matcher.DescriptionPatternMatcher;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.tuple.Pair;

public class MetadataParser {
    private ParserExceptionHandler parserExceptionHandler;
    private DescriptionPatternMatcher descriptionPatternMatcher;

    public MetadataParser() {
        descriptionPatternMatcher = new DescriptionPatternMatcher();
    }

    public ParsedDescriptionData parse(SlangSource source) {
        Validate.notNull(source.getContent(), "Source " + source.getName() + " cannot be null");
        try {
            return extractDescriptionData(source);
        } catch (Throwable e) {
            throw new RuntimeException("There was a problem parsing the description: " + source.getName() + "."
                    + System.lineSeparator() + parserExceptionHandler.getErrorMessage(e), e);
        }
    }

    private ParsedDescriptionData extractDescriptionData(SlangSource source) {
        List<String> lines = SlangSourceUtils.readLines(source);
        return processRawLines(lines);
    }

    private ParsedDescriptionData processRawLines(List<String> lines) {
        DescriptionBuilder descriptionBuilder = new DescriptionBuilder();
        for (int lineNrZeroBased = 0; lineNrZeroBased < lines.size(); lineNrZeroBased++) {
            String currentLine = lines.get(lineNrZeroBased);

            // block start -  #!!
            if (descriptionPatternMatcher.matchesDescriptionStart(currentLine)) {
                handleBlockStart(descriptionBuilder, lineNrZeroBased);
            } else
            // #!!#
            if (descriptionPatternMatcher.matchesDescriptionEnd(currentLine)) {
                handleDescriptionEnd(descriptionBuilder, lines, lineNrZeroBased);
            } else {
                // #! @tag var: content <=> @tag var
                if (descriptionPatternMatcher.matchesDescriptionVariableLine(currentLine)) {
                    handleDescriptionLineVariableSyntax(descriptionBuilder, currentLine);
                } else
                // #! @tag: content
                if (descriptionPatternMatcher.matchesDescriptionGeneralLine(currentLine)) {
                    handleDescriptionLineGeneralSyntax(descriptionBuilder, currentLine);
                } else {
                    if (descriptionPatternMatcher.matchesVariableLineDeclarationOnlyLine(currentLine)) {
                        handleDescriptionLineVariableDeclarationOnlySyntax(descriptionBuilder, currentLine);
                    } else {
                        // #! continued from previous line
                        if (descriptionPatternMatcher.matchesDescriptionComplementaryLine(currentLine)) {
                            handleDescriptionLineComplementarySyntax(descriptionBuilder, currentLine);
                        } else {
                            // check if line is allowed inside description
                            if (descriptionBuilder.descriptionOpened()) {
                                handleNonDescriptionLineInsideDescription(descriptionBuilder, currentLine,
                                        lineNrZeroBased);
                            }
                        }
                    }
                }
            }
        }
        return descriptionBuilder.build();
    }

    private void handleNonDescriptionLineInsideDescription(DescriptionBuilder descriptionBuilder,
            String currentLine, int lineNumberZeroBased) {
        // check line fits into description
        if (!descriptionPatternMatcher.isLineAcceptedInsideDescription(currentLine)) {
            descriptionBuilder.addError(new RuntimeException(MetadataUtils.generateErrorMessage(lineNumberZeroBased,
                    "Line is not acceptable inside description section")));
            descriptionBuilder.resetCurrentDescription();
        }
    }

    private void handleDescriptionEnd(DescriptionBuilder descriptionBuilder, List<String> lines,
            int currentLineNr) {
        // block end
        if (descriptionBuilder.descriptionOpened()) {
            String stepName = tryExtractStepName(lines, currentLineNr + 1);
            if (stepName == null) {
                // general description
                descriptionBuilder.endExecutableDescription();
            } else {
                // step description
                descriptionBuilder.endStepDescription(stepName);
            }
        }
        // ignore
    }

    private String tryExtractStepName(List<String> lines, int lineNr) {
        String stepName = null;
        int nrOfLines = lines.size();

        if (inRange(lineNr, nrOfLines)) {
            String currentLine = lines.get(lineNr);

            while (isIgnorableLine(currentLine) && inRange(lineNr, nrOfLines)) {
                currentLine = lines.get(lineNr++);
            }

            if (inRange(lineNr, nrOfLines)) {
                // investigate line
                if (descriptionPatternMatcher.matchesStepStartLine(currentLine)) {
                    stepName = descriptionPatternMatcher.getStepName(currentLine);
                }
            }
        }

        return stepName;
    }

    private boolean isIgnorableLine(String line) {
        return StringUtils.isBlank(line) || descriptionPatternMatcher.matchesCommentLine(line);
    }

    private boolean inRange(int nr, int nrOfLines) {
        return nr < nrOfLines;
    }

    private void handleDescriptionLineComplementarySyntax(DescriptionBuilder descriptionBuilder,
            String currentLine) {
        // if description is opened
        if (descriptionBuilder.descriptionOpened()) {
            // add
            String data = descriptionPatternMatcher.getDescriptionComplementaryLineData(currentLine);
            data = data.trim();
            descriptionBuilder.addToDescriptionToMostRecentlyUsedTag(data);
        }
        // otherwise ignore
    }

    private void handleDescriptionLineGeneralSyntax(DescriptionBuilder descriptionBuilder, String currentLine) {
        // if description is opened
        if (descriptionBuilder.descriptionOpened()) {
            // add
            Pair<String, String> data = descriptionPatternMatcher.getDescriptionGeneralLineData(currentLine);
            descriptionBuilder.addToDescription(data.getLeft(), data.getRight());
        }
        // otherwise ignore
    }

    private void handleDescriptionLineVariableSyntax(DescriptionBuilder descriptionBuilder, String currentLine) {
        // if description is opened
        if (descriptionBuilder.descriptionOpened()) {
            // add
            Pair<String, String> data = descriptionPatternMatcher.getDescriptionVariableLineData(currentLine);
            descriptionBuilder.addToDescription(data.getLeft(), data.getRight());
        }
        // otherwise ignore
    }

    private void handleDescriptionLineVariableDeclarationOnlySyntax(DescriptionBuilder descriptionBuilder,
            String currentLine) {
        // if description is opened
        if (descriptionBuilder.descriptionOpened()) {
            // add
            Pair<String, String> data = descriptionPatternMatcher
                    .getDescriptionVariableLineDataDeclarationOnly(currentLine);
            descriptionBuilder.addToDescription(data.getLeft(), data.getRight());
        }
        // otherwise ignore
    }

    private void handleBlockStart(DescriptionBuilder descriptionBuilder, int currentLineNumberZeroBased) {
        // not clear state
        if (descriptionBuilder.descriptionOpened()) {
            // raise exception, begin description
            descriptionBuilder.addError(new RuntimeException(MetadataUtils
                    .generateErrorMessage(currentLineNumberZeroBased, "Description already in progress")));
        }
        descriptionBuilder.beginDescription(currentLineNumberZeroBased + 1);
    }

    public void setParserExceptionHandler(ParserExceptionHandler parserExceptionHandler) {
        this.parserExceptionHandler = parserExceptionHandler;
    }
}