package hu.sztaki.ilab.longneck.process.constraint; import hu.sztaki.ilab.longneck.Record; import hu.sztaki.ilab.longneck.process.Atomic; import hu.sztaki.ilab.longneck.process.VariableSpace; import hu.sztaki.ilab.longneck.process.block.BlockUtils; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.log4j.Logger; /** * Checks, if the field matches the specified regular expression. * * Matched subgroups can also be checked using contained constraints. The match groups are assigned * to variables $0, $1, $2... and so on, within the match constraint scope. * * @author Molnar Peter <molnarp@sztaki.mta.hu> */ public class MatchConstraint extends AndOperator implements Atomic { private List<String> applyTo; /** The regular expression used in the block. */ protected String regexp; /** A field which contain the the regular expression used in the block. */ protected String regexpfield; /** The matcher object used for matching. */ protected Pattern pattern; @Override public CheckResult check(Record record, VariableSpace scope) { // Prepare result variable List<CheckResult> results = new ArrayList<CheckResult>(applyTo.size()); if(!validatePattern(record, scope)) { results.add(new CheckResult(this, false, null, null, "No regexp value or field defined.")); return new CheckResult(this, false, null, null, null, results); } String details = String.format("Regexp: '%1$s'.", regexp); for (String fieldName : applyTo) { // Get source value String value = BlockUtils.getValue(fieldName, record, scope); if (value == null) { value = ""; } // Match full field value against pattern Matcher m = pattern.matcher(value); if (m.find()) { results.add(new CheckResult(this, true, fieldName, value, details)); } else { results.add(new CheckResult(this, false, fieldName, value, details)); return new CheckResult(this, false, null, null, null, results); } if (m.groupCount() >= 1 && constraints != null && constraints.size() > 0) { // Create match record VariableSpace matchScope = new VariableSpace(scope); for (int i = 0; i <= m.groupCount(); ++i) { scope.setVariable(Integer.toString(i), m.group(i)); } scope.setVariable("groupCount", Integer.toString(m.groupCount())); // Execute constraints on match scope CheckResult parentResults = super.check(record, matchScope); results.add(parentResults); if (! parentResults.isPassed()) { return new CheckResult(this, false, null, null, null, results); } } } return new CheckResult(this, true, null, null, null, results); } protected boolean validatePattern(Record record, VariableSpace parentScope) { if (regexpfield != null) { String regexpfieldvalue = BlockUtils.getValue(regexpfield, record, parentScope); if (regexpfieldvalue == null) { Logger.getLogger(this.getClass().getName()).warn( String.format("The given filed in regexpfield is't exist: fieldname = %1$s!", regexpfield)); return false; } pattern = Pattern.compile(regexpfieldvalue); } return pattern != null; } /** * Sets the regular expression. * * @param regexp The regular expression to execute. */ public void setRegexp (String regexp) { this.regexp = regexp; pattern = Pattern.compile(regexp); } public String getRegexp() { return regexp; } public String getRegexpfield() { return regexpfield; } public void setRegexpfield(String regexpfield) { this.regexpfield = regexpfield; } @Override public void setApplyTo(List<String> fieldNames) { this.applyTo = fieldNames; } public List<String> getApplyTo() { return applyTo; } public void setApplyTo(String applyTo) { // Assign filtered list this.applyTo = BlockUtils.splitIdentifiers(applyTo); } @Override public MatchConstraint clone() { MatchConstraint copy = (MatchConstraint) super.clone(); if (applyTo != null) { copy.applyTo = new ArrayList<String>(applyTo.size()); copy.applyTo.addAll(applyTo); } return copy; } }