001/* 002 * Copyright 2002-2019 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.messaging.handler; 018 019import java.util.ArrayList; 020import java.util.Arrays; 021import java.util.List; 022import java.util.stream.Collectors; 023 024import org.springframework.lang.Nullable; 025import org.springframework.messaging.Message; 026import org.springframework.util.Assert; 027 028/** 029 * Composite {@link MessageCondition} that delegates to other message conditions. 030 * 031 * <p>For {@link #combine} and {@link #compareTo} it is expected that the "other" 032 * composite contains the same number, type, and order of message conditions. 033 * 034 * @author Rossen Stoyanchev 035 * @since 5.2 036 */ 037public class CompositeMessageCondition implements MessageCondition<CompositeMessageCondition> { 038 039 private final List<MessageCondition<?>> messageConditions; 040 041 042 public CompositeMessageCondition(MessageCondition<?>... messageConditions) { 043 this(Arrays.asList(messageConditions)); 044 } 045 046 private CompositeMessageCondition(List<MessageCondition<?>> messageConditions) { 047 Assert.notEmpty(messageConditions, "No message conditions"); 048 this.messageConditions = messageConditions; 049 } 050 051 052 public List<MessageCondition<?>> getMessageConditions() { 053 return this.messageConditions; 054 } 055 056 @SuppressWarnings("unchecked") 057 public <T extends MessageCondition<T>> T getCondition(Class<T> messageConditionType) { 058 for (MessageCondition<?> condition : this.messageConditions) { 059 if (messageConditionType.isAssignableFrom(condition.getClass())) { 060 return (T) condition; 061 } 062 } 063 throw new IllegalStateException("No condition of type: " + messageConditionType); 064 } 065 066 067 @Override 068 public CompositeMessageCondition combine(CompositeMessageCondition other) { 069 checkCompatible(other); 070 List<MessageCondition<?>> result = new ArrayList<>(this.messageConditions.size()); 071 for (int i = 0; i < this.messageConditions.size(); i++) { 072 result.add(combine(getMessageConditions().get(i), other.getMessageConditions().get(i))); 073 } 074 return new CompositeMessageCondition(result); 075 } 076 077 @SuppressWarnings("unchecked") 078 private <T extends MessageCondition<T>> T combine(MessageCondition<?> first, MessageCondition<?> second) { 079 return ((T) first).combine((T) second); 080 } 081 082 @Override 083 public CompositeMessageCondition getMatchingCondition(Message<?> message) { 084 List<MessageCondition<?>> result = new ArrayList<>(this.messageConditions.size()); 085 for (MessageCondition<?> condition : this.messageConditions) { 086 MessageCondition<?> matchingCondition = (MessageCondition<?>) condition.getMatchingCondition(message); 087 if (matchingCondition == null) { 088 return null; 089 } 090 result.add(matchingCondition); 091 } 092 return new CompositeMessageCondition(result); 093 } 094 095 @Override 096 public int compareTo(CompositeMessageCondition other, Message<?> message) { 097 checkCompatible(other); 098 List<MessageCondition<?>> otherConditions = other.getMessageConditions(); 099 for (int i = 0; i < this.messageConditions.size(); i++) { 100 int result = compare (this.messageConditions.get(i), otherConditions.get(i), message); 101 if (result != 0) { 102 return result; 103 } 104 } 105 return 0; 106 } 107 108 @SuppressWarnings("unchecked") 109 private <T extends MessageCondition<T>> int compare( 110 MessageCondition<?> first, MessageCondition<?> second, Message<?> message) { 111 112 return ((T) first).compareTo((T) second, message); 113 } 114 115 private void checkCompatible(CompositeMessageCondition other) { 116 List<MessageCondition<?>> others = other.getMessageConditions(); 117 for (int i = 0; i < this.messageConditions.size(); i++) { 118 if (i < others.size()) { 119 if (this.messageConditions.get(i).getClass().equals(others.get(i).getClass())) { 120 continue; 121 } 122 } 123 throw new IllegalArgumentException("Mismatched CompositeMessageCondition: " + 124 this.messageConditions + " vs " + others); 125 } 126 } 127 128 129 @Override 130 public boolean equals(@Nullable Object other) { 131 if (this == other) { 132 return true; 133 } 134 if (!(other instanceof CompositeMessageCondition)) { 135 return false; 136 } 137 CompositeMessageCondition otherComposite = (CompositeMessageCondition) other; 138 checkCompatible(otherComposite); 139 List<MessageCondition<?>> otherConditions = otherComposite.getMessageConditions(); 140 for (int i = 0; i < this.messageConditions.size(); i++) { 141 if (!this.messageConditions.get(i).equals(otherConditions.get(i))) { 142 return false; 143 } 144 } 145 return true; 146 } 147 148 @Override 149 public int hashCode() { 150 int hashCode = 0; 151 for (MessageCondition<?> condition : this.messageConditions) { 152 hashCode += condition.hashCode() * 31; 153 } 154 return hashCode; 155 } 156 157 @Override 158 public String toString() { 159 return this.messageConditions.stream().map(Object::toString).collect(Collectors.joining(",", "{", "}")); 160 } 161 162}