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

Java tutorial

Introduction

Here is the source code for com.galenframework.speclang2.pagespec.ForLoop.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.parser.StringCharReader;
import com.galenframework.parser.StructNode;
import com.galenframework.specs.Place;
import org.apache.commons.lang3.math.NumberUtils;
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.Pattern;

public class ForLoop {

    public static final String DEFAULT_VARIABLE_NAME = "index";
    private String indexMapping;
    private String previousMapping;
    private String nextMapping;
    private Object[] sequence;
    private String variableName;

    public ForLoop(Object[] sequence, String variableName, String previousMapping, String nextMapping,
            String indexMapping) {
        this.sequence = sequence;
        this.variableName = variableName;
        this.previousMapping = previousMapping;
        this.nextMapping = nextMapping;
        this.indexMapping = indexMapping;
    }

    public static ForLoop read(boolean isSimpleLoop, PageSpecHandler pageSpecHandler, StringCharReader reader,
            StructNode originNode) {
        try {
            String emptyness = reader.readUntilSymbol('[').trim();
            if (!emptyness.isEmpty()) {
                throw new SyntaxException(originNode, "Unexpected token: " + emptyness);
            }

            String sequenceStatement = reader.readUntilSymbol(']');
            Object[] sequence;
            if (isSimpleLoop) {
                sequence = readSequenceForSimpleLoop(sequenceStatement, originNode.getPlace());
            } else {
                sequence = readSequenceFromPageObjects(sequenceStatement, pageSpecHandler);
            }

            String variableName = DEFAULT_VARIABLE_NAME;

            String previousMapping = null;
            String nextMapping = null;
            String indexMapping = null;

            if (reader.hasMoreNormalSymbols()) {
                String nextWord = reader.readWord();
                if (!nextWord.equals("as")) {
                    throw new SyntaxException("Invalid token: " + nextWord);
                }

                variableName = reader.readWord();

                if (variableName.isEmpty()) {
                    throw new SyntaxException("Missing index");
                }

                if (reader.hasMoreNormalSymbols()) {
                    reader.readUntilSymbol(',');

                    Pair<String, String> extraMappings = parseExtraMapping(reader);
                    if ("prev".equals(extraMappings.getKey())) {
                        previousMapping = extraMappings.getValue();
                    } else if ("next".equals(extraMappings.getKey())) {
                        nextMapping = extraMappings.getValue();
                    } else if ("index".equals(extraMappings.getKey())) {
                        indexMapping = extraMappings.getValue();
                    } else {
                        throw new SyntaxException("Unknown loop mapping: " + extraMappings.getKey());
                    }
                }
            }
            return new ForLoop(sequence, variableName, previousMapping, nextMapping, indexMapping);
        } catch (SyntaxException ex) {
            ex.setPlace(originNode.getPlace());
            throw ex;
        }
    }

    private static Pair<String, String> parseExtraMapping(StringCharReader reader) {
        String type = reader.readWord();
        String as = reader.readWord();
        String varName = reader.readWord();

        if (type.isEmpty()) {
            throw new SyntaxException("Missing type. Expected 'prev' or 'next'");
        }
        if (!"as".equals(as)) {
            throw new SyntaxException("Incorrect statement. Use 'as'");
        }
        if (varName.isEmpty()) {
            throw new SyntaxException("Missing mapping name for '" + type + "'");
        }

        String theRest = reader.getTheRest().trim();
        if (!theRest.isEmpty()) {
            throw new SyntaxException("Cannot process: " + theRest);
        }

        return new ImmutablePair<>(type, varName);
    }

    private static String[] readSequenceFromPageObjects(String sequenceStatement, PageSpecHandler pageSpecHandler) {
        List<String> matchingObjects = pageSpecHandler.findAllObjectsMatchingStrictStatements(sequenceStatement);
        return matchingObjects.toArray(new String[matchingObjects.size()]);
    }

    private static Object[] readSequenceForSimpleLoop(String sequenceStatement, Place place) {
        sequenceStatement = sequenceStatement.replace(" ", "");
        sequenceStatement = sequenceStatement.replace("\t", "");
        Pattern sequencePattern = Pattern.compile(".*\\-.*");
        try {
            String[] values = sequenceStatement.split(",");

            ArrayList<Object> sequence = new ArrayList<>();

            for (String stringValue : values) {
                if (sequencePattern.matcher(stringValue).matches()) {
                    sequence.addAll(createSequence(stringValue));
                } else {
                    sequence.add(convertValueToIndex(stringValue));
                }
            }

            return sequence.toArray(new Object[sequence.size()]);
        } catch (Exception ex) {
            throw new SyntaxException(place, "Incorrect sequence syntax: " + sequenceStatement, ex);
        }
    }

    private static Object convertValueToIndex(String stringValue) {
        if (NumberUtils.isNumber(stringValue)) {
            return NumberUtils.toLong(stringValue);
        } else {
            return stringValue;
        }
    }

    private static List<Object> createSequence(String value) {
        int dashIndex = value.indexOf('-');

        int rangeA = Integer.parseInt(value.substring(0, dashIndex));
        int rangeB = Integer.parseInt(value.substring(dashIndex + 1));

        return createSequence(rangeA, rangeB);
    }

    private static List<Object> createSequence(int min, int max) {
        if (max >= min) {
            List<Object> parameters = new LinkedList<>();
            for (int i = min; i <= max; i++) {
                parameters.add(i);
            }
            return parameters;
        } else {
            return Collections.emptyList();
        }
    }

    public List<StructNode> apply(LoopVisitor loopVisitor) throws IOException {
        List<StructNode> resultingNodes = new LinkedList<>();

        int begin = 0;
        int end = sequence.length;

        if (previousMapping != null) {
            begin = 1;
        }
        if (nextMapping != null) {
            end = end - 1;
        }

        int index = 0;

        for (int i = begin; i < end; i++) {

            index += 1;

            Map<String, Object> vars = new HashMap<>();
            vars.put(variableName, sequence[i]);

            if (previousMapping != null) {
                vars.put(previousMapping, sequence[i - 1]);
            }
            if (nextMapping != null) {
                vars.put(nextMapping, sequence[i + 1]);
            }

            if (indexMapping != null) {
                vars.put(indexMapping, index);
            }

            resultingNodes.addAll(loopVisitor.visitLoop(vars));
        }

        return resultingNodes;
    }
}