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