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; 021 022import javax.servlet.http.HttpServletRequest; 023 024import org.springframework.lang.Nullable; 025 026/** 027 * A holder for a {@link RequestCondition} useful when the type of the request 028 * condition is not known ahead of time, e.g. custom condition. Since this 029 * class is also an implementation of {@code RequestCondition}, effectively it 030 * decorates the held request condition and allows it to be combined and compared 031 * with other request conditions in a type and null safe way. 032 * 033 * <p>When two {@code RequestConditionHolder} instances are combined or compared 034 * with each other, it is expected the conditions they hold are of the same type. 035 * If they are not, a {@link ClassCastException} is raised. 036 * 037 * @author Rossen Stoyanchev 038 * @since 3.1 039 */ 040public final class RequestConditionHolder extends AbstractRequestCondition<RequestConditionHolder> { 041 042 @Nullable 043 private final RequestCondition<Object> condition; 044 045 046 /** 047 * Create a new holder to wrap the given request condition. 048 * @param requestCondition the condition to hold, may be {@code null} 049 */ 050 @SuppressWarnings("unchecked") 051 public RequestConditionHolder(@Nullable RequestCondition<?> requestCondition) { 052 this.condition = (RequestCondition<Object>) requestCondition; 053 } 054 055 056 /** 057 * Return the held request condition, or {@code null} if not holding one. 058 */ 059 @Nullable 060 public RequestCondition<?> getCondition() { 061 return this.condition; 062 } 063 064 @Override 065 protected Collection<?> getContent() { 066 return (this.condition != null ? Collections.singleton(this.condition) : Collections.emptyList()); 067 } 068 069 @Override 070 protected String getToStringInfix() { 071 return " "; 072 } 073 074 /** 075 * Combine the request conditions held by the two RequestConditionHolder 076 * instances after making sure the conditions are of the same type. 077 * Or if one holder is empty, the other holder is returned. 078 */ 079 @Override 080 public RequestConditionHolder combine(RequestConditionHolder other) { 081 if (this.condition == null && other.condition == null) { 082 return this; 083 } 084 else if (this.condition == null) { 085 return other; 086 } 087 else if (other.condition == null) { 088 return this; 089 } 090 else { 091 assertEqualConditionTypes(this.condition, other.condition); 092 RequestCondition<?> combined = (RequestCondition<?>) this.condition.combine(other.condition); 093 return new RequestConditionHolder(combined); 094 } 095 } 096 097 /** 098 * Ensure the held request conditions are of the same type. 099 */ 100 private void assertEqualConditionTypes(RequestCondition<?> thisCondition, RequestCondition<?> otherCondition) { 101 Class<?> clazz = thisCondition.getClass(); 102 Class<?> otherClazz = otherCondition.getClass(); 103 if (!clazz.equals(otherClazz)) { 104 throw new ClassCastException("Incompatible request conditions: " + clazz + " and " + otherClazz); 105 } 106 } 107 108 /** 109 * Get the matching condition for the held request condition wrap it in a 110 * new RequestConditionHolder instance. Or otherwise if this is an empty 111 * holder, return the same holder instance. 112 */ 113 @Override 114 @Nullable 115 public RequestConditionHolder getMatchingCondition(HttpServletRequest request) { 116 if (this.condition == null) { 117 return this; 118 } 119 RequestCondition<?> match = (RequestCondition<?>) this.condition.getMatchingCondition(request); 120 return (match != null ? new RequestConditionHolder(match) : null); 121 } 122 123 /** 124 * Compare the request conditions held by the two RequestConditionHolder 125 * instances after making sure the conditions are of the same type. 126 * Or if one holder is empty, the other holder is preferred. 127 */ 128 @Override 129 public int compareTo(RequestConditionHolder other, HttpServletRequest request) { 130 if (this.condition == null && other.condition == null) { 131 return 0; 132 } 133 else if (this.condition == null) { 134 return 1; 135 } 136 else if (other.condition == null) { 137 return -1; 138 } 139 else { 140 assertEqualConditionTypes(this.condition, other.condition); 141 return this.condition.compareTo(other.condition, request); 142 } 143 } 144 145}