com.technophobia.substeps.model.Syntax Maven / Gradle / Ivy
/*
* Copyright Technophobia Ltd 2012
*
* This file is part of Substeps.
*
* Substeps is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Substeps is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Substeps. If not, see .
*/
package com.technophobia.substeps.model;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.technophobia.substeps.model.exception.DuplicateStepImplementationException;
import com.technophobia.substeps.model.exception.StepImplementationException;
import com.technophobia.substeps.model.exception.UnimplementedStepException;
import com.technophobia.substeps.runner.syntax.DefaultSyntaxErrorReporter;
import com.technophobia.substeps.runner.syntax.SyntaxErrorReporter;
/**
*
*
* @author imoore
*
*/
public class Syntax {
// These two will always be populated
private final Map> stepImplementationMap = new HashMap>();
// this might not be populated
private PatternMap subStepsMap = null;
private boolean strict;
private boolean failOnDuplicateStepImplementations = true;
private String[] nonStrictKeywordPrecedence;
private final SyntaxErrorReporter syntaxErrorReporter;
public Syntax() {
this(new DefaultSyntaxErrorReporter());
}
public Syntax(final SyntaxErrorReporter syntaxErrorReporter) {
this.syntaxErrorReporter = syntaxErrorReporter;
}
public Map> getStepImplementationMap() {
return stepImplementationMap;
}
public List getStepImplementations() {
// build a list of the impls in the order of the annotations
final List allImpls = new ArrayList();
final List sortedAnnotations = new ArrayList();
sortedAnnotations.addAll(stepImplementationMap.keySet());
Collections.sort(sortedAnnotations);
// get all the PatternMaps for each annotation:
for (final String annotation : sortedAnnotations) {
final PatternMap patternMap = stepImplementationMap.get(annotation);
if (patternMap != null) {
for (final StepImplementation impl : patternMap.values()) {
allImpls.add(impl);
}
}
}
return allImpls;
}
/**
* @param keyWord
* @return
*/
private PatternMap getPatternMapForAnnotation(final String keyWord) {
return stepImplementationMap.get(keyWord);
}
/**
* @param loadSubSteps
*/
public void setSubStepsMap(final PatternMap loadSubSteps) {
subStepsMap = loadSubSteps;
}
public PatternMap getSubStepsMap() {
return subStepsMap;
}
/**
* @return
*/
public List getSortedRootSubSteps() {
final Collection rootSubSteps = subStepsMap.values();
final List sortedList = new ArrayList();
sortedList.addAll(rootSubSteps);
Collections.sort(sortedList, ParentStep.PARENT_STEP_COMPARATOR);
return sortedList;
}
/**
* @param impl
*/
public void addStepImplementation(final StepImplementation impl) {
PatternMap patternMap = stepImplementationMap.get(impl.getKeyword());
if (patternMap == null) {
patternMap = new PatternMap();
stepImplementationMap.put(impl.getKeyword(), patternMap);
}
final String pattern = impl.getValue();
if (!patternMap.containsPattern(pattern)) {
patternMap.put(pattern, impl);
} else {
final StepImplementationException ex = new DuplicateStepImplementationException(pattern,
patternMap.getValueForPattern(pattern), impl);
syntaxErrorReporter.reportStepImplError(ex);
if (failOnDuplicateStepImplementations) {
throw ex;
}
}
}
/**
* @param strict
*/
public void setStrict(final boolean strict, final String[] nonStrictKeywordPrecedence) {
this.strict = strict;
this.nonStrictKeywordPrecedence = nonStrictKeywordPrecedence;
if (!strict && (this.nonStrictKeywordPrecedence == null || this.nonStrictKeywordPrecedence.length == 0)) {
throw new IllegalArgumentException(
"Please provide a keyword precedence in parameter nonStrictKeywordPrecedence to use when running in non strict mode");
}
}
public void setFailOnDuplicateStepImplementations(final boolean failOnDuplicateStepImplementations) {
this.failOnDuplicateStepImplementations = failOnDuplicateStepImplementations;
}
/**
* @param parameterLine
* @return
*/
public List getStepImplementations(final String keyword, final String parameterLine) {
return getStepImplementationsInternal(keyword, parameterLine, false);
}
public List checkForStepImplementations(final String keyword, final String parameterLine) {
return getStepImplementationsInternal(keyword, parameterLine, true);
}
/**
* @param keyword
* @param parameterLine
* @return
*/
private List getStepImplementationsInternal(final String keyword, final String parameterLine,
final boolean okNotTofindAnything) {
List list = getStrictStepimplementation(keyword, parameterLine, okNotTofindAnything);
if (!strict
&& ((list == null && okNotTofindAnything) || (!okNotTofindAnything && list != null && list.isEmpty()))) {
// look for an alternative, iterate through the
// nonStrictKeywordPrecedence until we get what we want
for (final String altKeyword : nonStrictKeywordPrecedence) {
// don't use the same keyword again
if (altKeyword.compareToIgnoreCase(keyword) != 0) {
final List altStepImplementations = getStrictStepimplementation(altKeyword,
parameterLine.replaceFirst(keyword, altKeyword), okNotTofindAnything);
if (!altStepImplementations.isEmpty()) {
// found an alternative, bail immediately
list = new ArrayList(Collections2.transform(altStepImplementations,
new CloneStepImplementationsWithNewKeywordFunction(keyword)));
break;
}
}
}
}
return list;
}
/**
* @param keyword
* @param parameterLine
* @return
*/
private List getStrictStepimplementation(final String keyword, final String parameterLine,
final boolean okNotTofindAnything) {
List list = null;
final PatternMap pMap = getPatternMapForAnnotation(keyword);
if (pMap != null) {
list = pMap.get(parameterLine);
}
else if (!okNotTofindAnything) {
throw new UnimplementedStepException(parameterLine);
}
return list;
}
private static final class CloneStepImplementationsWithNewKeywordFunction implements
Function {
private final String keyword;
public CloneStepImplementationsWithNewKeywordFunction(final String keyword) {
this.keyword = keyword;
}
public StepImplementation apply(final StepImplementation stepImplementation) {
return stepImplementation.cloneWithKeyword(keyword);
}
}
/**
* @return the strict
*/
public boolean isStrict() {
return strict;
}
/**
* @return the nonStrictKeywordPrecedence
*/
public String[] getNonStrictKeywordPrecedence() {
return nonStrictKeywordPrecedence;
}
}