/* Generated By:JJTree: Do not edit this line. MatchCriteria.java Version 4.3 */
/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=true,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
package org.teiid.query.sql.lang;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.teiid.core.util.LRUCache;
import org.teiid.core.util.PropertiesUtils;
import org.teiid.designer.query.sql.lang.IMatchCriteria;
import org.teiid.designer.runtime.version.spi.ITeiidServerVersion;
import org.teiid.query.parser.LanguageVisitor;
import org.teiid.query.sql.symbol.Expression;
import org.teiid.runtime.client.Messages;
import org.teiid.runtime.client.TeiidClientException;
/**
*
*/
public class MatchCriteria extends Criteria
implements PredicateCriteria, IMatchCriteria<Expression, LanguageVisitor> {
/** The internal null escape character */
public static final char NULL_ESCAPE_CHAR = 0;
private static final char DEFAULT_ESCAPE_CHAR = PropertiesUtils.getBooleanProperty(System.getProperties(), "org.teiid.backslashDefaultMatchEscape", false)?'\\':NULL_ESCAPE_CHAR; //$NON-NLS-1$
/** The left-hand expression. */
private Expression leftExpression;
/** The right-hand expression. */
private Expression rightExpression;
private boolean negated;
/** The escape character or '' if there is none */
private char escapeChar = DEFAULT_ESCAPE_CHAR;
private MatchMode mode = MatchMode.LIKE;
/**
* @param p
* @param id
*/
public MatchCriteria(ITeiidServerVersion p, int id) {
super(p, id);
}
/**
* Get left expression.
* @return Left expression
*/
@Override
public Expression getLeftExpression() {
return this.leftExpression;
}
/**
* Set left expression.
* @param expression expression
*/
@Override
public void setLeftExpression(Expression expression) {
this.leftExpression = expression;
}
/**
* Get right expression.
* @return right expression
*/
@Override
public Expression getRightExpression() {
return this.rightExpression;
}
/**
* Set right expression.
* @param expression expression
*/
@Override
public void setRightExpression(Expression expression) {
this.rightExpression = expression;
}
/**
* Returns whether this criteria is negated.
* @return flag indicating whether this criteria contains a NOT
*/
@Override
public boolean isNegated() {
return negated;
}
/**
* Sets the negation flag for this criteria.
* @param negationFlag true if this criteria contains a NOT; false otherwise
*/
@Override
public void setNegated(boolean negationFlag) {
negated = negationFlag;
}
/**
* Get the escape character, which can be placed before the wildcard or single match
* character in the expression to prevent it from being used as a wildcard or single
* match. The escape character must not be used elsewhere in the expression.
* For example, to match "35%" without activating % as a wildcard, set the escape character
* to '$' and use the expression "35$%".
* @return Escape character, if not set will return {@link #NULL_ESCAPE_CHAR}
*/
@Override
public char getEscapeChar() {
return this.escapeChar;
}
/**
* Set the escape character which can be used when the wildcard or single
* character should be used literally.
* @param escapeChar New escape character
*/
@Override
public void setEscapeChar(char escapeChar) {
this.escapeChar = escapeChar;
}
@Override
public MatchMode getMode() {
return mode;
}
/**
* @param mode
*/
public void setMode(MatchMode mode) {
this.mode = mode;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + this.escapeChar;
result = prime * result + ((this.leftExpression == null) ? 0 : this.leftExpression.hashCode());
result = prime * result + ((this.mode == null) ? 0 : this.mode.hashCode());
result = prime * result + (this.negated ? 1231 : 1237);
result = prime * result + ((this.rightExpression == null) ? 0 : this.rightExpression.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!super.equals(obj)) return false;
if (getClass() != obj.getClass()) return false;
MatchCriteria other = (MatchCriteria)obj;
if (this.escapeChar != other.escapeChar) return false;
if (this.leftExpression == null) {
if (other.leftExpression != null) return false;
} else if (!this.leftExpression.equals(other.leftExpression)) return false;
if (this.mode != other.mode) return false;
if (this.negated != other.negated) return false;
if (this.rightExpression == null) {
if (other.rightExpression != null) return false;
} else if (!this.rightExpression.equals(other.rightExpression)) return false;
return true;
}
/** Accept the visitor. **/
@Override
public void acceptVisitor(LanguageVisitor visitor) {
visitor.visit(this);
}
@Override
public MatchCriteria clone() {
MatchCriteria clone = new MatchCriteria(getTeiidVersion(), this.id);
if(getRightExpression() != null)
clone.setRightExpression(getRightExpression().clone());
if(getLeftExpression() != null)
clone.setLeftExpression(getLeftExpression().clone());
if(getMode() != null)
clone.setMode(getMode());
clone.setNegated(isNegated());
clone.setEscapeChar(getEscapeChar());
return clone;
}
private final static LRUCache<List<?>, Pattern> patternCache = new LRUCache<List<?>, Pattern>(100);
/**
* @param newPattern
* @param originalPattern
* @param flags
* @return patter object based on the given parameters
* @throws Exception
*/
public static Pattern getPattern(String newPattern, String originalPattern, int flags) throws Exception {
List<?> key = Arrays.asList(newPattern, flags);
Pattern p = patternCache.get(key);
if (p == null) {
try {
p = Pattern.compile(newPattern, Pattern.DOTALL);
patternCache.put(key, p);
} catch(PatternSyntaxException e) {
throw new TeiidClientException(e, Messages.gs(Messages.TEIID.TEIID30448, new Object[]{originalPattern, e.getMessage()}));
}
}
return p;
}
/**
* <p>Utility to convert the pattern into a different match syntax</p>
*/
public static class PatternTranslator {
private char[] reserved;
private char newEscape;
private char[] toReplace;
private String[] replacements;
private int flags;
private final LRUCache<List<?>, Pattern> cache = new LRUCache<List<?>, Pattern>(100);
/**
* @param toReplace replacement for %
* @param replacements replacement for _
* @param reserved sorted array of reserved chars in the new match syntax
* @param newEscape escape char in the new syntax
* @param flags extra bitwise flags
*/
public PatternTranslator(char[] toReplace, String[] replacements, char[] reserved, char newEscape, int flags) {
this.reserved = reserved;
this.newEscape = newEscape;
this.toReplace = toReplace;
this.replacements = replacements;
this.flags = flags;
}
/**
* @param pattern
* @param escape
* @return translated pattern
* @throws Exception
*/
public Pattern translate(String pattern, char escape) throws Exception {
List<?> key = Arrays.asList(pattern, escape);
Pattern result = null;
synchronized (cache) {
result = cache.get(key);
}
if (result == null) {
String newPattern = getPatternString(pattern, escape);
result = getPattern(newPattern, pattern, flags);
synchronized (cache) {
cache.put(key, result);
}
}
return result;
}
/**
* @param pattern
* @param escape
* @return pattern string based on given pattern
* @throws Exception
*/
public String getPatternString(String pattern, char escape)
throws Exception {
int startChar = 0;
StringBuffer newPattern = new StringBuffer(pattern.length());
if (pattern.length() > 0 && pattern.charAt(0) == '%') {
startChar = 1;
} else {
newPattern.append('^');
}
boolean escaped = false;
boolean endsWithMatchAny = false;
for (int i = startChar; i < pattern.length(); i++) {
char character = pattern.charAt(i);
if (character == escape && character != NULL_ESCAPE_CHAR) {
if (escaped) {
appendCharacter(newPattern, character);
escaped = false;
} else {
escaped = true;
}
} else {
int index = Arrays.binarySearch(toReplace, character);
if (index >= 0) {
if (escaped) {
appendCharacter(newPattern, character);
escaped = false;
} else {
if (character == '%' && i == pattern.length() - 1) {
endsWithMatchAny = true;
continue;
}
newPattern.append(replacements[index]);
}
} else {
if (escaped) {
throw new TeiidClientException(Messages.gs(Messages.TEIID.TEIID30449, new Object[] {pattern, new Character(escape)}));
}
appendCharacter(newPattern, character);
}
}
}
if (escaped) {
throw new TeiidClientException(Messages.gs(Messages.TEIID.TEIID30449, new Object[] {pattern, new Character(escape)}));
}
if (!endsWithMatchAny) {
newPattern.append('$');
}
return newPattern.toString();
}
private void appendCharacter(StringBuffer newPattern, char character) {
if (Arrays.binarySearch(this.reserved, character) >= 0) {
newPattern.append(this.newEscape);
}
newPattern.append(character);
}
}
}
/* JavaCC - OriginalChecksum=0f89c892141b9a7e6acaf4cfc0d222f5 (do not edit this line) */