package io.micronaut.web.router;
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.convert.ConversionService;
import io.micronaut.core.type.Argument;
import io.micronaut.core.util.CollectionUtils;
import io.micronaut.http.HttpMethod;
import io.micronaut.http.uri.UriMatchInfo;
import io.micronaut.http.uri.UriMatchVariable;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
@Internal
class DefaultUriRouteMatch<T, R> extends AbstractRouteMatch<T, R> implements UriRouteMatch<T, R> {
private final HttpMethod httpMethod;
private final UriMatchInfo matchInfo;
private final DefaultRouteBuilder.DefaultUriRoute uriRoute;
private final Charset defaultCharset;
DefaultUriRouteMatch(UriMatchInfo matchInfo,
DefaultRouteBuilder.DefaultUriRoute uriRoute,
Charset defaultCharset, ConversionService<?> conversionService
) {
super(uriRoute, conversionService);
this.uriRoute = uriRoute;
this.matchInfo = matchInfo;
this.httpMethod = uriRoute.httpMethod;
this.defaultCharset = defaultCharset;
}
@Override
public UriRouteMatch<T, R> decorate(Function<RouteMatch<R>, R> executor) {
Map<String, Object> variables = getVariableValues();
List<Argument> arguments = getRequiredArguments();
RouteMatch thisRoute = this;
return new DefaultUriRouteMatch<T, R>(matchInfo, uriRoute, defaultCharset, conversionService) {
@Override
public List<Argument> getRequiredArguments() {
return arguments;
}
@Override
public R execute(Map argumentValues) {
return (R) executor.apply(thisRoute);
}
@Override
public Map<String, Object> getVariableValues() {
return variables;
}
};
}
@Override
protected RouteMatch<R> newFulfilled(Map<String, Object> newVariables, List<Argument> requiredArguments) {
return new DefaultUriRouteMatch<T, R>(matchInfo, uriRoute, defaultCharset, conversionService) {
@Override
public List<Argument> getRequiredArguments() {
return requiredArguments;
}
@Override
public Map<String, Object> getVariableValues() {
return newVariables;
}
};
}
@Override
public UriRouteMatch<T, R> fulfill(Map<String, Object> argumentValues) {
return (UriRouteMatch<T, R>) super.fulfill(argumentValues);
}
@Override
public String getUri() {
return matchInfo.getUri();
}
@Override
public Map<String, Object> getVariableValues() {
Map<String, Object> variables = matchInfo.getVariableValues();
if (CollectionUtils.isNotEmpty(variables)) {
final String charset = defaultCharset.toString();
Map<String, Object> decoded = new LinkedHashMap<>(variables.size());
variables.forEach((k, v) -> {
if (v instanceof CharSequence) {
try {
v = URLDecoder.decode(v.toString(), charset);
} catch (UnsupportedEncodingException e) {
}
}
decoded.put(k, v);
});
return decoded;
}
return variables;
}
@Override
public List<UriMatchVariable> getVariables() {
return matchInfo.getVariables();
}
@Override
public Map<String, UriMatchVariable> getVariableMap() {
return matchInfo.getVariableMap();
}
@Override
public UriRoute getRoute() {
return (UriRoute) abstractRoute;
}
@Override
public HttpMethod getHttpMethod() {
return httpMethod;
}
@Override
public String toString() {
return httpMethod + " - " + matchInfo.getUri();
}
}