com.galenframework.speclang2.pagespec.PageSectionProcessor.java Source code

Java tutorial

Introduction

Here is the source code for com.galenframework.speclang2.pagespec.PageSectionProcessor.java

Source

/*******************************************************************************
* Copyright 2017 Ivan Shubin http://galenframework.com
* 
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* 
*   http://www.apache.org/licenses/LICENSE-2.0
* 
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.galenframework.speclang2.pagespec;

import com.galenframework.parser.SyntaxException;
import com.galenframework.specs.page.PageSection;
import com.galenframework.specs.page.SpecGroup;
import com.galenframework.parser.StringCharReader;
import com.galenframework.speclang2.pagespec.rules.Rule;
import com.galenframework.parser.Expectations;
import com.galenframework.parser.StructNode;
import com.galenframework.specs.Spec;
import com.galenframework.specs.page.ObjectSpecs;
import com.galenframework.specs.Place;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;

import java.io.IOException;
import java.util.*;
import java.util.regex.Matcher;

public class PageSectionProcessor {
    public static final String NO_OBJECT_NAME = null;
    private final PageSpecHandler pageSpecHandler;
    private final PageSection parentSection;

    public PageSectionProcessor(PageSpecHandler pageSpecHandler) {
        this.pageSpecHandler = pageSpecHandler;
        this.parentSection = null;
    }

    public PageSectionProcessor(PageSpecHandler pageSpecHandler, PageSection parentSection) {
        this.pageSpecHandler = pageSpecHandler;
        this.parentSection = parentSection;
    }

    public void process(StructNode sectionNode) throws IOException {
        if (sectionNode.getChildNodes() != null) {
            String sectionName = sectionNode.getName().substring(1, sectionNode.getName().length() - 1).trim();
            PageSection section = findSection(sectionName);
            if (section == null) {
                section = new PageSection(sectionName, sectionNode.getPlace());
                if (parentSection != null) {
                    parentSection.addSubSection(section);
                } else {
                    pageSpecHandler.addSection(section);
                }
            }
            processSection(section, sectionNode.getChildNodes());
        }
    }

    private void processSection(PageSection section, List<StructNode> childNodes) throws IOException {
        for (StructNode sectionChildNode : childNodes) {
            String childPlace = sectionChildNode.getName();
            if (isSectionDefinition(childPlace)) {
                new PageSectionProcessor(pageSpecHandler, section).process(sectionChildNode);
            } else if (isRule(childPlace)) {
                processSectionRule(section, sectionChildNode);
            } else if (isObject(childPlace)) {
                processObject(section, sectionChildNode);
            } else {
                throw new SyntaxException(sectionChildNode, "Unknown statement: " + childPlace);
            }
        }
    }

    private void processSectionRule(PageSection section, StructNode ruleNode) throws IOException {
        String ruleText = ruleNode.getName().substring(1).trim();

        Pair<PageRule, Map<String, String>> rule = findAndProcessRule(ruleText, ruleNode);

        PageSection ruleSection = new PageSection(ruleText, ruleNode.getPlace());
        section.addSubSection(ruleSection);

        List<StructNode> resultingNodes;
        try {
            resultingNodes = rule.getKey().apply(pageSpecHandler, ruleText, NO_OBJECT_NAME, rule.getValue(),
                    ruleNode.getChildNodes());
            processSection(ruleSection, resultingNodes);
        } catch (Exception ex) {
            throw new SyntaxException(ruleNode, "Error processing rule: " + ruleText, ex);
        }
    }

    private Pair<PageRule, Map<String, String>> findAndProcessRule(String ruleText, StructNode ruleNode) {
        ListIterator<Pair<Rule, PageRule>> iterator = pageSpecHandler.getPageRules()
                .listIterator(pageSpecHandler.getPageRules().size());
        /*
        It is important to make a reversed iteration over all rules so that
        it is possible for the end user to override previously defined rules
         */

        while (iterator.hasPrevious()) {
            Pair<Rule, PageRule> rulePair = iterator.previous();
            Matcher matcher = rulePair.getKey().getPattern().matcher(ruleText);
            if (matcher.matches()) {
                int index = 1;

                Map<String, String> parameters = new HashMap<>();

                for (String parameterName : rulePair.getKey().getParameters()) {
                    String value = matcher.group(index);
                    pageSpecHandler.setGlobalVariable(parameterName, value, ruleNode);

                    parameters.put(parameterName, value);
                    index += 1;
                }

                return new ImmutablePair<>(rulePair.getValue(), parameters);
            }
        }
        throw new SyntaxException(ruleNode, "Couldn't find rule matching: " + ruleText);
    }

    private void processObjectLevelRule(ObjectSpecs objectSpecs, StructNode sourceNode) throws IOException {
        String ruleText = sourceNode.getName().substring(1).trim();
        Pair<PageRule, Map<String, String>> rule = findAndProcessRule(ruleText, sourceNode);

        try {
            pageSpecHandler.setGlobalVariable("objectName", objectSpecs.getObjectName(), sourceNode);

            List<StructNode> specNodes = rule.getKey().apply(pageSpecHandler, ruleText, objectSpecs.getObjectName(),
                    rule.getValue(), sourceNode.getChildNodes());

            SpecGroup specGroup = new SpecGroup();
            specGroup.setName(ruleText);
            objectSpecs.addSpecGroup(specGroup);

            for (StructNode specNode : specNodes) {
                specGroup.addSpec(
                        pageSpecHandler.getSpecReader().read(specNode.getName(), pageSpecHandler.getContextPath()));
            }
        } catch (Exception ex) {
            throw new SyntaxException(sourceNode, "Error processing rule: " + ruleText, ex);
        }
    }

    private boolean isRule(String nodeText) {
        return nodeText.startsWith("|");
    }

    private PageSection findSection(String sectionName) {
        if (parentSection != null) {
            return findSection(sectionName, parentSection.getSections());
        } else {
            return findSection(sectionName, pageSpecHandler.getPageSections());
        }
    }

    private PageSection findSection(String sectionName, List<PageSection> sections) {
        for (PageSection section : sections) {
            if (section.getName().equals(sectionName)) {
                return section;
            }
        }
        return null;
    }

    private void processObject(PageSection section, StructNode objectNode) throws IOException {
        String name = objectNode.getName();
        String objectExpression = name.substring(0, name.length() - 1).trim();

        List<String> objectNames = pageSpecHandler.findAllObjectsMatchingStrictStatements(objectExpression);

        for (String objectName : objectNames) {
            if (objectNode.getChildNodes() != null && objectNode.getChildNodes().size() > 0) {
                ObjectSpecs objectSpecs = findObjectSpecsInSection(section, objectName);
                if (objectSpecs == null) {
                    objectSpecs = new ObjectSpecs(objectName);
                    section.addObjects(objectSpecs);
                }

                for (StructNode specNode : objectNode.getChildNodes()) {
                    if (isRule(specNode.getName())) {
                        processObjectLevelRule(objectSpecs, specNode);
                    } else {
                        processSpec(objectSpecs, specNode);
                    }
                }
            }
        }
    }

    private void processSpec(ObjectSpecs objectSpecs, StructNode specNode) {
        if (specNode.getChildNodes() != null && !specNode.getChildNodes().isEmpty()) {
            throw new SyntaxException(specNode, "Specs cannot have inner blocks");
        }
        String specText = specNode.getName();
        boolean onlyWarn = false;
        if (specText.startsWith("%")) {
            specText = specText.substring(1);
            onlyWarn = true;
        }

        String alias = null;
        StringCharReader reader = new StringCharReader(specText);
        if (reader.firstNonWhiteSpaceSymbol() == '"') {
            alias = Expectations.doubleQuotedText().read(reader);
            specText = reader.getTheRest();
        }

        Spec spec;
        try {
            spec = pageSpecHandler.getSpecReader().read(specText, pageSpecHandler.getContextPath());
        } catch (SyntaxException ex) {
            ex.setPlace(specNode.getPlace());
            throw ex;
        }
        spec.setOnlyWarn(onlyWarn);
        spec.setAlias(alias);
        if (specNode.getPlace() != null) {
            spec.setPlace(new Place(specNode.getPlace().getFilePath(), specNode.getPlace().getLineNumber()));
        }
        spec.setProperties(pageSpecHandler.getProperties());
        spec.setJsVariables(pageSpecHandler.getJsVariables());

        objectSpecs.getSpecs().add(spec);
    }

    private ObjectSpecs findObjectSpecsInSection(PageSection section, String objectName) {
        if (section.getObjects() != null) {
            for (ObjectSpecs objectSpecs : section.getObjects()) {
                if (objectSpecs.getObjectName().equals(objectName)) {
                    return objectSpecs;
                }
            }
        }
        return null;
    }

    private boolean isObject(String childPlace) {
        return childPlace.endsWith(":");
    }

    public static boolean isSectionDefinition(String name) {
        return name.startsWith("=") && name.endsWith("=");
    }
}