001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- 002 * 003 * Copyright © 2024–2025 microBean™. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 006 * the License. You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 011 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 012 * specific language governing permissions and limitations under the License. 013 */ 014package org.microbean.bean; 015 016import java.util.Collection; 017import java.util.List; 018 019import org.microbean.assign.Matcher; 020 021import org.microbean.qualifier.NamedAttributeMap; 022 023import static org.microbean.bean.InterceptorBindings.anyInterceptorBinding; 024import static org.microbean.bean.InterceptorBindings.interceptorBindings; 025 026/** 027 * A {@link Matcher} encapsulating <a 028 * href="https://jakarta.ee/specifications/cdi/4.0/jakarta-cdi-spec-4.0#interceptors">CDI-compatible interceptor binding 029 * matching rules</a>. 030 * 031 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a> 032 * 033 * @see #test(Collection, Collection) 034 */ 035public final class InterceptorBindingsMatcher implements Matcher<Collection<? extends NamedAttributeMap<?>>, Collection<? extends NamedAttributeMap<?>>> { 036 037 /** 038 * Creates a new {@link InterceptorBindingsMatcher}. 039 */ 040 public InterceptorBindingsMatcher() { 041 super(); 042 } 043 044 /** 045 * Returns {@code true} if and only if either (a) both the collection of {@linkplain 046 * InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in {@code receiverAttributes} and 047 * the collection of {@linkplain InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in 048 * {@code payloadAttributes} are {@linkplain Collection#isEmpty() empty}, or (b) if the collection of {@linkplain 049 * InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in {@code payloadAttributes} has 050 * only one element and that element {@linkplain InterceptorBindings#anyInterceptorBinding(NamedAttributeMap) is the 051 * <dfn>any</dfn> interceptor binding}, or (c) the sizes of the collection of {@linkplain 052 * InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in {@code receiverAttributes} and 053 * the collection of {@linkplain InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in 054 * {@code payloadAttributes} are the same and the collection of {@linkplain 055 * InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in {@code receiverAttributes} 056 * {@linkplain Collection#containsAll(Collection) contains all} the collection of {@linkplain 057 * InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in {@code payloadAttributes} and 058 * the collection of {@linkplain InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in 059 * {@code payloadAttributes} {@linkplain Collection#containsAll(Collection) contains all} the collection of 060 * {@linkplain InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in {@code 061 * receiverAttributes}. 062 * 063 * @param receiverAttributes a {@link Collection} of {@link NamedAttributeMap}s; must not be {@code null} 064 * 065 * @param payloadAttributes a {@link Collection} of {@link NamedAttributeMap}s; must not be {@code null} 066 * 067 * @return {@code true} if and only if either (a) both the collection of {@linkplain 068 * InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in {@code receiverAttributes} and 069 * the collection of {@linkplain InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in 070 * {@code payloadAttributes} are {@linkplain Collection#isEmpty() empty}, or (b) if the collection of {@linkplain 071 * InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in {@code payloadAttributes} has 072 * only one element and that element {@linkplain InterceptorBindings#anyInterceptorBinding(NamedAttributeMap) is the 073 * <dfn>any</dfn> interceptor binding}, or (c) the sizes of the collection of {@linkplain 074 * InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in {@code receiverAttributes} and 075 * the collection of {@linkplain InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in 076 * {@code payloadAttributes} are the same and the collection of {@linkplain 077 * InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in {@code receiverAttributes} 078 * {@linkplain Collection#containsAll(Collection) contains all} the collection of {@linkplain 079 * InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in {@code payloadAttributes} and 080 * the collection of {@linkplain InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in 081 * {@code payloadAttributes} {@linkplain Collection#containsAll(Collection) contains all} the collection of 082 * {@linkplain InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in {@code 083 * receiverAttributes} 084 * 085 * @exception NullPointerException if either {@code receiverAttributes} or {@code payloadAttributes} is {@code null} 086 */ 087 @Override // Matcher<Collection<? extends NamedAttributeMap<?>>, Collection<? extends NamedAttributeMap<?>>> 088 public final boolean test(final Collection<? extends NamedAttributeMap<?>> receiverAttributes, 089 final Collection<? extends NamedAttributeMap<?>> payloadAttributes) { 090 final List<? extends NamedAttributeMap<?>> payloadBindings = interceptorBindings(payloadAttributes); 091 if (payloadBindings.isEmpty()) { 092 return interceptorBindings(receiverAttributes).isEmpty(); 093 } else if (payloadBindings.size() == 1 && anyInterceptorBinding(payloadBindings.get(0))) { 094 return true; 095 } 096 final List<? extends NamedAttributeMap<?>> receiverBindings = interceptorBindings(receiverAttributes); 097 return 098 receiverBindings.size() == payloadBindings.size() && 099 receiverBindings.containsAll(payloadBindings) && 100 payloadBindings.containsAll(receiverBindings); 101 } 102 103}