/*
* -----------------------------------------------------------------------\
* PerfCake
*
* Copyright (C) 2010 - 2016 the original author or authors.
*
* 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 org.perfcake.validation;
import org.perfcake.message.Message;
import org.perfcake.util.StringTemplate;
import org.perfcake.util.StringUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.w3c.dom.Element;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* <p>Checks the message payload for the given regular expression.</p>
*
* <p>It is possible to set the {@link java.util.regex.Pattern#compile(String, int)} compile flags using the particular properties.</p>
*
* <p>All flags but {@link java.util.regex.Pattern#UNIX_LINES} are supported. That is because
* {@link org.perfcake.util.StringUtil#trimLines(String)} is used to pre-process the message payload
* that changes all line breakers to <code>\n</code>.</p>
*
* @author <a href="mailto:lucie.fabrikova@gmail.com">Lucie Fabriková</a>
* @author <a href="mailto:marvenec@gmail.com">Martin Večeřa</a>
* @author <a href="mailto:pavel.macik@gmail.com">Pavel Macík</a>
* @see java.util.regex.Pattern#compile(String, int)
*/
public class RegExpValidator implements MessageValidator {
private static final Logger log = LogManager.getLogger(RegExpValidator.class);
private StringTemplate pattern;
// java.util.regex.Pattern flags
private boolean caseInsensitive = false;
private boolean multiline = false;
private boolean dotall = false;
private boolean unicodeCase = false;
private boolean canonEq = false;
private boolean literal = false;
private boolean unicodeCharacterClass = false;
private boolean comments = false;
@Override
public boolean isValid(final Message originalMessage, final Message response, final Properties messageAttributes) {
final String trimmedLinesOfPayload = StringUtil.trimLines((response == null || response.getPayload() == null) ? "" : response.getPayload().toString());
final String resultPayload = StringUtil.trim(trimmedLinesOfPayload);
if (!matches(resultPayload, pattern.toString(messageAttributes))) {
if (log.isInfoEnabled()) {
log.info(String.format("Message payload '%s' does not match the pattern '%s'.", (response != null) ? response.getPayload().toString() : "", pattern.toString(messageAttributes)));
}
return false;
}
return true;
}
private boolean matches(final String string, final String regex) {
int flags = 0;
if (caseInsensitive) {
flags = flags | Pattern.CASE_INSENSITIVE;
}
if (multiline) {
flags = flags | Pattern.MULTILINE;
}
if (dotall) {
flags = flags | Pattern.DOTALL;
}
if (unicodeCase) {
flags = flags | Pattern.UNICODE_CASE;
}
if (canonEq) {
flags = flags | Pattern.CANON_EQ;
}
if (literal) {
flags = flags | Pattern.LITERAL;
}
if (unicodeCharacterClass) {
flags = flags | Pattern.UNICODE_CHARACTER_CLASS;
}
if (comments) {
flags = flags | Pattern.COMMENTS;
}
final Pattern p = Pattern.compile(regex, flags);
final Matcher m = p.matcher(string);
return m.matches();
}
/**
* Gets the regular expression pattern.
*
* @return The regular expression pattern.
*/
public String getPattern() {
return pattern.toString();
}
/**
* Sets the regular expression pattern.
*
* @param pattern
* The regular expression pattern.
* @return Instance of this to support fluent API.
*/
public RegExpValidator setPattern(final String pattern) {
this.pattern = new StringTemplate(pattern);
return this;
}
/**
* Sets the regular expression pattern taken from {@link org.w3c.dom.Element Element}'s text content.
*
* @param pattern
* The DOM element from whose content the regular expression pattern is taken.
*/
public void setPatternAsElement(final Element pattern) {
this.pattern = new StringTemplate(pattern.getTextContent());
}
/**
* Gets the value of {@link java.util.regex.Pattern#COMMENTS} flag used to compile the regular expression pattern.
*
* @return The value of {@link java.util.regex.Pattern#COMMENTS} flag.
* @see java.util.regex.Pattern#compile(String, int)
*/
public boolean isComments() {
return comments;
}
/**
* Sets the value of {@link java.util.regex.Pattern#COMMENTS} flag used to compile the regular expression pattern.
*
* @param comments
* The value of {@link java.util.regex.Pattern#COMMENTS} flag.
* @return Instance of this to support fluent API.
* @see java.util.regex.Pattern#compile(String, int)
*/
public RegExpValidator setComments(final boolean comments) {
this.comments = comments;
return this;
}
/**
* Gets the value of {@link java.util.regex.Pattern#CASE_INSENSITIVE} flag used to compile the regular expression pattern.
*
* @return The value of {@link java.util.regex.Pattern#CASE_INSENSITIVE} flag.
* @see java.util.regex.Pattern#compile(String, int)
*/
public boolean isCaseInsensitive() {
return caseInsensitive;
}
/**
* Sets the value of {@link java.util.regex.Pattern#CASE_INSENSITIVE} flag used to compile the regular expression pattern.
*
* @param caseInsensitive
* The value of {@link java.util.regex.Pattern#CASE_INSENSITIVE} flag.
* @return Instance of this to support fluent API.
* @see java.util.regex.Pattern#compile(String, int)
*/
public RegExpValidator setCaseInsensitive(final boolean caseInsensitive) {
this.caseInsensitive = caseInsensitive;
return this;
}
/**
* Gets the value of {@link java.util.regex.Pattern#MULTILINE} flag used to compile the regular expression pattern.
*
* @return The value of {@link java.util.regex.Pattern#MULTILINE} flag.
* @see java.util.regex.Pattern#compile(String, int)
*/
public boolean isMultiline() {
return multiline;
}
/**
* sets the value of {@link java.util.regex.Pattern#MULTILINE} flag used to compile the regular expression pattern.
*
* @param multiline
* The value of {@link java.util.regex.Pattern#MULTILINE} flag.
* @return Instance of this to support fluent API.
* @see java.util.regex.Pattern#compile(String, int)
*/
public RegExpValidator setMultiline(final boolean multiline) {
this.multiline = multiline;
return this;
}
/**
* Gets the value of {@link java.util.regex.Pattern#DOTALL} flag used to compile the regular expression pattern.
*
* @return The value of {@link java.util.regex.Pattern#DOTALL} flag.
* @see java.util.regex.Pattern#compile(String, int)
*/
public boolean isDotall() {
return dotall;
}
/**
* Sets the value of {@link java.util.regex.Pattern#DOTALL} flag used to compile the regular expression pattern.
*
* @param dotall
* The value of {@link java.util.regex.Pattern#DOTALL} flag.
* @return Instance of this to support fluent API.
* @see java.util.regex.Pattern#compile(String, int)
*/
public RegExpValidator setDotall(final boolean dotall) {
this.dotall = dotall;
return this;
}
/**
* Gets the value of {@link java.util.regex.Pattern#UNICODE_CASE} flag used to compile the regular expression pattern.
*
* @return The value of {@link java.util.regex.Pattern#UNICODE_CASE} flag.
* @see java.util.regex.Pattern#compile(String, int)
*/
public boolean isUnicodeCase() {
return unicodeCase;
}
/**
* Sets the value of {@link java.util.regex.Pattern#UNICODE_CASE} flag used to compile the regular expression pattern.
*
* @param unicodeCase
* The value of {@link java.util.regex.Pattern#UNICODE_CASE} flag.
* @return Instance of this to support fluent API.
* @see java.util.regex.Pattern#compile(String, int)
*/
public RegExpValidator setUnicodeCase(final boolean unicodeCase) {
this.unicodeCase = unicodeCase;
return this;
}
/**
* Gets the value of {@link java.util.regex.Pattern#CANON_EQ} flag used to compile the regular expression pattern.
*
* @return The value of {@link java.util.regex.Pattern#CANON_EQ} flag.
* @see java.util.regex.Pattern#compile(String, int)
*/
public boolean isCanonEq() {
return canonEq;
}
/**
* Sets the value of {@link java.util.regex.Pattern#CANON_EQ} flag used to compile the regular expression pattern.
*
* @param canonEq
* The value of {@link java.util.regex.Pattern#CANON_EQ} flag.
* @return Instance of this to support fluent API.
* @see java.util.regex.Pattern#compile(String, int)
*/
public RegExpValidator setCanonEq(final boolean canonEq) {
this.canonEq = canonEq;
return this;
}
/**
* Gets the value of {@link java.util.regex.Pattern#LITERAL} flag used to compile the regular expression pattern.
*
* @return The value of {@link java.util.regex.Pattern#LITERAL} flag.
* @see java.util.regex.Pattern#compile(String, int)
*/
public boolean isLiteral() {
return literal;
}
/**
* Sets the value of {@link java.util.regex.Pattern#LITERAL} flag used to compile the regular expression pattern.
*
* @param literal
* The value of {@link java.util.regex.Pattern#LITERAL} flag.
* @return Instance of this to support fluent API.
* @see java.util.regex.Pattern#compile(String, int)
*/
public RegExpValidator setLiteral(final boolean literal) {
this.literal = literal;
return this;
}
/**
* Gets the value of {@link java.util.regex.Pattern#UNICODE_CHARACTER_CLASS} flag used to compile the regular expression pattern.
*
* @return The value of {@link java.util.regex.Pattern#UNICODE_CHARACTER_CLASS} flag.
* @see java.util.regex.Pattern#compile(String, int)
*/
public boolean isUnicodeCharacterClass() {
return unicodeCharacterClass;
}
/**
* Sets the value of {@link java.util.regex.Pattern#UNICODE_CHARACTER_CLASS} flag used to compile the regular expression pattern.
*
* @param unicodeCharacterClass
* The value of {@link java.util.regex.Pattern#UNICODE_CHARACTER_CLASS} flag.
* @return Instance of this to support fluent API.
* @see java.util.regex.Pattern#compile(String, int)
*/
public RegExpValidator setUnicodeCharacterClass(final boolean unicodeCharacterClass) {
this.unicodeCharacterClass = unicodeCharacterClass;
return this;
}
}