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.HashMap.newHashMap;
033
034/**
035 * A creator of proxies for business method interceptions.
036 *
037 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
038 */
039public interface InterceptionProxier {
040
041  /**
042   * Creates an <dfn>interception proxy</dfn> for a given contextual instance.
043   *
044   * @param <I> the contextual instance type
045   *
046   * @param id an {@link Id}; must not be {@code null}
047   *
048   * @param instanceSupplier a {@link Supplier} of contextual instances of the appropriate type; must not be {@code null}
049   *
050   * @param aroundInvokeInterceptions a {@link Map} of {@link InterceptorMethod}s indexed by the {@link
051   * ExecutableElement} to which they apply; must not be {@code null}
052   *
053   * @return a non-{@code null} interception proxy
054   *
055   * @exception NullPointerException if any argument is {@code null}
056   */
057  public <I> I interceptionProxy(final Id id,
058                                 final Supplier<? extends I> instanceSupplier,
059                                 final Map<ExecutableElement, List<InterceptorMethod>> aroundInvokeInterceptions);
060
061  /**
062   * A {@link ProxySpecification} that exposes {@link InterceptorMethod}-related information.
063   *
064   * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
065   *
066   * @see #interceptorMethods(ExecutableElement)
067   */
068  public static class Specification extends ProxySpecification {
069
070    private final Map<ExecutableElement, List<InterceptorMethod>> aroundInvokeInterceptions;
071
072    /**
073     * Creates a new {@link Specification}.
074     *
075     * @param domain a {@link Domain}; must not be {@code null}
076     *
077     * @param id an {@link Id}; must not be {@code null}
078     *
079     * @param aroundInvokeInterceptions a {@link Map} of {@link InterceptorMethod}s indexed by the {@link
080     * ExecutableElement} to which they apply; must not be {@code null}
081     *
082     * @exception NullPointerException if any argument is {@code null}
083     */
084    public Specification(final Domain domain,
085                         final Id id,
086                         final Map<ExecutableElement, List<InterceptorMethod>> aroundInvokeInterceptions) {
087      super(domain, id);
088      final Map<ExecutableElement, List<InterceptorMethod>> m = newHashMap(aroundInvokeInterceptions.size());
089      for (final Entry<ExecutableElement, List<InterceptorMethod>> e : aroundInvokeInterceptions.entrySet()) {
090        m.put(e.getKey(), List.copyOf(e.getValue()));
091      }
092      this.aroundInvokeInterceptions = Map.copyOf(m);
093    }
094
095    /**
096     * Returns a non-{@code null}, immutable, determinate {@link List} of {@link InterceptorMethod}s pertaining to the
097     * supplied {@link ExecutableElement}.
098     *
099     * @param ee an {@link ExecutableElement}; must not be {@code null}
100     *
101     * @return a non-{@code null}, immutable, determinate {@link List} of {@link InterceptorMethod}s pertaining to the
102     * supplied {@link ExecutableElement}
103     *
104     * @exception NullPointerException if {@code ee} is {@code null}
105     */
106    public final List<InterceptorMethod> interceptorMethods(final ExecutableElement ee) {
107      final List<InterceptorMethod> ims = this.aroundInvokeInterceptions.get(ee);
108      return ims == null || ims.isEmpty() ? List.of() : ims;
109    }
110    
111  }
112  
113}