001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
002 *
003 * Copyright © 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.producer;
015
016import java.util.List;
017import java.util.Map;
018import java.util.Map.Entry;
019
020import java.util.function.Supplier;
021
022import javax.lang.model.element.ExecutableElement;
023
024import org.microbean.bean.Id;
025
026import org.microbean.construct.Domain;
027
028import org.microbean.interceptor.InterceptorMethod;
029
030import org.microbean.proxy.ProxySpecification;
031
032import static java.util.Collections.unmodifiableMap;
033
034import static java.util.HashMap.newHashMap;
035
036/**
037 * A creator of proxies for business method interceptions.
038 *
039 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
040 */
041public interface InterceptionProxier {
042
043  /**
044   * Creates an <dfn>interception proxy</dfn> for a given contextual instance.
045   *
046   * @param <I> the contextual instance type
047   *
048   * @param id an {@link Id}; must not be {@code null}
049   *
050   * @param instanceSupplier a {@link Supplier} of contextual instances of the appropriate type; must not be {@code null}
051   *
052   * @param aroundInvokeInterceptions a {@link Map} of {@link InterceptorMethod}s indexed by the {@link
053   * ExecutableElement} to which they apply; must not be {@code null}
054   *
055   * @return a non-{@code null} interception proxy
056   *
057   * @exception NullPointerException if any argument is {@code null}
058   */
059  public <I> I interceptionProxy(final Id id,
060                                 final Supplier<? extends I> instanceSupplier,
061                                 final Map<ExecutableElement, List<InterceptorMethod>> aroundInvokeInterceptions);
062
063  /**
064   * A {@link ProxySpecification} that exposes {@link InterceptorMethod}-related information.
065   *
066   * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
067   *
068   * @see #interceptorMethods(ExecutableElement)
069   *
070   * @see ProxySpecification
071   *
072   * @see org.microbean.proxy.AbstractProxier#proxy(ProxySpecification, Supplier)
073   */
074  public static class Specification extends ProxySpecification {
075
076    private final Map<ExecutableElement, List<InterceptorMethod>> aroundInvokeInterceptions;
077
078    /**
079     * Creates a new {@link Specification}.
080     *
081     * @param domain a {@link Domain}; must not be {@code null}
082     *
083     * @param id an {@link Id}; must not be {@code null}
084     *
085     * @param aroundInvokeInterceptions a {@link Map} of {@link InterceptorMethod}s indexed by the {@link
086     * ExecutableElement} to which they apply; must not be {@code null}
087     *
088     * @exception NullPointerException if any argument is {@code null}
089     */
090    public Specification(final Domain domain,
091                         final Id id,
092                         final Map<ExecutableElement, List<InterceptorMethod>> aroundInvokeInterceptions) {
093      super(domain, id);
094      final Map<ExecutableElement, List<InterceptorMethod>> m = newHashMap(aroundInvokeInterceptions.size());
095      for (final Entry<ExecutableElement, List<InterceptorMethod>> e : aroundInvokeInterceptions.entrySet()) {
096        m.put(e.getKey(), List.copyOf(e.getValue()));
097      }
098      this.aroundInvokeInterceptions = unmodifiableMap(m);
099    }
100
101    /**
102     * Returns a non-{@code null}, immutable, determinate {@link List} of {@link InterceptorMethod}s pertaining to the
103     * supplied {@link ExecutableElement}.
104     *
105     * @param ee an {@link ExecutableElement}; must not be {@code null}
106     *
107     * @return a non-{@code null}, immutable, determinate {@link List} of {@link InterceptorMethod}s pertaining to the
108     * supplied {@link ExecutableElement}
109     *
110     * @exception NullPointerException if {@code ee} is {@code null}
111     */
112    public final List<InterceptorMethod> interceptorMethods(final ExecutableElement ee) {
113      final List<InterceptorMethod> ims = this.aroundInvokeInterceptions.get(ee);
114      return ims == null || ims.isEmpty() ? List.of() : ims;
115    }
116
117  }
118
119}