All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sparkling.route.SimpleRouteMatcher Maven / Gradle / Ivy

There is a newer version: 1.1.2
Show newest version
/*
 * Copyright 2011- Per Wendel
 *
 *  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 sparkling.route;

import java.util.ArrayList;
import java.util.List;

import sparkling.utils.SparklingUtils;

/**
 * Simple route matcher that is supposed to work exactly as Sinatra's
 *
 * @author Per Wendel
 */
public class SimpleRouteMatcher implements RouteMatcher {
    private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(SimpleRouteMatcher.class);

    private List routes;

    private static class RouteEntry {
        private HttpMethod httpMethod;
        private String path;
        private Object target;

        private boolean matches(final HttpMethod httpMethod, final String path) {
            if ( (httpMethod == HttpMethod.before || httpMethod == HttpMethod.after)
                            && (this.httpMethod == httpMethod)
                            && this.path.equals(SparklingUtils.ALL_PATHS)) {
                // Is filter and matches all
                return true;
            }
            boolean match = false;
            if (this.httpMethod == httpMethod) {
                match = matchPath(path);
            }
            return match;
        }

        private boolean matchPath(final String path) {
            if (!this.path.endsWith("*") && ((path.endsWith("/") && !this.path.endsWith("/"))
                            || (this.path.endsWith("/") && !path.endsWith("/")))) { 
                // One and not both ends with slash
                return false;
            }
            if (this.path.equals(path)) {
                // Paths are the same
                return true;
            }

            // check params
            List thisPathList = SparklingUtils.convertRouteToList(this.path);
            List pathList = SparklingUtils.convertRouteToList(path);

            int thisPathSize = thisPathList.size();
            int pathSize = pathList.size();

            if (thisPathSize == pathSize) {
                for (int i = 0; i < thisPathSize; i++) {
                    String thisPathPart = thisPathList.get(i);
                    String pathPart = pathList.get(i);

                    if ((i == thisPathSize -1) && (thisPathPart.equals("*") && this.path.endsWith("*"))) {
                        // wildcard match
                        return true;
                    }

                    if ((!thisPathPart.startsWith(":"))
                            && !thisPathPart.equals(pathPart)
                            && !thisPathPart.equals("*")) {
                        return false;
                    }
                }
                // All parts matched
                return true;
            }
            else {
                // Number of "path parts" not the same
                // check wild card:
                if (this.path.endsWith("*")) {
                    if (pathSize == (thisPathSize - 1) && (path.endsWith("/"))) {
                        // Hack for making wildcards work with trailing slash
                        pathList.add("");
                        pathList.add("");
                        pathSize += 2;
                    }

                    if (thisPathSize < pathSize) {
                        for (int i = 0; i < thisPathSize; i++) {
                            String thisPathPart = thisPathList.get(i);
                            String pathPart = pathList.get(i);
                            if (thisPathPart.equals("*") && (i == thisPathSize -1) && this.path.endsWith("*")) {
                                // wildcard match
                                return true;
                            }
                            if (!thisPathPart.startsWith(":") 
                                    && !thisPathPart.equals(pathPart)
                                    && !thisPathPart.equals("*")) {
                                return false;
                            }
                        }
                        // All parts matched
                        return true;
                    }
                    // End check wild card
                }
                return false;
            }
        }

        public String toString() {
            return httpMethod.name() + ", " + path + ", " + target;
        }
    }

    public SimpleRouteMatcher() {
        routes = new ArrayList();
    }

    @Override
    public RouteMatch findTargetForRequestedRoute(final HttpMethod httpMethod, final String path) {
        for (RouteEntry entry : routes) {
            if (entry.matches(httpMethod, path)) {
                return new RouteMatch(httpMethod, entry.target, entry.path, path);
            }
        }
        return null;
    }

    @Override
    public List findTargetsForRequestedRoute(final HttpMethod httpMethod, final String path) {
        List matchSet = new ArrayList();
        for (RouteEntry entry : routes) {
            if (entry.matches(httpMethod, path)) {
                matchSet.add(new RouteMatch(httpMethod, entry.target, entry.path, path));
            }
        }
        return matchSet;
    }

    @Override
    public void parseValidateAddRoute(final String route, final Object target) {
        try {
            int singleQuoteIndex = route.indexOf(SINGLE_QUOTE);
            String httpMethod = route.substring(0, singleQuoteIndex).trim().toLowerCase();
            String url = route.substring(singleQuoteIndex + 1, route.length() - 1).trim();

            // Use special enum stuff to get from value
            HttpMethod method;
            try {
                method = HttpMethod.valueOf(httpMethod);
            }
            catch (IllegalArgumentException e) {
                LOG.error("The @Route value: "
                                + route
                                + " has an invalid HTTP method part: "
                                + httpMethod
                                + ".");
                return;
            }
            addRoute(method, url, target);
        }
        catch (Exception e) {
            LOG.error("The @Route value: " + route + " is not in the correct format", e);
        }
    }

    private void addRoute(final HttpMethod method, final String url, final Object target) {
        RouteEntry entry = new RouteEntry();
        entry.httpMethod = method;
        entry.path = url;
        entry.target = target;
        LOG.debug("Adds route: " + entry);
        // Adds to end of list
        routes.add(entry);
    }

    @Override
    public void clearRoutes() {
        routes.clear();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy