001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
002 *
003 * Copyright © 2024 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.Collections;
018import java.util.LinkedHashSet;
019import java.util.Objects;
020import java.util.SequencedSet;
021
022import org.microbean.interceptor.InterceptionFunction;
023import org.microbean.interceptor.InterceptorMethod;
024
025import static org.microbean.interceptor.Interceptions.ofConstruction;
026
027// Applies around-construct logic to contextual instance production.
028public final class InterceptingProducer<I> implements Producer<I> {
029
030  private final InterceptionFunction f;
031
032  private final Producer<I> producer;
033
034  @SuppressWarnings("unchecked")
035  public InterceptingProducer(final Collection<? extends InterceptorMethod> interceptorMethods,
036                              final Producer<I> producer) {
037    super();
038    this.producer = Objects.requireNonNull(producer, "producer");
039    final SequencedSet<AttributedElement> dependencies = producer.dependencies();
040    this.f = ofConstruction(interceptorMethods, (ignored, argumentsArray) -> {
041        final SequencedSet<Assignment<?>> assignments = new LinkedHashSet<>();
042        int i = 0;
043        for (final AttributedElement dependency : dependencies) {
044          assignments.add(new Assignment<>(dependency, argumentsArray[i++]));
045        }
046        return this.produce(Collections.unmodifiableSequencedSet(assignments));
047      });
048  }
049
050  @Override // Producer<I> (Aggregate)
051  public final SequencedSet<? extends Assignment<?>> assign(final Request<?> r) {
052    return this.producer.assign(r);
053  }
054
055  @Override // Producer<I> (Aggregate)
056  public final SequencedSet<AttributedElement> dependencies() {
057    return this.producer.dependencies();
058  }
059
060  @Override // Producer<I>
061  public final void dispose(final I i, final Request<I> r) {
062    this.producer.dispose(i, r);
063  }
064
065  @Override // Producer<I>
066  @SuppressWarnings("unchecked")
067  public final I produce(final Request<?> r) {
068    final Collection<? extends AttributedElement> dependencies = this.dependencies();
069    final Object[] array = new Object[dependencies.size()];
070    int i = 0;
071    for (final AttributedElement d : dependencies) {
072      array[i++] = r.reference(d.attributedType());
073    }
074    return (I)this.f.apply(array);
075  }
076
077  @Override // Producer<I>
078  public final I produce(final SequencedSet<? extends Assignment<?>> assignments) {
079    return this.producer.produce(assignments);
080  }
081
082}