001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- 002 * 003 * Copyright © 2023–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.ArrayList; 017import java.util.Collection; 018import java.util.Collections; 019import java.util.List; 020import java.util.Map; 021import java.util.Objects; 022 023import org.microbean.attributes.Attributes; 024import org.microbean.attributes.StringValue; 025 026/** 027 * A utility class providing methods that work with interceptor bindings. 028 * 029 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a> 030 */ 031public final class InterceptorBindings { 032 033 private static final Attributes INTERCEPTOR_BINDING = Attributes.of("InterceptorBinding"); 034 035 private static final List<Attributes> INTERCEPTOR_BINDING_LIST = List.of(INTERCEPTOR_BINDING); 036 037 private static final Attributes ANY_INTERCEPTOR_BINDING = Attributes.of("Any", INTERCEPTOR_BINDING_LIST); 038 039 private InterceptorBindings() { 040 super(); 041 } 042 043 /** 044 * Returns a {@link Attributes} representing the <dfn>any</dfn> interceptor binding. 045 * 046 * @return a {@link Attributes} representing the <dfn>any</dfn> interceptor binding; never {@code null} 047 */ 048 public static final Attributes anyInterceptorBinding() { 049 return ANY_INTERCEPTOR_BINDING; 050 } 051 052 /** 053 * Returns {@code true} if and only if the supplied {@link Attributes} represents the <dfn>any</dfn> 054 * interceptor binding. 055 * 056 * @param a a {@link Attributes}; may be {@code null} in which case {@code false} will be returned 057 * 058 * @return {@code true} if and only if the supplied {@link Attributes} represents the <dfn>any</dfn> 059 * interceptor binding 060 * 061 * @see #anyInterceptorBinding() 062 */ 063 public static final boolean anyInterceptorBinding(final Attributes a) { 064 return ANY_INTERCEPTOR_BINDING.equals(a) && interceptorBinding(a); 065 } 066 067 /** 068 * Returns a {@link Attributes} representing the <dfn>interceptor binding</dfn> (meta-) interceptor binding. 069 * 070 * @return a {@link Attributes} representing the <dfn>interceptor binding</dfn> (meta-) interceptor binding; 071 * never {@code null} 072 */ 073 public static final Attributes interceptorBinding() { 074 return INTERCEPTOR_BINDING; 075 } 076 077 /** 078 * Returns {@code true} if and only if the supplied {@link Attributes} is itself a {@link Attributes} that can be used 079 * to designate other {@link Attributes} instances as interceptor bindings, or a {@link Attributes} so designated. 080 * 081 * @param a a {@link Attributes}; may be {@code null} in which case {@code false} will be returned 082 * 083 * @return {@code true} if and only if the supplied {@link Attributes} is itself a {@link Attributes} 084 * that can be used to designate other {@link Attributes} instances as interceptor bindings, or a {@link 085 * Attributes} so designated 086 * 087 * @see #interceptorBinding() 088 */ 089 public static final boolean interceptorBinding(final Attributes a) { 090 return a != null && interceptorBinding(a.attributes(a.name())); 091 } 092 093 private static final boolean interceptorBinding(final Iterable<? extends Attributes> mds) { 094 for (final Attributes md : mds) { 095 if (md.equals(INTERCEPTOR_BINDING) && md.attributes().isEmpty() || interceptorBinding(md)) { 096 return true; 097 } 098 } 099 return false; 100 } 101 102 /** 103 * Given a {@link Collection} of {@link Attributes}s, returns an immutable {@link List} consisting of those 104 * {@link Attributes} instances that are {@linkplain #interceptorBinding() deemed to be interceptor bindings}. 105 * 106 * @param c a {@link Collection}; must not be {@code null} 107 * 108 * @return a {@link List} of interceptor bindings 109 * 110 * @exception NullPointerException if {@code c} is {@code null} 111 */ 112 public static final List<Attributes> interceptorBindings(final Collection<? extends Attributes> c) { 113 if (c.isEmpty()) { 114 return List.of(); 115 } 116 final ArrayList<Attributes> list = new ArrayList<>(c.size()); 117 for (final Attributes a : c) { 118 if (interceptorBinding(a)) { 119 list.add(a); 120 } 121 } 122 list.trimToSize(); 123 return Collections.unmodifiableList(list); 124 } 125 126 /** 127 * Returns a {@link Attributes} representing a <dfn>target class</dfn> interceptor binding. 128 * 129 * @param type the target class name; must not be {@code null} 130 * 131 * @return a {@link Attributes} representing a <dfn>target class</dfn> interceptor binding; never {@code null} 132 * 133 * @exception NullPointerException if {@code type} is {@code null} 134 */ 135 public static final Attributes targetClassInterceptorBinding(final String type) { 136 return Attributes.of("TargetClass", Map.of("class", StringValue.of(type)), Map.of(), Map.of("TargetClass", INTERCEPTOR_BINDING_LIST)); 137 } 138 139 /** 140 * Returns {@code true} if and only if the supplied {@link Attributes} is a <dfn>target class</dfn> interceptor 141 * binding. 142 * 143 * @param a a {@link Attributes}; must not be {@code null} 144 * 145 * @return {@code true} if and only if the supplied {@link Attributes} is a <dfn>target class</dfn> interceptor 146 * binding 147 * 148 * @exception NullPointerException if {@code a} is {@code null} 149 */ 150 // Is a a TargetClass interceptor binding? 151 public static final boolean targetClassInterceptorBinding(final Attributes a) { 152 return a.name().equals("TargetClass") && interceptorBinding(a); 153 } 154 155}