Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.cybermkd.route.core.Route Maven / Gradle / Ivy
package com.cybermkd.route.core;
import com.cybermkd.common.Constant;
import com.cybermkd.common.entity.Entity;
import com.cybermkd.common.http.*;
import com.cybermkd.common.http.exception.WebException;
import com.cybermkd.common.http.result.HttpStatus;
import com.cybermkd.common.util.Joiner;
import com.cybermkd.common.util.analysis.ParamAttribute;
import com.cybermkd.common.util.analysis.ParamNamesScaner;
import com.cybermkd.common.util.json.Jsoner;
import com.cybermkd.common.util.json.ModelDeserializer;
import com.cybermkd.common.util.stream.StreamReader;
import com.cybermkd.log.Logger;
import com.cybermkd.route.core.multipart.MultipartBuilder;
import com.cybermkd.route.core.multipart.MultipartParam;
import com.cybermkd.route.exception.InitException;
import com.cybermkd.route.interceptor.Interceptor;
import com.cybermkd.route.render.RenderFactory;
import com.cybermkd.route.valid.Validator;
import com.alibaba.fastjson.JSONObject;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.cybermkd.common.util.Checker.checkArgument;
import static com.cybermkd.common.util.Checker.checkNotNull;
/**
* Created by ice on 14-12-19.
*/
public class Route {
public static final String PARAM_PATTERN = "([^\\/]+)";
private static final Logger logger = Logger.getLogger(Route.class);
private static final PathParserCharProcessor regularCharPathParserCharProcessor = new PathParserCharProcessor() {
public void handle(int curChar, PathPatternParser pathPatternParser) {
if (curChar == '{') {
pathPatternParser.processor = new CurlyBracesPathParamPathParserCharProcessor();
} else if (curChar == ':') {
pathPatternParser.processor = new SimpleColumnBasedPathParamParserCharProcessor();
} else {
pathPatternParser.patternBuilder.appendCodePoint(curChar);
pathPatternParser.stdPathPatternBuilder.appendCodePoint(curChar);
}
}
public void end(PathPatternParser pathPatternParser) {
}
};
private final String httpMethod;
private final String pathPattern;
private final String stdPathPattern;
private final Pattern pattern;
private final List pathParamNames;
private final Class extends Resource> resourceClass;
private final Method method;
private final List allParamNames;
private final int[] allLineNumbers;
private final List> allParamTypes;
private final List allGenericParamTypes;
private final Interceptor[] interceptors;
private final int[][] interceptorsLineNumbers;
private final Validator[] validators;
private final int[][] validsLineNumbers;
private final MultipartBuilder multipartBuilder;
private final Map headers;
public Route(Class extends Resource> resourceClass, ParamAttribute paramAttribute, String httpMethod, String pathPattern, Method method, Interceptor[] interceptors, String des, Validator[] validators, MultipartBuilder multipartBuilder, Map headers) {
this.resourceClass = resourceClass;
this.httpMethod = checkNotNull(httpMethod);
this.pathPattern = checkNotNull(pathPattern);
this.method = method;
this.multipartBuilder = multipartBuilder;
this.interceptors = interceptors;
this.allParamNames = paramAttribute.getNames();
this.allLineNumbers = paramAttribute.getLines();
this.allParamTypes = Arrays.asList(method.getParameterTypes());
this.allGenericParamTypes = Arrays.asList(method.getGenericParameterTypes());
this.validators = validators;
this.headers = headers;
//获取拦截器的行号
if (Constant.showRoute) {
this.interceptorsLineNumbers = new int[interceptors.length][];
//获取参数
ParamAttribute paramAttr;
int i = 0;
for (Interceptor interceptor : interceptors) {
try {
paramAttr = ParamNamesScaner.getParamNames(interceptor.getClass().getMethod("intercept", RouteInvocation.class));
} catch (NoSuchMethodException e) {
throw new InitException(e.getMessage(), e);
}
this.interceptorsLineNumbers[i] = paramAttr.getLines();
i++;
}
//验证器
this.validsLineNumbers = new int[validators.length][];
i = 0;
for (Validator validator : validators) {
try {
paramAttr = ParamNamesScaner.getParamNames(validator.getClass().getMethod("validate", Params.class, RouteMatch.class));
} catch (NoSuchMethodException e) {
throw new InitException(e.getMessage(), e);
}
this.validsLineNumbers[i] = paramAttr.getLines();
i++;
}
} else {
this.validsLineNumbers = null;
this.interceptorsLineNumbers = null;
}
PathPatternParser s = new PathPatternParser(pathPattern);
s.parse();
this.pattern = Pattern.compile(s.patternBuilder.toString());
this.stdPathPattern = s.stdPathPatternBuilder.toString();
this.pathParamNames = s.pathParamNames;
//check arguments
for (String pName : pathParamNames) {
if (!allParamNames.contains(pName)) {
throw new IllegalArgumentException("PathParameter '" + pName + "' could not found in method arguments at " + resourceClass.getName() + "(" + resourceClass.getSimpleName() + ".java:" + allLineNumbers[0] + ")");
}
}
if (logger.isInfoEnabled()) {
//print route
StringBuilder sb = new StringBuilder("\n\nBuild route ----------------- ").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())).append(" ------------------------------");
sb.append("\nResource : ").append(resourceClass.getName()).append("(").append(resourceClass.getSimpleName()).append(".java:").append(allLineNumbers[0]).append(")");
sb.append("\nMethod : ").append(method.getName());
sb.append("\nPathPattern : ").append(httpMethod).append(" ").append(pathPattern);
//print params
StringBuilder sbPath = new StringBuilder("\nPathParams : ");
StringBuilder sbOther = new StringBuilder("\nOtherParams : ");
int pSize = allParamNames.size();
String pName;
if (pSize > 0) {
for (int i = 0; i < pSize; i++) {
pName = allParamNames.get(i);
if (pathParamNames.contains(pName)) {
sbPath.append(pName).append("(").append(allGenericParamTypes.get(i)).append(") ");
} else {
sbOther.append(pName).append("(").append(allGenericParamTypes.get(i)).append(") ");
}
}
}
sb.append(sbPath).append(sbOther);
Type returnType = method.getGenericReturnType();
sb.append("\nReturnType : ").append(returnType);
sb.append("\nDescriptions : ").append(des);
if (validators != null && validators.length > 0 && validsLineNumbers != null) {
sb.append("\nValidators : ");
int i = 0;
for (Validator validator : validators) {
if (i > 0)
sb.append("\n ");
Class extends Validator> vc = validator.getClass();
sb.append(vc.getName()).append("(").append(vc.getSimpleName()).append(".java:").append(validsLineNumbers[i][0]).append(")");
i++;
}
}
if (interceptors != null && interceptors.length > 0 && interceptorsLineNumbers != null) {
sb.append("\nInterceptors : ");
int i = 0;
for (Interceptor interceptor : interceptors) {
if (i > 0) {
sb.append("\n ");
}
Class extends Interceptor> ic = interceptor.getClass();
sb.append(ic.getName()).append("(").append(ic.getSimpleName()).append(".java:").append(interceptorsLineNumbers[i][0]).append(")");
i++;
}
}
sb.append("\n--------------------------------------------------------------------------------\n");
logger.info(sb.toString());
}
}
/**
* 匹配路由
*
* @param request request对象
* @param response response对象
* @return route
*/
public RouteMatch match(HttpRequest request, HttpResponse response) {
if (!this.httpMethod.equals(request.getHttpMethod())) {
return null;
}
String restPath = request.getRestPath();
String extension = "";
if (restPath.contains(".")) {
int index = restPath.lastIndexOf(".");
extension = restPath.substring(index + 1);
if (RenderFactory.contains(extension)) {
restPath = restPath.substring(0, index);
} else {
extension = "";
}
}
Matcher m = pattern.matcher(restPath);
if (!m.matches()) {
return null;
}
if (headers.size() > 0) {
for (Map.Entry headersEntry : headers.entrySet()) {
if (!headersEntry.getValue().equals(request.getHeader(headersEntry.getKey()))) {
return null;
}
}
}
//pathParams
Map pathParams = new HashMap();
for (int i = 0; i < m.groupCount() && i < pathParamNames.size(); i++) {
pathParams.put(pathParamNames.get(i), m.group(i + 1));
}
//formParams
Map> formParams = null;
//有文件上传
MultipartParam multipartParam = null;
if (multipartBuilder != null) {
multipartParam = multipartBuilder.readMultipart(request);
}
RouteMatch routeMatch = null;
Params params = null;
Map fileParams = null;
String jsonParams = null;
String contentType = request.getContentType();
try {
if (contentType != null && contentType.toLowerCase().contains(ContentType.JSON.value())) {
//从 queryString 取json
String queryString = request.getQueryString();
if (queryString != null && (httpMethod.equals(HttpMethod.GET) || httpMethod.equals(HttpMethod.DELETE)) && Jsoner.isJson(queryString)) {
jsonParams = queryString;
} else {
jsonParams = getJson(request);
formParams = request.getQueryParams();
}
printMatchRoute(request.getContentType(), jsonParams, pathParams, formParams, null);
params = parseJsonParams(jsonParams, pathParams, formParams);
} else {
formParams = request.getQueryParams();
//print match route
if (multipartParam != null) {
fileParams = multipartParam.getUploadedFiles();
if (formParams != null) {
formParams.putAll(multipartParam.getParams());
} else {
formParams = multipartParam.getParams();
}
printMatchRoute(request.getContentType(), null, pathParams, formParams, fileParams);
params = parseFormParams(pathParams, formParams, fileParams);
} else {
printMatchRoute(request.getContentType(), null, pathParams, formParams, null);
params = parseFormParams(pathParams, formParams, new Hashtable());
}
}
} catch (Exception e) {
printMatchRoute(request.getContentType(), jsonParams, pathParams, formParams, fileParams);
throwException(e);
}
routeMatch = new RouteMatch(pathPattern, restPath, extension, params, request, response);
return routeMatch;
}
/**
* 打印route信息
*
* @param pathParams path参数
* @param formParams 其他参数
* @param fileParams 文件参数
*/
private void printMatchRoute(String contentType, String jsonParams, Map pathParams, Map> formParams, Map fileParams) {
if (Constant.showRoute && logger.isInfoEnabled()) {
//print route
StringBuilder sb = new StringBuilder("\n\nMatch route ----------------- ").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())).append(" ------------------------------");
sb.append("\nResource : ").append(resourceClass.getName()).append("(").append(resourceClass.getSimpleName()).append(".java:" + allLineNumbers[0] + ")");
sb.append("\nMethod : ").append(method.getName());
sb.append("\nPathPattern : ").append(httpMethod).append(" ").append(pathPattern);
sb.append("\nContentType : ").append(contentType);
//print pathParams
sb.append("\nPathParams : ");
if (pathParams != null && pathParams.size() > 0) {
Set> paramsEntrySet = pathParams.entrySet();
for (Map.Entry paramsEntry : paramsEntrySet) {
sb.append(paramsEntry.getKey()).append(" = {").append(paramsEntry.getValue()).append("}");
sb.append(" ");
}
}
//print formParams
if (formParams != null && formParams.size() > 0) {
sb.append("\nFormParams : ");
List values;
Set>> formParamsEntrySet = formParams.entrySet();
for (Map.Entry> formParamsEntry : formParamsEntrySet) {
values = formParamsEntry.getValue();
if (values.size() >= 1) {
sb.append(formParamsEntry.getKey()).append(" = {").append(values.get(0)).append("}");
}
sb.append(" ");
}
}
//print jsonParams
if (jsonParams != null) {
sb.append("\nJsonParams : ").append(jsonParams);
}
//print fileParams
if (fileParams != null && fileParams.size() > 0) {
sb.append("\nFileParams : ");
UploadedFile value;
Set> fileParamsEntrySet = fileParams.entrySet();
for (Map.Entry fileParamsEntry : fileParamsEntrySet) {
value = fileParamsEntry.getValue();
sb.append(fileParamsEntry.getKey()).append(" = {").append(value.getOriginalFileName()).append("(").append(value.getContentType()).append(")}");
sb.append(" ");
}
}
Type returnType = method.getGenericReturnType();
sb.append("\nReturnType : ").append(returnType);
if (validators != null && validators.length > 0) {
sb.append("\nValidators : ");
int i = 0;
for (Validator validator : validators) {
if (i > 0)
sb.append("\n ");
Class extends Validator> vc = validator.getClass();
sb.append(vc.getName()).append("(").append(vc.getSimpleName()).append(".java:").append(validsLineNumbers[i][0]).append(")");
i++;
}
}
if (interceptors != null && interceptors.length > 0) {
sb.append("\nInterceptors : ");
int i = 0;
for (Interceptor interceptor : interceptors) {
if (i > 0) {
sb.append("\n ");
}
Class extends Interceptor> ic = interceptor.getClass();
sb.append(ic.getName()).append("(").append(ic.getSimpleName()).append(".java:").append(interceptorsLineNumbers[i][0]).append(")");
i++;
}
}
sb.append("\n--------------------------------------------------------------------------------\n");
logger.info(sb.toString());
}
}
public String toString() {
return httpMethod + " " + pathPattern + " " + Joiner.on(",").join(allParamNames);
}
public Class extends Resource> getResourceClass() {
return resourceClass;
}
public Method getMethod() {
return method;
}
public String getHttpMethod() {
return httpMethod;
}
public String getPattern() {
return pattern.pattern();
}
public String getPathPattern() {
return pathPattern;
}
public String getStdPathPattern() {
return stdPathPattern;
}
public List getPathParamNames() {
return pathParamNames;
}
public List getAllParamNames() {
return allParamNames;
}
public List> getAllParamTypes() {
return allParamTypes;
}
public List getAllGenericParamTypes() {
return allGenericParamTypes;
}
public Interceptor[] getInterceptors() {
return interceptors;
}
public Validator[] getValidators() {
return validators;
}
public int[] getAllLineNumbers() {
return allLineNumbers;
}
// here comes the path pattern parsing logic
// the code is pretty ugly with lot of cross dependencies, I tried to keep it performant, correct, and maintainable
// not sure those goals are all achieved though
public MultipartBuilder getMultipartBuilder() {
return multipartBuilder;
}
public Map getHeaders() {
return headers;
}
/**
* 抛出异常
*
* @param throwable
*/
public void throwException(Throwable throwable) {
if (throwable instanceof WebException) {
throw (WebException) throwable;
} else {
WebException exception = getWebException(throwable, 0);
Throwable cause = throwable.getCause();
if (cause != null) {
logger.error("Route method invoke error.", cause);
} else {
logger.error("Route method invoke error.", throwable);
}
throw exception;
}
}
private WebException getWebException(Throwable throwable, int deep) {
WebException result = null;
String message = throwable.getMessage();
if (message == null) {
Throwable cause = throwable.getCause();
if (cause != null) {
if (cause instanceof WebException) {
result = (WebException) cause;
} else {
message = cause.getMessage();
if (message == null && !throwable.equals(cause) && deep < 100) {
result = getWebException(cause, ++deep);
}
}
}
} else {
if (throwable instanceof WebException) {
result = (WebException) throwable;
}
}
if (result == null) {
result = new WebException(HttpStatus.INTERNAL_SERVER_ERROR, message);
}
return result;
}
/**
* 获取json字符串
*
* @param request
* @return
*/
private String getJson(HttpRequest request) {
String json = null;
try {
InputStream is = request.getContentStream();
if (is != null) {
json = StreamReader.readString(is);
}
} catch (IOException e) {
String msg = "Could not read inputStream when contentType is '" + request.getContentType() + "'.";
logger.error(msg, e);
throw new WebException(msg);
}
return json;
}
/**
* 获取所有的请求参数
*
* @return 所有参数
*/
private Params parseFormParams(Map pathParams, Map> formParams, Map fileParams) throws IllegalAccessException, InstantiationException {
Params params = new Params();
int i = 0;
Class paramType = null;
List valueArr = null;
//判断范型类型
Type[] typeArguments;
Class keyTypeClass;
Class valueTypeClass;
for (String name : allParamNames) {
paramType = allParamTypes.get(i);
//path里的参数
if (pathParamNames.contains(name)) {
if (paramType == String.class) {
params.set(name, pathParams.get(name));
} else
params.set(name, ModelDeserializer.parse(pathParams.get(name), paramType));
} else {//其他参数
if (paramType == UploadedFile.class) {
params.set(name, fileParams.remove(name));
} else if (paramType == Map.class) {
typeArguments = ((ParameterizedType) allGenericParamTypes.get(i)).getActualTypeArguments();
if (typeArguments.length >= 2) {
keyTypeClass = (Class) typeArguments[0];
valueTypeClass = (Class) typeArguments[1];
if (keyTypeClass == String.class && valueTypeClass == UploadedFile.class) {
params.set(name, fileParams);
} else {
valueArr = formParams.remove(name);
params.set(name, parseString(paramType, valueArr));
}
} else {
valueArr = formParams.remove(name);
params.set(name, parseString(paramType, valueArr));
}
} else {
valueArr = formParams.remove(name);
params.set(name, parseString(paramType, valueArr));
}
}
i++;
}
String name;
if (formParams.size() > 0) {
for (Map.Entry> formEntry : formParams.entrySet()) {
name = formEntry.getKey();
if (!params.containsName(name)) {
valueArr = formEntry.getValue();
if (valueArr != null && valueArr.size() > 0) {
params.set(name, valueArr.get(0));
} else {
params.set(name, null);
}
}
}
}
if (fileParams.size() > 0) {
for (Map.Entry fileEntry : fileParams.entrySet()) {
name = fileEntry.getKey();
if (!params.containsName(name)) {
params.set(fileEntry.getKey(), fileEntry.getValue());
}
}
}
return params;
}
/**
* 转换string类型参数
*
* @param paramType
* @param valueArr
*/
private Object parseString(Class paramType, List valueArr) throws InstantiationException, IllegalAccessException {
String value;
Object result = null;
if (valueArr != null && valueArr.size() > 0) {
//不支持数组参数
value = valueArr.get(0);
if (paramType == String.class) {
result = value;
} else {
//转换为对应的对象类型
result = ModelDeserializer.parse(value, paramType);
}
}
return result;
}
/**
* 获取所有以application/json方式提交的数据
*
* @param json json字符串
* @return 所有参数
*/
private Params parseJsonParams(String json, Map pathParams, Map> formParams) throws IllegalAccessException, InstantiationException {
Params params = new Params();
int i = 0;
Class paramType = null;
//只有一个参数时 直接把该参数 放入方法
boolean oneParamParse = false;
int paramSize = allParamNames.size() - pathParamNames.size();
if (Constant.oneParamParse) {
oneParamParse = paramSize == 1;
}
Object obj = null;
List valueArr = null;
boolean hasJsonParam = null != json && !"".equals(json);
Object receiveParams = null;
if (hasJsonParam && !oneParamParse) {
if (json.startsWith("\"") || json.startsWith("{") || json.startsWith("[")) {
receiveParams = Jsoner.toObject(json);
} else {
receiveParams = Jsoner.toObject("\"" + json + "\"");
}
hasJsonParam = receiveParams != null;
}
for (String name : allParamNames) {
paramType = allParamTypes.get(i);
//path里的参数
if (pathParamNames.contains(name)) {
if (paramType == String.class) {
params.set(name, pathParams.get(name));
} else {
params.set(name, Jsoner.toObject(pathParams.get(name), paramType));
}
} else {//其他参数
if (hasJsonParam) {
if (oneParamParse) {
//转换对象到指定的类型
params.set(name, parse(allGenericParamTypes.get(i), paramType, ModelDeserializer.parse(json, paramType)));
} else {
if (receiveParams instanceof Map) {
obj = ((Map) receiveParams).remove(name);
if (obj != null) {
if (paramType == String.class) {
params.set(name, obj.toString());
} else {
//转换对象到指定的类型
params.set(name, parse(allGenericParamTypes.get(i), paramType, obj));
}
}
}
}
}
//没有获取到的参数设置为空
if (!params.containsName(name)) {
if (formParams != null && formParams.size() > 0) {
valueArr = formParams.remove(name);
}
params.set(name, parseString(paramType, valueArr));
}
}
i++;
}
String name;
if (hasJsonParam && receiveParams instanceof Map && !oneParamParse) {
for (Map.Entry receiveEntry : ((Map) receiveParams).entrySet()) {
name = receiveEntry.getKey();
if (!params.containsName(name)) {
params.set(receiveEntry.getKey(), receiveEntry.getValue());
}
}
}
if (formParams != null && formParams.size() > 0) {
for (Map.Entry> formEntry : formParams.entrySet()) {
name = formEntry.getKey();
if (!params.containsName(name)) {
valueArr = formEntry.getValue();
if (valueArr != null && valueArr.size() > 0) {
params.set(name, valueArr.get(0));
} else {
params.set(name, null);
}
}
}
}
return params;
}
/**
* 把参数转到对应的类型
*
* @param paramType
* @param obj
*/
private Object parse(Type genericParamType, Class paramType, Object obj) throws InstantiationException, IllegalAccessException {
Class keyTypeClass;
Class paramTypeClass;
List list;
List newlist;
List blist;
List newblist;
Set set;
Set newset;
Set bset;
Set newbset;
Map map;
Set> mapEntry;
Map newMap;
Object result = null;
if (obj != null) {
if (Map.class.isAssignableFrom(paramType)) {
keyTypeClass = (Class) ((ParameterizedType) genericParamType).getActualTypeArguments()[0];
paramTypeClass = (Class) ((ParameterizedType) genericParamType).getActualTypeArguments()[1];
map = (Map) obj;
newMap = new HashMap();
mapEntry = map.entrySet();
for (Map.Entry entry : mapEntry) {
newMap.put(ModelDeserializer.parse(entry.getKey(), keyTypeClass), ModelDeserializer.parse(entry.getValue(), paramTypeClass));
}
result = newMap;
} else if (Collection.class.isAssignableFrom(paramType)) {
paramTypeClass = (Class) ((ParameterizedType) genericParamType).getActualTypeArguments()[0];
if (List.class.isAssignableFrom(paramType)) {
//Entity类型
if (Entity.class.isAssignableFrom(paramTypeClass)) {
list = (List) obj;
newlist = new ArrayList();
for (JSONObject jo : list) {
newlist.add(ModelDeserializer.deserialze(jo, paramTypeClass));
}
result = newlist;
} else {
blist = (List) obj;
if (String.class == paramTypeClass) {
newblist = new ArrayList();
for (Object o : blist) {
newblist.add(o.toString());
}
} else {
newblist = new ArrayList();
for (Object o : blist) {
if (paramTypeClass.isAssignableFrom(o.getClass())) {
newblist.add(o);
} else {
newblist.add(ModelDeserializer.parse(o, paramTypeClass));
}
}
}
result = newblist;
}
} else if (Set.class.isAssignableFrom(paramType)) {
//Entity
if (Entity.class.isAssignableFrom(paramTypeClass)) {
set = (Set) obj;
newset = new HashSet();
for (JSONObject jo : set) {
newset.add(ModelDeserializer.deserialze(jo, paramTypeClass));
}
result = newset;
} else {
bset = (Set) obj;
if (String.class == paramTypeClass) {
newbset = new HashSet();
for (Object o : bset) {
newbset.add(o.toString());
}
} else {
newbset = new HashSet();
for (Object o : bset) {
if (paramTypeClass.isAssignableFrom(o.getClass())) {
newbset.add(o);
} else {
newbset.add(ModelDeserializer.parse(o, paramTypeClass));
}
}
}
result = newbset;
}
}
} else {
result = ModelDeserializer.parse(obj, paramType);
}
}
return result;
}
private static interface PathParserCharProcessor {
void handle(int curChar, PathPatternParser pathPatternParser);
void end(PathPatternParser pathPatternParser);
}
private static final class PathPatternParser {
final int length;
final String pathPattern;
int offset = 0;
PathParserCharProcessor processor = regularCharPathParserCharProcessor;
List pathParamNames = new ArrayList();
StringBuilder patternBuilder = new StringBuilder();
StringBuilder stdPathPatternBuilder = new StringBuilder();
private PathPatternParser(String pathPattern) {
this.length = pathPattern.length();
this.pathPattern = pathPattern;
}
void parse() {
while (offset < length) {
int curChar = pathPattern.codePointAt(offset);
processor.handle(curChar, this);
offset += Character.charCount(curChar);
}
processor.end(this);
}
}
private static final class CurlyBracesPathParamPathParserCharProcessor implements PathParserCharProcessor {
private int openBr = 1;
private boolean inRegexDef;
private StringBuilder pathParamName = new StringBuilder();
private StringBuilder pathParamRegex = new StringBuilder();
public void handle(int curChar, PathPatternParser pathPatternParser) {
if (curChar == '}') {
openBr--;
if (openBr == 0) {
// found matching brace, end of path param
if (pathParamName.length() == 0) {
// it was a mere {}, can't be interpreted as a path param
pathPatternParser.processor = regularCharPathParserCharProcessor;
pathPatternParser.patternBuilder.append("{}");
pathPatternParser.stdPathPatternBuilder.append("{}");
return;
}
// only the opening paren
checkArgument(pathParamRegex.length() != 1, "illegal path parameter definition '%s' at offset %d - custom regex must not be empty",
pathPatternParser.pathPattern, pathPatternParser.offset);
if (pathParamRegex.length() == 0) {
// use default regex
pathParamRegex.append(PARAM_PATTERN);
} else {
// close paren for matching group
pathParamRegex.append(")");
}
pathPatternParser.processor = regularCharPathParserCharProcessor;
pathPatternParser.patternBuilder.append(pathParamRegex);
pathPatternParser.stdPathPatternBuilder.append("{").append(pathParamName).append("}");
pathPatternParser.pathParamNames.add(pathParamName.toString());
return;
}
} else if (curChar == '{') {
openBr++;
}
if (inRegexDef) {
pathParamRegex.appendCodePoint(curChar);
} else {
if (curChar == ':') {
// we were in path name, the column marks the separator with the regex definition, we go in regex mode
inRegexDef = true;
pathParamRegex.append("(");
} else {
//only letters are authorized in path param name
checkArgument(Character.isLetterOrDigit(curChar), "illegal path parameter definition '%s' at offset %d" +
" - only letters and digits are authorized in path param name",
pathPatternParser.pathPattern, pathPatternParser.offset);
pathParamName.appendCodePoint(curChar);
}
}
}
public void end(PathPatternParser pathPatternParser) {
}
}
private static final class SimpleColumnBasedPathParamParserCharProcessor implements PathParserCharProcessor {
private StringBuilder pathParamName = new StringBuilder();
public void handle(int curChar, PathPatternParser pathPatternParser) {
// if (!Character.isLetterOrDigit(curChar) && curChar != '_') {
if (curChar == '/') {
pathPatternParser.patternBuilder.append(PARAM_PATTERN);
pathPatternParser.stdPathPatternBuilder.append("{").append(pathParamName).append("}");
pathPatternParser.pathParamNames.add(pathParamName.toString());
pathPatternParser.processor = regularCharPathParserCharProcessor;
pathPatternParser.processor.handle(curChar, pathPatternParser);
} else {
pathParamName.appendCodePoint(curChar);
}
}
public void end(PathPatternParser pathPatternParser) {
pathPatternParser.patternBuilder.append(PARAM_PATTERN);
pathPatternParser.stdPathPatternBuilder.append("{").append(pathParamName).append("}");
pathPatternParser.pathParamNames.add(pathParamName.toString());
}
}
}