Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
net.mindengine.galen.specs.reader.SpecReader Maven / Gradle / Ivy
/*******************************************************************************
* Copyright 2015 Ivan Shubin http://mindengine.net
*
* 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 net.mindengine.galen.specs.reader;
import static net.mindengine.galen.parser.Expectations.*;
import static net.mindengine.galen.specs.Alignment.ALL;
import static net.mindengine.galen.specs.Alignment.BOTTOM;
import static net.mindengine.galen.specs.Alignment.CENTERED;
import static net.mindengine.galen.specs.Alignment.LEFT;
import static net.mindengine.galen.specs.Alignment.RIGHT;
import static net.mindengine.galen.specs.Alignment.TOP;
import static net.mindengine.galen.suite.reader.Line.UNKNOWN_LINE;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.mindengine.galen.config.GalenConfig;
import net.mindengine.galen.page.Rect;
import net.mindengine.galen.parser.*;
import net.mindengine.galen.specs.*;
import net.mindengine.galen.specs.colors.ColorRange;
import net.mindengine.rainbow4j.filters.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
public class SpecReader {
private static final Place NULL_PLACE = null;
private Properties properties;
private Map specsMap = new HashMap();
public SpecReader(Properties properties) {
initSpecs();
this.properties = properties;
}
private void initSpecs() {
putSpec("absent", new SimpleSpecProcessor(new SpecInit() {
public Spec init() {
return new SpecAbsent();
}
}));
putSpec("visible", new SimpleSpecProcessor(new SpecInit() {
public Spec init() {
return new SpecVisible();
}
}));
putSpec("contains(\\s+partly)?", new SpecListProccessor(new SpecListInit() {
public Spec init(String specName, List list) {
String arguments = specName.substring("contains".length()).trim();
boolean isPartly = (!arguments.isEmpty() && arguments.equals("partly"));
return new SpecContains(list, isPartly);
}
}));
putSpec("width", new SpecComplexProcessor(expectThese(range()), new SpecComplexInit() {
public Spec init(String specName, String paramsText, String contextPath, Object[] args) {
return new SpecWidth((Range) args[0]);
}
}));
putSpec("height", new SpecComplexProcessor(expectThese(range()), new SpecComplexInit() {
public Spec init(String specName, String paramsText, String contextPath, Object[] args) {
return new SpecHeight((Range) args[0]);
}
}));
putSpec("text\\s+.*", new SpecProcessor() {
@Override
public Spec processSpec(String specName, String paramsText, String contextPath) {
String arguments = specName.substring("text".length()).trim();
List allWords = Expectations.readAllWords(arguments);
if (allWords.size() > 0) {
String type = allWords.get(allWords.size() - 1);
allWords.remove(allWords.size() - 1);
return new SpecText(SpecText.Type.fromString(type), paramsText.trim()).withOperations(allWords);
}
else throw new SyntaxException("Missing validation type (is, starts, ends, contains, matches)");
}
});
putSpec("css.*", new SpecProcessor() {
@Override
public Spec processSpec(String specName, String paramsText, String contextPath) {
String arguments = specName.substring("css".length()).trim();
StringCharReader reader = new StringCharReader(arguments);
String cssPropertyName = Expectations.word().read(reader);
String typeString = Expectations.word().read(reader);
if (cssPropertyName.isEmpty()) {
throw new SyntaxException("Missing css property name");
}
if (typeString.isEmpty()) {
throw new SyntaxException("Missing validation type (is, contains, starts, ends, matches)");
}
return new SpecCss(cssPropertyName, SpecText.Type.fromString(typeString), paramsText.trim());
}
});
putSpec("inside.*", new SpecComplexProcessor(expectThese(objectName(), locations()), new SpecComplexInit() {
@SuppressWarnings("unchecked")
@Override
public Spec init(String specName, String paramsText, String contextPath, Object[] args) {
String leftoverName = specName.substring(6).trim();
String objectName = (String) args[0];
List locations = (List) args[1];
SpecInside spec = new SpecInside(objectName, locations);
if (leftoverName.equals("partly")) {
spec.setPartly(true);
}
return spec;
}
}));
putSpec("near", new SpecComplexProcessor(expectThese(objectName(), locations()), new SpecComplexInit() {
@SuppressWarnings("unchecked")
@Override
public Spec init(String specName, String paramsText, String contextPath, Object[] args) {
String objectName = (String) args[0];
List locations = (List) args[1];
if (locations == null || locations.size() == 0) {
throw new SyntaxException(UNKNOWN_LINE, "There is no location defined");
}
return new SpecNear(objectName, locations);
}
}));
putSpec("(above|below)", new SpecProcessor() {
@Override
public Spec processSpec(String specName, String paramsText, String contextPath) throws IOException {
StringCharReader reader = new StringCharReader(paramsText.trim());
String objectName = new ExpectWord().read(reader);
Range range;
if (reader.hasMore()) {
range = Expectations.range().read(reader);
}
else {
range = Range.greaterThan(-1.0);
}
if (specName.equals("above")) {
return new SpecAbove(objectName, range);
}
else return new SpecBelow(objectName, range);
}
});
putSpec("(left\\s+of|right\\s+of)", new SpecProcessor() {
@Override
public Spec processSpec(String specName, String paramsText, String contextPath) throws IOException {
String direction = Expectations.word().read(new StringCharReader(specName));
StringCharReader reader = new StringCharReader(paramsText.trim());
String objectName = new ExpectWord().read(reader);
Range range;
if (reader.hasMore()) {
range = Expectations.range().read(reader);
}
else {
range = Range.greaterThan(-1.0);
}
if (direction.equals("left")) {
return new SpecLeftOf(objectName, range);
} else {
return new SpecRightOf(objectName, range);
}
}
});
putSpec("aligned\\s+.*", new SpecObjectAndErrorRateProcessor(new SpecObjectAndErrorRateInit() {
@Override
public Spec init(String specName, String objectName, Integer errorRate) {
String arguments = specName.substring("aligned".length()).trim();
StringCharReader reader = new StringCharReader(arguments);
String[] words = ExpectWord.readAllWords(reader);
if (words.length == 0) {
throw new SyntaxException("Alignment is not defined. Should be either 'vertically' either 'horizonally'");
}
String type = words[0];
Alignment alignment = Alignment.ALL;
if (words.length > 1) {
alignment = Alignment.parse(words[1]);
}
if (errorRate == null) {
errorRate = 0;
}
if (type.equals("horizontally")) {
if (alignment.isOneOf(CENTERED, TOP, BOTTOM, ALL)) {
return new SpecHorizontally(alignment, objectName).withErrorRate(errorRate);
}
else {
throw new SyntaxException(UNKNOWN_LINE, "Horizontal alignment doesn't allow this side: " + alignment.toString());
}
}
else if (type.equals("vertically")) {
if (alignment.isOneOf(CENTERED, LEFT, RIGHT, ALL)) {
return new SpecVertically(alignment, objectName).withErrorRate(errorRate);
}
else {
throw new SyntaxException(UNKNOWN_LINE, "Verticall alignment doesn't allow this side: " + alignment.toString());
}
}
else {
throw new SyntaxException("Unknown alignment: " + type);
}
}
}));
putSpec("centered\\s.*", new SpecObjectAndErrorRateProcessor(new SpecObjectAndErrorRateInit() {
@Override
public Spec init(String specName, String objectName, Integer errorRate) {
specName = specName.replace("centered", "").trim();
String args[] = specName.split(" ");
SpecCentered.Alignment alignment = SpecCentered.Alignment.ALL;
SpecCentered.Location location = null;
if (args.length == 1) {
location = SpecCentered.Location.fromString(args[0]);
}
else {
alignment = SpecCentered.Alignment.fromString(args[0]);
location = SpecCentered.Location.fromString(args[1]);
}
// Setting default 2 px error rate in case it was not provided in page spec
if (errorRate == null) {
errorRate = 2;
}
return new SpecCentered(objectName, alignment, location).withErrorRate(errorRate);
}
}));
putSpec("(on\\s.*|on)", new SpecComplexProcessor(expectThese(objectName(), locations()), new SpecComplexInit() {
@SuppressWarnings("unchecked")
@Override
public Spec init(String specName, String paramsText, String contextPath, Object[] args) {
String objectName = (String) args[0];
String[] words = ExpectWord.readAllWords(new StringCharReader(specName));
if (words.length > 3) {
throw new SyntaxException("Too many sides. Should use only 2");
}
Side sideHorizontal = Side.TOP;
Side sideVertical = Side.LEFT;
boolean isFirstHorizontal = false;
if (words.length > 1) {
Side side = Side.fromString(words[1]);
if (side == Side.TOP || side == Side.BOTTOM) {
isFirstHorizontal = true;
sideHorizontal = side;
}
else sideVertical = side;
}
if (words.length > 2) {
Side side = Side.fromString(words[2]);
if (side == Side.TOP || side == Side.BOTTOM) {
if (isFirstHorizontal) {
throw new SyntaxException("Cannot use theses sides: " + words[1] + " " + words[2]);
}
sideHorizontal = side;
}
else {
if (!isFirstHorizontal) {
throw new SyntaxException("Cannot use theses sides: " + words[1] + " " + words[2]);
}
sideVertical = side;
}
}
List locations = (List) args[1];
if (locations == null || locations.size() == 0) {
throw new SyntaxException(UNKNOWN_LINE, "There is no location defined");
}
return new SpecOn(objectName, sideHorizontal, sideVertical, locations);
}
}));
putSpec("component.*", new SpecProcessor() {
@Override
public Spec processSpec(String specName, String paramsText, String contextPath) throws IOException {
String childFilePath = paramsText.trim();
if (childFilePath.isEmpty()) {
throw new SyntaxException("File path to component spec is not specified");
}
String fullFilePath = childFilePath;
if (contextPath != null) {
fullFilePath = contextPath + File.separator + childFilePath;
}
SpecComponent spec = new SpecComponent();
spec.setSpecPath(fullFilePath);
if (getSecondWord(specName).equals("frame")) {
spec.setFrame(true);
}
return spec;
}
});
putSpec("color\\s+scheme", new SpecComplexProcessor(expectThese(colorRanges()), new SpecComplexInit() {
@SuppressWarnings("unchecked")
@Override
public Spec init(String specName, String paramsText, String contextPath, Object[] args) {
List colorRanges = (List)args[0];
if (colorRanges == null || colorRanges.size() == 0) {
throw new SyntaxException("There are no colors defined");
}
SpecColorScheme spec = new SpecColorScheme();
spec.setColorRanges(colorRanges);
return spec;
}
}));
putSpec("image", new SpecComplexProcessor(expectThese(commaSeparatedRepeatedKeyValues()), new SpecComplexInit() {
@Override
public Spec init(String specName, String paramsText, String contextPath, Object[] args) {
List> parameters = (List>) args[0];
SpecImage spec = new SpecImage();
spec.setImagePaths(new LinkedList());
spec.setStretch(false);
spec.setErrorRate(GalenConfig.getConfig().getImageSpecDefaultErrorRate());
spec.setTolerance(GalenConfig.getConfig().getImageSpecDefaultTolerance());
for (Pair parameter : parameters) {
if ("file".equals(parameter.getKey())) {
if (contextPath != null) {
spec.getImagePaths().add(contextPath + File.separator + parameter.getValue());
}
else {
spec.getImagePaths().add(parameter.getValue());
}
}
else if ("error".equals(parameter.getKey())) {
spec.setErrorRate(SpecImage.ErrorRate.fromString(parameter.getValue()));
}
else if ("tolerance".equals(parameter.getKey())) {
spec.setTolerance(parseIntegerParameter("tolerance", parameter.getValue()));
}
else if ("stretch".equals(parameter.getKey())) {
spec.setStretch(true);
}
else if ("area".equals(parameter.getKey())) {
spec.setSelectedArea(parseRect(parameter.getValue()));
}
else if ("filter".equals(parameter.getKey())) {
ImageFilter filter = parseImageFilter(parameter.getValue());
spec.getOriginalFilters().add(filter);
spec.getSampleFilters().add(filter);
}
else if ("filter-a".equals(parameter.getKey())) {
ImageFilter filter = parseImageFilter(parameter.getValue());
spec.getOriginalFilters().add(filter);
}
else if ("filter-b".equals(parameter.getKey())) {
ImageFilter filter = parseImageFilter(parameter.getValue());
spec.getSampleFilters().add(filter);
}
else if ("map-filter".equals(parameter.getKey())) {
ImageFilter filter = parseImageFilter(parameter.getValue());
spec.getMapFilters().add(filter);
}
else if ("crop-if-outside".equals(parameter.getKey())) {
spec.setCropIfOutside(true);
}
else {
throw new SyntaxException("Unknown parameter: " + parameter.getKey());
}
}
if (spec.getImagePaths() == null || spec.getImagePaths().size() == 0) {
throw new SyntaxException("There are no images defined");
}
return spec;
}
}));
}
private String getSecondWord(String text) {
StringCharReader reader = new StringCharReader(text);
Expectations.word().read(reader);
return Expectations.word().read(reader);
}
private ImageFilter parseImageFilter(String filterText) {
StringCharReader reader = new StringCharReader(filterText);
String filterName = new ExpectWord().read(reader);
Double value = new ExpectNumber().read(reader);
if ("contrast".equals(filterName)) {
return new ContrastFilter(value.intValue());
}
else if ("blur".equals(filterName)) {
return new BlurFilter(value.intValue());
}
else if ("denoise".equals(filterName)) {
return new DenoiseFilter(value.intValue());
}
else if ("saturation".equals(filterName)) {
return new SaturationFilter(value.intValue());
}
else if ("quantinize".equals(filterName)) {
return new QuantinizeFilter(value.intValue());
}
else throw new SyntaxException("Unknown image filter: " + filterName);
}
private Rect parseRect(String text) {
Integer[] numbers = new Integer[4];
StringCharReader reader = new StringCharReader(text);
for (int i=0;i 0) {
statement = specText.substring(0, splitterIndex);
if (splitterIndex < specText.length()) {
paramsText = specText.substring(splitterIndex + 1);
}
}
Spec spec = readSpecWithParams(statement.replace("\t", " ").trim(), paramsText, contextPath);
if (spec != null) {
spec.setOriginalText(specText);
spec.setProperties(properties);
}
spec.setPlace(place);
return spec;
}
private Spec readSpecWithParams(String specName, String paramsText, String contextPath) throws IOException {
return findMatchingSpec(specName).processSpec(specName, paramsText, contextPath);
}
private SpecProcessor findMatchingSpec(String specName) {
for (Map.Entry entry : specsMap.entrySet()) {
Matcher matcher = entry.getKey().matcher(specName);
if (matcher.matches()) {
return entry.getValue();
}
}
throw new SyntaxException(UNKNOWN_LINE, "Such constraint does not exist: " + specName);
}
private void putSpec(String patternText, SpecProcessor specProcessor) {
specsMap.put(Pattern.compile(patternText), specProcessor);
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
}