ratpack.path.internal.DefaultPathBinderBuilder Maven / Gradle / Ivy
/*
* Copyright 2014 the original author or authors.
*
* 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 ratpack.path.internal;
import com.google.common.collect.ImmutableList;
import ratpack.path.PathBinder;
import ratpack.path.PathBinderBuilder;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DefaultPathBinderBuilder implements PathBinderBuilder {
private static final Pattern PLACEHOLDER = Pattern.compile("((?:^|/):(\\w+)\\??:([^/])+)|((?:^|/)::([^/])+)|((?:^|/):(\\w+)\\??)");
private final ImmutableList.Builder tokensBuilder = ImmutableList.builder();
private final StringBuilder pattern = new StringBuilder();
private final StringBuilder description = new StringBuilder();
private boolean addedOptional;
private boolean addedToken;
public PathBinderBuilder tokenWithPattern(String token, String pattern) {
if (addedOptional) {
throw new IllegalArgumentException(String.format("Cannot add mandatory parameter %s after optional parameters", token));
}
addedToken = true;
tokensBuilder.add(token);
this.pattern.append(String.format("(?:(?:^|/)(%s))", pattern));
appendDescriptionSegment(":").append(token).append(":").append(pattern);
return this;
}
public PathBinderBuilder optionalTokenWithPattern(String token, String pattern) {
addedOptional = true;
addedToken = true;
tokensBuilder.add(token);
this.pattern.append(String.format("(?:(?:^|/)(%s))?", pattern));
appendDescriptionSegment(":").append(token).append("?:").append(pattern);
return this;
}
public PathBinderBuilder token(String token) {
if (addedOptional) {
throw new IllegalArgumentException(String.format("Cannot add mandatory parameter %s after optional parameters", token));
}
addedToken = true;
tokensBuilder.add(token);
pattern.append("(?:(?:^|/)([^/?]+))");
appendDescriptionSegment(":").append(token);
return this;
}
public PathBinderBuilder optionalToken(String token) {
addedOptional = true;
addedToken = true;
tokensBuilder.add(token);
pattern.append("(?:(?:^|/)([^/?]*))?");
appendDescriptionSegment(":").append(token).append("?");
return this;
}
public PathBinderBuilder literalPattern(String pattern) {
this.pattern.append("(?:(?:^|/)").append("(?:").append(pattern).append("))");
appendDescriptionSegment("::").append(pattern);
return this;
}
public PathBinderBuilder literal(String literal) {
this.pattern.append("\\Q").append(literal).append("\\E");
this.description.append(literal);
return this;
}
private StringBuilder appendDescriptionSegment(String segment) {
if (description.length() > 0) {
description.append("/");
}
return description.append(segment);
}
public PathBinder build(boolean exhaustive) {
String regex = (addedToken ? "(\\Q\\E" : "(") + pattern + (addedToken ? "\\Q\\E)" : ")") + (exhaustive ? "(?:/|$)" : "(?:/.*)?");
Pattern compiled = Pattern.compile(regex);
return new TokenPathBinder(tokensBuilder.build(), description.toString(), compiled);
}
public static PathBinder parse(String path, boolean exact) {
PathBinderBuilder pathBinderBuilder = new DefaultPathBinderBuilder();
Matcher matchResult = PLACEHOLDER.matcher(path);
int lastIndex = 0;
if (matchResult.find()) {
do {
int thisIndex = matchResult.start();
if (thisIndex != lastIndex) {
pathBinderBuilder.literal(path.substring(lastIndex, thisIndex));
}
lastIndex = matchResult.end();
String component = matchResult.group(0);
boolean found = false;
for (PathTokenType type : PathTokenType.values()) {
if (type.match(component, pathBinderBuilder)) {
found = true;
break;
}
}
if (!found) {
throw new IllegalArgumentException(String.format("Cannot match path %s (%s)", path, component));
}
} while (matchResult.find());
if (lastIndex < path.length()) {
pathBinderBuilder.literal(path.substring(lastIndex));
}
} else {
pathBinderBuilder.literal(path);
}
return pathBinderBuilder.build(exact);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy