blob: 06db3796e40d6e181b931a773ff8912683918d0e [file] [log] [blame]
// ***************************************************************************************************************************
// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *
// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *
// * to you 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.apache.juneau.pojotools;
import static org.apache.juneau.internal.StringUtils.*;
import java.util.*;
import java.util.regex.*;
import org.apache.juneau.*;
import org.apache.juneau.internal.*;
/**
* TODO
*
*/
public class StringMatcherFactory extends MatcherFactory {
/**
* Default reusable matcher.
*/
public static final StringMatcherFactory DEFAULT = new StringMatcherFactory();
@Override
public boolean canMatch(ClassMeta<?> cm) {
return true;
}
@Override
public Matcher create(String pattern) {
return new StringMatcher(pattern);
}
/**
* A construct representing a single search pattern.
*/
private static class StringMatcher extends Matcher {
private String pattern;
private static final AsciiSet
META_CHARS = AsciiSet.create("*?'\""),
SQ_CHAR = AsciiSet.create("'"),
DQ_CHAR = AsciiSet.create("\""),
REGEX_CHARS = AsciiSet.create("+\\[]{}()^$.");
Pattern[] orPatterns, andPatterns, notPatterns;
public StringMatcher(String searchPattern) {
this.pattern = searchPattern.trim();
List<Pattern> ors = new LinkedList<>();
List<Pattern> ands = new LinkedList<>();
List<Pattern> nots = new LinkedList<>();
for (String s : splitQuoted(pattern, true)) {
char c0 = s.charAt(0), c9 = s.charAt(s.length()-1);
if (c0 == '/' && c9 == '/' && s.length() > 1) {
ands.add(Pattern.compile(strip(s)));
} else {
char prefix = '^';
boolean ignoreCase = false;
if (s.length() > 1 && (c0 == '^' || c0 == '+' || c0 == '-')) {
prefix = c0;
s = s.substring(1);
c0 = s.charAt(0);
}
if (c0 == '\'') {
s = unEscapeChars(strip(s), SQ_CHAR);
ignoreCase = true;
} else if (c0 == '"') {
s = unEscapeChars(strip(s), DQ_CHAR);
}
if (REGEX_CHARS.contains(s) || META_CHARS.contains(s)) {
StringBuilder sb = new StringBuilder();
boolean isInEscape = false;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (isInEscape) {
if (c == '?' || c == '*' || c == '\\')
sb.append('\\').append(c);
else
sb.append(c);
isInEscape = false;
} else {
if (c == '\\')
isInEscape = true;
else if (c == '?')
sb.append(".?");
else if (c == '*')
sb.append(".*");
else if (REGEX_CHARS.contains(c))
sb.append("\\").append(c);
else
sb.append(c);
}
}
s = sb.toString();
}
int flags = Pattern.DOTALL;
if (ignoreCase)
flags |= Pattern.CASE_INSENSITIVE;
Pattern p = Pattern.compile(s, flags);
if (prefix == '-')
nots.add(p);
else if (prefix == '+')
ands.add(p);
else
ors.add(p);
}
}
orPatterns = ors.toArray(new Pattern[ors.size()]);
andPatterns = ands.toArray(new Pattern[ands.size()]);
notPatterns = nots.toArray(new Pattern[nots.size()]);
}
@Override
public boolean matches(ClassMeta<?> cm, Object o) {
String s = (String)o;
for (int i = 0; i < andPatterns.length; i++)
if (! andPatterns[i].matcher(s).matches())
return false;
for (int i = 0; i < notPatterns.length; i++)
if (notPatterns[i].matcher(s).matches())
return false;
for (int i = 0; i < orPatterns.length; i++)
if (orPatterns[i].matcher(s).matches())
return true;
return orPatterns.length == 0;
}
@Override
public String toString() {
return pattern;
}
}
}