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

com.nike.riposte.util.MultiMatcher Maven / Gradle / Ivy

There is a newer version: 0.20.0
Show newest version
package com.nike.riposte.util;

import com.nike.riposte.server.http.RequestInfo;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
import java.util.stream.Collectors;

import io.netty.handler.codec.http.HttpMethod;

/**
 * Class for determining whether a request should be matched to a given endpoint or not. You can call {@link
 * #matchesPath(RequestInfo)} to see if the endpoint matches the given request's path, and {@link
 * #matchesMethod(RequestInfo)} to see if the endpoint matches the given request's HTTP method. If both method calls
 * return true then the endpoint wants to handle the request. Order for the matchingPathTemplates collection may be
 * important depending on what your path templates are as the first one matched is used. If order is important you
 * should use a deterministic collection (List, SortedSet, etc) when creating the MultiMatcher.
 * 

* There are a few static factory methods for creating a new instance of this class using common argument patterns: * {@link #match(String)}, {@link #match(Collection, HttpMethod...)}, and {@link #match(Collection, Collection)}. *

* This class supports path parameters. An Ant path matcher is used to determine matches. See {@link * RequestInfo#getPathParams()} for a quick description of the easy/common path template structure that results in path * parameters. */ @SuppressWarnings("WeakerAccess") public class MultiMatcher implements Matcher { protected static final AntPathMatcher pathParamExtractor = new AntPathMatcher(); protected final Collection matchingPathTemplates; protected final Collection matchingMethods; protected final boolean matchAllMethods; protected MultiMatcher(Collection matchingPathTemplates, Collection matchingMethods, boolean matchAllMethods) { // If the path template doesn't start with a forward slash it has no hope of ever matching any incoming request. if (matchingPathTemplates == null || matchingPathTemplates.isEmpty() || matchingPathTemplates.stream().anyMatch(path -> !path.startsWith("/"))) { throw new IllegalArgumentException("matchingPathTemplates cannot be null or empty and paths must start " + "with a forward slash '/'"); } if (matchingMethods == null) throw new IllegalArgumentException("matchingMethods cannot be null"); this.matchingMethods = matchingMethods; this.matchingPathTemplates = matchingPathTemplates.stream() .map(MatcherUtil::stripEndSlash) .collect(Collectors.toList()); this.matchAllMethods = matchAllMethods; } /** * @return A new multi-matcher with the given path template that matches all HTTP methods ({@link * #isMatchAllMethods()} will return true). */ public static MultiMatcher match(Collection matchingPathTemplates) { return new MultiMatcher(matchingPathTemplates, Collections.emptyList(), true); } /** * @return A new multi-matcher with the given path templates that match the given HTTP methods. */ public static MultiMatcher match(Collection matchingPathTemplates, HttpMethod... matchingMethods) { if (matchingMethods == null || matchingMethods.length == 0) { throw new IllegalArgumentException("matchingMethods cannot be null or empty. If you want to match all " + "methods use the single-arg match(Collection) method."); } return new MultiMatcher(matchingPathTemplates, Arrays.asList(matchingMethods), false); } /** * @return A new multi-matcher with the given path templates that match the given HTTP methods. */ public static MultiMatcher match(Collection matchingPathTemplates, Collection matchingMethods) { if (matchingMethods == null || matchingMethods.isEmpty()) { throw new IllegalArgumentException("matchingMethods cannot be null or empty. If you want to match all " + "methods use the single-arg match(Collection) method."); } return new MultiMatcher(matchingPathTemplates, matchingMethods, false); } /** * {@inheritDoc} */ @Override public Collection matchingMethods() { return matchingMethods; } /** * {@inheritDoc} */ public Collection matchingPathTemplates() { return matchingPathTemplates; } /** * @return Returns the first pattern found in the collection that matches the given request if one exists. Order of * paths can be significant so when creating a MultiMatcher use an ordered collection if some path may match * multiple patterns. */ @Override public Optional matchesPath(RequestInfo request) { if (request == null || request.getPath() == null) return Optional.empty(); // Ignore trailing slashes on the actual path. String path = MatcherUtil.stripEndSlash(request.getPath()); return matchingPathTemplates .stream() // Ignore trailing slashes on the template. .filter(pathTemplate -> pathParamExtractor.match(pathTemplate, path)) .findFirst(); } /** * {@inheritDoc} */ @Override public boolean matchesMethod(RequestInfo request) { if (matchAllMethods) return true; //noinspection SimplifiableIfStatement if (request == null || request.getMethod() == null) return false; return matchingMethods().contains(request.getMethod()); } /** * {@inheritDoc} */ @Override public boolean isMatchAllMethods() { return matchAllMethods; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy