001/* 002 * Copyright 2002-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.servlet.mvc.condition; 018 019import java.util.Collection; 020import java.util.Collections; 021import java.util.LinkedHashSet; 022import java.util.Set; 023import javax.servlet.http.HttpServletRequest; 024 025import org.springframework.util.ObjectUtils; 026import org.springframework.web.bind.annotation.RequestMapping; 027import org.springframework.web.util.WebUtils; 028 029/** 030 * A logical conjunction (' && ') request condition that matches a request against 031 * a set parameter expressions with syntax defined in {@link RequestMapping#params()}. 032 * 033 * @author Arjen Poutsma 034 * @author Rossen Stoyanchev 035 * @since 3.1 036 */ 037public final class ParamsRequestCondition extends AbstractRequestCondition<ParamsRequestCondition> { 038 039 private final Set<ParamExpression> expressions; 040 041 042 /** 043 * Create a new instance from the given param expressions. 044 * @param params expressions with syntax defined in {@link RequestMapping#params()}; 045 * if 0, the condition will match to every request. 046 */ 047 public ParamsRequestCondition(String... params) { 048 this(parseExpressions(params)); 049 } 050 051 private ParamsRequestCondition(Collection<ParamExpression> conditions) { 052 this.expressions = Collections.unmodifiableSet(new LinkedHashSet<ParamExpression>(conditions)); 053 } 054 055 056 private static Collection<ParamExpression> parseExpressions(String... params) { 057 Set<ParamExpression> expressions = new LinkedHashSet<ParamExpression>(); 058 if (params != null) { 059 for (String param : params) { 060 expressions.add(new ParamExpression(param)); 061 } 062 } 063 return expressions; 064 } 065 066 067 /** 068 * Return the contained request parameter expressions. 069 */ 070 public Set<NameValueExpression<String>> getExpressions() { 071 return new LinkedHashSet<NameValueExpression<String>>(this.expressions); 072 } 073 074 @Override 075 protected Collection<ParamExpression> getContent() { 076 return this.expressions; 077 } 078 079 @Override 080 protected String getToStringInfix() { 081 return " && "; 082 } 083 084 /** 085 * Returns a new instance with the union of the param expressions 086 * from "this" and the "other" instance. 087 */ 088 @Override 089 public ParamsRequestCondition combine(ParamsRequestCondition other) { 090 Set<ParamExpression> set = new LinkedHashSet<ParamExpression>(this.expressions); 091 set.addAll(other.expressions); 092 return new ParamsRequestCondition(set); 093 } 094 095 /** 096 * Returns "this" instance if the request matches all param expressions; 097 * or {@code null} otherwise. 098 */ 099 @Override 100 public ParamsRequestCondition getMatchingCondition(HttpServletRequest request) { 101 for (ParamExpression expression : expressions) { 102 if (!expression.match(request)) { 103 return null; 104 } 105 } 106 return this; 107 } 108 109 /** 110 * Returns: 111 * <ul> 112 * <li>0 if the two conditions have the same number of parameter expressions 113 * <li>Less than 0 if "this" instance has more parameter expressions 114 * <li>Greater than 0 if the "other" instance has more parameter expressions 115 * </ul> 116 * <p>It is assumed that both instances have been obtained via 117 * {@link #getMatchingCondition(HttpServletRequest)} and each instance 118 * contains the matching parameter expressions only or is otherwise empty. 119 */ 120 @Override 121 public int compareTo(ParamsRequestCondition other, HttpServletRequest request) { 122 return (other.expressions.size() - this.expressions.size()); 123 } 124 125 126 /** 127 * Parses and matches a single param expression to a request. 128 */ 129 static class ParamExpression extends AbstractNameValueExpression<String> { 130 131 ParamExpression(String expression) { 132 super(expression); 133 } 134 135 @Override 136 protected boolean isCaseSensitiveName() { 137 return true; 138 } 139 140 @Override 141 protected String parseValue(String valueExpression) { 142 return valueExpression; 143 } 144 145 @Override 146 protected boolean matchName(HttpServletRequest request) { 147 return WebUtils.hasSubmitParameter(request, this.name); 148 } 149 150 @Override 151 protected boolean matchValue(HttpServletRequest request) { 152 return ObjectUtils.nullSafeEquals(this.value, request.getParameter(this.name)); 153 } 154 } 155 156}