jetbrick.web.mvc.router.UrlSegmentMatcher Maven / Gradle / Ivy
/**
* Copyright 2013-2014 Guoqiang Chen, Shanghai, China. All rights reserved.
*
* Email: [email protected]
* URL: http://subchen.github.io/
*
* 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 jetbrick.web.mvc.router;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import jetbrick.commons.JdkVersion;
import jetbrick.commons.lang.StringEscapeUtils;
import jetbrick.commons.lang.WildcharUtils;
import jetbrick.web.mvc.action.PathVariables;
/**
* 按照不同的方式,进行 URL Segment 匹配.
*/
public abstract class UrlSegmentMatcher {
private static final Map cache = new HashMap();
public abstract boolean match(String urlSegment, PathVariables pathVariables);
public static UrlSegmentMatcher create(String urlSegment) {
UrlSegmentMatcher matcher = cache.get(urlSegment);
if (matcher == null) {
matcher = doCreate(urlSegment);
cache.put(urlSegment, matcher);
}
return matcher;
}
private static UrlSegmentMatcher doCreate(String urlSegment) {
int ipos = urlSegment.indexOf('{');
if (ipos != -1) {
if (urlSegment.indexOf(':') != -1) {
return RegexUrlSegmentMatcher.create(urlSegment);
} else if (ipos == 0 && urlSegment.indexOf('}') == urlSegment.length() - 1) {
String name = urlSegment.substring(1, urlSegment.length() - 1);
return new AnyUrlSegmentMatcher(name);
} else {
return RegexUrlSegmentMatcher.create(urlSegment);
}
} else if (urlSegment.indexOf('*') != -1) {
if (urlSegment.length() == 1) {
return new AnyUrlSegmentMatcher("*");
} else {
return new WildcharUrlSegmentMatcher(urlSegment);
}
} else if (urlSegment.indexOf('?') != -1) {
return new WildcharUrlSegmentMatcher(urlSegment);
} else {
return new EqualsUrlSegmentMatcher(urlSegment);
}
}
// 直接 equals 匹配
static final class EqualsUrlSegmentMatcher extends UrlSegmentMatcher {
private final String pattern;
public EqualsUrlSegmentMatcher(String pattern) {
this.pattern = pattern;
}
@Override
public boolean match(String urlSegment, PathVariables pathVariables) {
return pattern.equals(urlSegment);
}
}
// 任意匹配 (*)
static final class AnyUrlSegmentMatcher extends UrlSegmentMatcher {
private final String name;
public AnyUrlSegmentMatcher(String name) {
this.name = name;
}
@Override
public boolean match(String urlSegment, PathVariables pathVariables) {
pathVariables.add(name, urlSegment);
return true;
}
}
// 通配符匹配
static final class WildcharUrlSegmentMatcher extends UrlSegmentMatcher {
private final String pattern;
public WildcharUrlSegmentMatcher(String pattern) {
this.pattern = pattern;
}
@Override
public boolean match(String urlSegment, PathVariables pathVariables) {
return WildcharUtils.match(urlSegment, pattern);
}
}
// 正则表达式匹配
static abstract class RegexUrlSegmentMatcher extends UrlSegmentMatcher {
private static final Pattern PATH_PARAM_PATTERN = Pattern.compile("\\{[^}]+\\}");
public static RegexUrlSegmentMatcher create(String urlSegment) {
if (JdkVersion.IS_AT_LEAST_JAVA_7) {
return new Jdk7RegexUrlSegmentMatcher(urlSegment);
} else {
return new Jdk6RegexUrlSegmentMatcher(urlSegment);
}
}
protected final String toPattern(String urlSegment, List namedGroupList) {
StringBuilder sb = new StringBuilder(urlSegment.length() + 16);
Matcher m = PATH_PARAM_PATTERN.matcher(urlSegment);
int lastpos = 0;
while (m.find()) {
String s = urlSegment.substring(lastpos, m.start());
sb.append(StringEscapeUtils.escapeJavaRegexPattern(s));
String name = m.group(1);
String regex = "[^/]+";
int pos = name.indexOf(':');
if (pos > 0) {
regex = name.substring(pos + 1).trim();
name = name.substring(0, pos).trim();
}
sb.append("(?<").append(name).append('>').append(regex).append(')');
if (namedGroupList != null) {
namedGroupList.add(name);
}
lastpos = m.end() + 1;
}
if (lastpos < urlSegment.length()) {
String s = urlSegment.substring(lastpos);
sb.append(StringEscapeUtils.escapeJavaRegexPattern(s));
}
return sb.toString();
}
}
// 正则表达式匹配(JDK6)
static final class Jdk6RegexUrlSegmentMatcher extends RegexUrlSegmentMatcher {
private final jetbrick.commons.regex.Pattern pattern;
public Jdk6RegexUrlSegmentMatcher(String urlSegment) {
this.pattern = jetbrick.commons.regex.Pattern.compile(toPattern(urlSegment, null));
}
@Override
public boolean match(String urlSegment, PathVariables pathVariables) {
jetbrick.commons.regex.Matcher matcher = pattern.matcher(urlSegment);
if (matcher.matches()) {
for (String name : pattern.groupNames()) {
String value = matcher.group(name);
pathVariables.add(name, value);
}
return true;
}
return false;
}
}
// 正则表达式匹配(JDK7)
static final class Jdk7RegexUrlSegmentMatcher extends RegexUrlSegmentMatcher {
private final Pattern pattern;
private final List namedGroupList;
public Jdk7RegexUrlSegmentMatcher(String urlSegment) {
this.namedGroupList = new ArrayList(8);
this.pattern = Pattern.compile(toPattern(urlSegment, namedGroupList));
}
@Override
public boolean match(String urlSegment, PathVariables pathVariables) {
Matcher matcher = pattern.matcher(urlSegment);
if (matcher.matches()) {
for (String name : namedGroupList) {
String value = matcher.group(name);
pathVariables.add(name, value);
}
return true;
}
return false;
}
}
}