org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory.java

Source

/*
 * Copyright 2013-2019 the original author or authors.
 *
 * 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
 *
 *      https://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 org.springframework.cloud.gateway.handler.predicate;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.core.style.ToStringCreator;
import org.springframework.http.server.PathContainer;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.pattern.PathPattern;
import org.springframework.web.util.pattern.PathPattern.PathMatchInfo;
import org.springframework.web.util.pattern.PathPatternParser;

import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.putUriTemplateVariables;
import static org.springframework.http.server.PathContainer.parsePath;

/**
 * @author Spencer Gibb
 */
public class PathRoutePredicateFactory extends AbstractRoutePredicateFactory<PathRoutePredicateFactory.Config> {

    private static final Log log = LogFactory.getLog(RoutePredicateFactory.class);

    private static final String MATCH_OPTIONAL_TRAILING_SEPARATOR_KEY = "matchOptionalTrailingSeparator";

    private PathPatternParser pathPatternParser = new PathPatternParser();

    public PathRoutePredicateFactory() {
        super(Config.class);
    }

    private static void traceMatch(String prefix, Object desired, Object actual, boolean match) {
        if (log.isTraceEnabled()) {
            String message = String.format("%s \"%s\" %s against value \"%s\"", prefix, desired,
                    match ? "matches" : "does not match", actual);
            log.trace(message);
        }
    }

    public void setPathPatternParser(PathPatternParser pathPatternParser) {
        this.pathPatternParser = pathPatternParser;
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("patterns", MATCH_OPTIONAL_TRAILING_SEPARATOR_KEY);
    }

    @Override
    public ShortcutType shortcutType() {
        return ShortcutType.GATHER_LIST_TAIL_FLAG;
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        final ArrayList<PathPattern> pathPatterns = new ArrayList<>();
        synchronized (this.pathPatternParser) {
            pathPatternParser.setMatchOptionalTrailingSeparator(config.isMatchOptionalTrailingSeparator());
            config.getPatterns().forEach(pattern -> {
                PathPattern pathPattern = this.pathPatternParser.parse(pattern);
                pathPatterns.add(pathPattern);
            });
        }
        return exchange -> {
            PathContainer path = parsePath(exchange.getRequest().getURI().getRawPath());

            Optional<PathPattern> optionalPathPattern = pathPatterns.stream()
                    .filter(pattern -> pattern.matches(path)).findFirst();

            if (optionalPathPattern.isPresent()) {
                PathPattern pathPattern = optionalPathPattern.get();
                traceMatch("Pattern", pathPattern.getPatternString(), path, true);
                PathMatchInfo pathMatchInfo = pathPattern.matchAndExtract(path);
                putUriTemplateVariables(exchange, pathMatchInfo.getUriVariables());
                return true;
            } else {
                traceMatch("Pattern", config.getPatterns(), path, false);
                return false;
            }
        };
    }

    @Validated
    public static class Config {

        private List<String> patterns = new ArrayList<>();

        private boolean matchOptionalTrailingSeparator = true;

        @Deprecated
        public String getPattern() {
            if (!CollectionUtils.isEmpty(this.patterns)) {
                return patterns.get(0);
            }
            return null;
        }

        @Deprecated
        public Config setPattern(String pattern) {
            this.patterns = new ArrayList<>();
            this.patterns.add(pattern);
            return this;
        }

        public List<String> getPatterns() {
            return patterns;
        }

        public Config setPatterns(List<String> patterns) {
            this.patterns = patterns;
            return this;
        }

        public boolean isMatchOptionalTrailingSeparator() {
            return matchOptionalTrailingSeparator;
        }

        public Config setMatchOptionalTrailingSeparator(boolean matchOptionalTrailingSeparator) {
            this.matchOptionalTrailingSeparator = matchOptionalTrailingSeparator;
            return this;
        }

        @Override
        public String toString() {
            return new ToStringCreator(this).append("patterns", patterns)
                    .append("matchOptionalTrailingSeparator", matchOptionalTrailingSeparator).toString();
        }

    }

}