AsDelegate.java

  1. /*
  2.  * *************************************************************************************************************************************************************
  3.  *
  4.  * TheseFoolishThings: Miscellaneous utilities
  5.  * http://tidalwave.it/projects/thesefoolishthings
  6.  *
  7.  * Copyright (C) 2009 - 2025 by Tidalwave s.a.s. (http://tidalwave.it)
  8.  *
  9.  * *************************************************************************************************************************************************************
  10.  *
  11.  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
  12.  * You may obtain a copy of the License at
  13.  *
  14.  *     http://www.apache.org/licenses/LICENSE-2.0
  15.  *
  16.  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  17.  * CONDITIONS OF ANY KIND, either express or implied.  See the License for the specific language governing permissions and limitations under the License.
  18.  *
  19.  * *************************************************************************************************************************************************************
  20.  *
  21.  * git clone https://bitbucket.org/tidalwave/thesefoolishthings-src
  22.  * git clone https://github.com/tidalwave-it/thesefoolishthings-src
  23.  *
  24.  * *************************************************************************************************************************************************************
  25.  */
  26. package it.tidalwave.role.impl;

  27. import jakarta.annotation.Nonnull;
  28. import java.util.ArrayList;
  29. import java.util.Collection;
  30. import java.util.Collections;
  31. import java.util.List;
  32. import java.util.Optional;
  33. import java.util.function.Function;
  34. import it.tidalwave.util.As;
  35. import it.tidalwave.util.LazySupplier;
  36. import it.tidalwave.util.Parameters;
  37. import it.tidalwave.util.RoleFactory;
  38. import it.tidalwave.role.spi.OwnerRoleFactory;
  39. import it.tidalwave.role.spi.OwnerRoleFactoryProvider;
  40. import static it.tidalwave.util.Parameters.r;

  41. /***************************************************************************************************************************************************************
  42.  *
  43.  * An implementation of {@link As} that keeps some local roles and queries {@link OwnerRoleFactory}.
  44.  *
  45.  * @author  Fabrizio Giudici
  46.  *
  47.  **************************************************************************************************************************************************************/
  48. public class AsDelegate implements As
  49.   {
  50.     @Nonnull
  51.     private final Object owner;

  52.     @Nonnull
  53.     private final LazySupplier<OwnerRoleFactory> ownerRoleFactory;


  54.     @Nonnull
  55.     private final List<Object> roles = new ArrayList<>();

  56.     /***********************************************************************************************************************************************************
  57.      * Constructor for use in subclassing.
  58.      **********************************************************************************************************************************************************/
  59.     protected AsDelegate ()
  60.       {
  61.         owner = this;
  62.         ownerRoleFactory = LazySupplier.of(() -> OwnerRoleFactoryProvider.getInstance().createRoleFactory(this));
  63.       }

  64.     /***********************************************************************************************************************************************************
  65.      * Constructor for use in composition.
  66.      *
  67.      * @param  owner             the owner
  68.      * @since  3.2-ALPHA-3 (refactored)
  69.      **********************************************************************************************************************************************************/
  70.     public AsDelegate (@Nonnull final Object owner)
  71.       {
  72.         this(owner, Collections.emptyList());
  73.       }

  74.     /***********************************************************************************************************************************************************
  75.      * Constructor for use in composition. In addition to the mandatory owner, it accepts a single pre-instantiated
  76.      * role, or a {@link RoleFactory} that will be invoked to create additional roles.
  77.      *
  78.      * @param  owner          the owner
  79.      * @param  role           the role or {@link it.tidalwave.util.RoleFactory}
  80.      * @since  3.2-ALPHA-3
  81.      **********************************************************************************************************************************************************/
  82.     public AsDelegate (@Nonnull final Object owner, @Nonnull final Object role)
  83.       {
  84.         this(owner, r(Parameters.mustNotBeArrayOrCollection(role, "role")));
  85.       }

  86.     /***********************************************************************************************************************************************************
  87.      * Constructor for use in composition. In addition to the mandatory owner, it accepts a collection of
  88.      * pre-instantiated roles, or instances of {@link RoleFactory} that will be invoked to create additional roles.
  89.      *
  90.      * @param  owner          the owner
  91.      * @param  roles          roles or {@link it.tidalwave.util.RoleFactory} instances
  92.      * @since  3.2-ALPHA-3 (refactored)
  93.      **********************************************************************************************************************************************************/
  94.     public AsDelegate (@Nonnull final Object owner, @Nonnull final Collection<Object> roles)
  95.       {
  96.         this(o -> OwnerRoleFactoryProvider.getInstance().createRoleFactory(o), owner, roles);
  97.       }

  98.     /***********************************************************************************************************************************************************
  99.      * Constructor for use in tests. This constructor doesn't call {@link OwnerRoleFactoryProvider#getInstance()}.
  100.      *
  101.      * @param  systemRoleFactoryFunction  the factory
  102.      * @param  owner          the owner
  103.      * @param  roles          roles or {@link it.tidalwave.util.RoleFactory} instances
  104.      * @since  3.2-ALPHA-3 (refactored)
  105.      **********************************************************************************************************************************************************/
  106.     public AsDelegate (@Nonnull final Function<Object, OwnerRoleFactory> systemRoleFactoryFunction,
  107.                        @Nonnull final Object owner,
  108.                        @Nonnull final Collection<Object> roles)
  109.       {
  110.         ownerRoleFactory = LazySupplier.of(() -> systemRoleFactoryFunction.apply(owner));
  111.         this.owner = owner;
  112.         this.roles.addAll(RoleFactory.resolveFactories(owner, roles));
  113.       }

  114.     /***********************************************************************************************************************************************************
  115.      * {@inheritDoc}
  116.      *
  117.      * First, local roles are probed; then the owner, in case it directly implements the required role; at last,
  118.      * the systemRoleFactory is invoked.
  119.      **********************************************************************************************************************************************************/
  120.     @Override @Nonnull
  121.     public <T> Optional<T> maybeAs (@Nonnull final Class<? extends T> type)
  122.       {
  123.         for (final var role : roles)
  124.           {
  125.             if (type.isAssignableFrom(role.getClass()))
  126.               {
  127.                 return Optional.of(type.cast(role));
  128.               }
  129.           }

  130.         final var r = ownerRoleFactory.get().findRoles(type);
  131.         return r.isEmpty() ? Optional.empty() : Optional.of(r.iterator().next());
  132.       }

  133.     /***********************************************************************************************************************************************************
  134.      * {@inheritDoc}
  135.      *
  136.      * The list contains all the relevant local roles, as well as those retrieved by the delegate, in this order.
  137.      **********************************************************************************************************************************************************/
  138.     @Nonnull
  139.     public <T> Collection<T> asMany (@Nonnull final Class<? extends T> type)
  140.       {
  141.         final var results = new ArrayList<T>();

  142.         for (final var role : roles)
  143.           {
  144.             if (type.isAssignableFrom(role.getClass()))
  145.               {
  146.                 results.add(type.cast(role));
  147.               }
  148.           }

  149.         results.addAll(ownerRoleFactory.get().findRoles(type));

  150.         return results;
  151.       }
  152.   }