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