/** * The contents of this file are subject to the Open Software License * Version 3.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.opensource.org/licenses/osl-3.0.txt * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. */ package org.mulgara.query.filter; import org.apache.xerces.impl.xpath.regex.RegularExpression; import org.mulgara.query.QueryException; import org.mulgara.query.filter.value.ValueLiteral; /** * The regular expression test for values. * * @created Mar 8, 2008 * @author Paula Gearon * @copyright © 2008 <a href="mailto:pgearon@users.sourceforge.net">Paula Gearon</a> * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a> */ public class RegexFn extends BinaryTstFilter { /** Generated Serialization ID for RMI */ private static final long serialVersionUID = 6785353529347360357L; /** a cache of the last RegularExpression */ private RegularExpression re = null; /** a cache of the last pattern string */ private String oldPattern = null; /** The expression that resolves flags */ private ValueLiteral flagExpression = null; /** a cache of the last flag string */ private String oldFlags = null; /** * Creates an RegEx test operation with default flags. * @param str The string value to be tested. * @param patternStr The pattern to match the string against. */ public RegexFn(ValueLiteral str, ValueLiteral patternStr) { super(str, patternStr); } /** * Creates an RegEx test operation with specified flags. * @param str The string value to be tested. * @param patternStr The pattern to match the string against. * @param flagExpression The flags to be used in the expression. */ public RegexFn(ValueLiteral str, ValueLiteral patternStr, ValueLiteral flagExpression) { super(str, patternStr); this.flagExpression = flagExpression; if (flagExpression != null) flagExpression.setContextOwner(this); } /** @see org.mulgara.query.filter.BinaryTstFilter#testCmp() */ boolean testCmp() throws QueryException { return regex().matches(str()); } /** * Gets the regular expression to use for the current variable bindings. * This will calculate a new pattern and flags if either change for the current variable bindings. * @return A RegularExpression using the existing object if there was no update. * @throws QueryException If the pattern string or flags string cannot be resolved. */ private RegularExpression regex() throws QueryException { String patternStr = pattern(); String flagsStr = flags(); if (re == null) { re = new RegularExpression(patternStr, flagsStr); oldPattern = patternStr; oldFlags = flagsStr; } else if (!patternStr.equals(oldPattern) || notEquals(flagsStr, oldFlags)) { // re.setPattern(patternStr, flagsStr); // this has a Xerces bug re = new RegularExpression(patternStr, flagsStr); oldPattern = patternStr; oldFlags = flagsStr; } return re; } /** * Gets the string to be matched in this regular expression. * @return The string to be matched against. * @throws QueryException If the expression for the string cannot be resolved. */ private String str() throws QueryException { if (!lhs.isLiteral() || !((ValueLiteral)lhs).isSimple()) throw new QueryException("Type Error: Invalid type in regular expression. Need string, got: " + lhs.getClass().getSimpleName()); return ((ValueLiteral)lhs).getLexical(); } /** * Gets the pattern to use for this regex call. * @return The pattern to use. * @throws QueryException The expression for the pattern cannot be resolved. */ private String pattern() throws QueryException { if (!rhs.isLiteral() || !((ValueLiteral)rhs).isSimple()) throw new QueryException("Type Error: Invalid pattern type in regular expression. Need string, got: " + rhs.getClass().getSimpleName()); return ((ValueLiteral)rhs).getLexical(); } /** * Gets the flags to use for this regex call. * @return The flags to use, or an empty string if none was provided. * @throws QueryException The expression the flags are built on cannot be resolved. */ private String flags() throws QueryException { if (flagExpression == null) return null; if (!flagExpression.isLiteral() || !((ValueLiteral)flagExpression).isSimple()) throw new QueryException("Type Error: Invalid flags in regular expression. Need string, got: " + flagExpression.getClass().getSimpleName()); return flagExpression.getLexical(); } /** * Compares two strings that may be null for inequality. * @param a The first string. * @param b The second string. * @return <code>false</code> if the strings represent the same value, or are both null, * <code>true</code> otherwise. */ private static boolean notEquals(String a, String b) { if (a == null) return b != null; return b == null || !a.equals(b); } }