/*
* Copyright 2015 The Netty Project
*
* The Netty Project 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 io.netty.handler.codec.http.router;
/**
* Router that contains information about route matching orders, but doesn't
* contain information about HTTP request methods.
*
* Routes are devided into 3 sections: "first", "last", and "other".
* Routes in "first" are matched first, then in "other", then in "last".
*/
final class MethodlessRouter<T> {
private final OrderlessRouter<T> first = new OrderlessRouter<T>();
private final OrderlessRouter<T> other = new OrderlessRouter<T>();
private final OrderlessRouter<T> last = new OrderlessRouter<T>();
//--------------------------------------------------------------------------
/** Returns the "first" router; routes in this router will be matched first. */
public OrderlessRouter<T> first() {
return first;
}
/**
* Returns the "other" router; routes in this router will be matched after
* those in the "first" router, but before those in the "last" router.
*/
public OrderlessRouter<T> other() {
return other;
}
/** Returns the "last" router; routes in this router will be matched last. */
public OrderlessRouter<T> last() {
return last;
}
/** Returns the number of routes in this router. */
public int size() {
return first.routes().size() + other.routes().size() + last.routes().size();
}
//--------------------------------------------------------------------------
/**
* Adds route to the "first" section.
*
* A path can only point to one target. This method does nothing if the path
* has already been added.
*/
public MethodlessRouter<T> addRouteFirst(String path, T target) {
first.addRoute(path, target);
return this;
}
/**
* Adds route to the "other" section.
*
* A path can only point to one target. This method does nothing if the path
* has already been added.
*/
public MethodlessRouter<T> addRoute(String path, T target) {
other.addRoute(path, target);
return this;
}
/**
* Adds route to the "last" section.
*
* A path can only point to one target. This method does nothing if the path
* has already been added.
*/
public MethodlessRouter<T> addRouteLast(String path, T target) {
last.addRoute(path, target);
return this;
}
//--------------------------------------------------------------------------
/** Removes the route specified by the path. */
public void removePath(String path) {
first.removePath(path);
other.removePath(path);
last .removePath(path);
}
/** Removes all routes leading to the target. */
public void removeTarget(T target) {
first.removeTarget(target);
other.removeTarget(target);
last .removeTarget(target);
}
//--------------------------------------------------------------------------
/** @return {@code null} if no match; note: {@code queryParams} is not set in {@link RouteResult} */
public RouteResult<T> route(String path) {
return route(Path.removeSlashesAtBothEnds(path).split("/"));
}
/** @return {@code null} if no match; note: {@code queryParams} is not set in {@link RouteResult} */
public RouteResult<T> route(String[] requestPathTokens) {
RouteResult<T> ret = first.route(requestPathTokens);
if (ret != null) {
return ret;
}
ret = other.route(requestPathTokens);
if (ret != null) {
return ret;
}
ret = last.route(requestPathTokens);
if (ret != null) {
return ret;
}
return null;
}
/** Checks if there's any matching route. */
public boolean anyMatched(String[] requestPathTokens) {
return first.anyMatched(requestPathTokens) ||
other.anyMatched(requestPathTokens) ||
last.anyMatched(requestPathTokens);
}
/**
* Given a target and params, this method tries to do the reverse routing
* and returns the path.
*
* The params are put to placeholders in the path.
* The params can be a map of {@code placeholder name -> value}
* or ordered values. If a param doesn't have a placeholder, it will be put
* to the query part of the path.
*
* @return {@code null} if there's no match
*/
public String path(T target, Object... params) {
String ret = first.path(target, params);
if (ret != null) {
return ret;
}
ret = other.path(target, params);
if (ret != null) {
return ret;
}
return last.path(target, params);
}
}