View Javadoc
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.util.impl;
27  
28  import jakarta.annotation.Nonnull;
29  import java.util.ArrayList;
30  import java.util.Collection;
31  import java.util.Collections;
32  import java.util.List;
33  import java.util.Optional;
34  import java.util.function.Function;
35  import it.tidalwave.util.As;
36  import it.tidalwave.util.LazySupplier;
37  import it.tidalwave.util.Parameters;
38  import it.tidalwave.util.RoleFactory;
39  import it.tidalwave.role.spi.OwnerRoleFactory;
40  import it.tidalwave.role.spi.OwnerRoleFactoryProvider;
41  import static it.tidalwave.util.Parameters.r;
42  
43  /***************************************************************************************************************************************************************
44   *
45   * An implementation of {@link As} that keeps some local roles and queries {@link OwnerRoleFactory}.
46   *
47   * @author  Fabrizio Giudici
48   *
49   **************************************************************************************************************************************************************/
50  public class AsDelegate implements As
51    {
52      @Nonnull
53      private final LazySupplier<OwnerRoleFactory> ownerRoleFactory;
54  
55      @Nonnull
56      private final List<Object> roles = new ArrayList<>();
57  
58      /***********************************************************************************************************************************************************
59       * Constructor for use in composition.
60       * @param  owner          the owner
61       * @since  3.2-ALPHA-3 (refactored)
62       **********************************************************************************************************************************************************/
63      public AsDelegate (@Nonnull final Object owner)
64        {
65          this(owner, Collections.emptyList());
66        }
67  
68      /***********************************************************************************************************************************************************
69       * Constructor for use in composition. In addition to the mandatory owner, it accepts a single pre-instantiated role, or a {@link RoleFactory} that will be
70       * invoked to create additional roles.
71       * @param  owner          the owner
72       * @param  role           the role or {@link it.tidalwave.util.RoleFactory}
73       * @since  3.2-ALPHA-3
74       **********************************************************************************************************************************************************/
75      public AsDelegate (@Nonnull final Object owner, @Nonnull final Object role)
76        {
77          this(owner, r(Parameters.mustNotBeArrayOrCollection(role, "role")));
78        }
79  
80      /***********************************************************************************************************************************************************
81       * Constructor for use in composition. In addition to the mandatory owner, it accepts a collection of pre-instantiated roles, or instances of
82       * {@link RoleFactory} that will be invoked to create additional roles.
83       * @param  owner          the owner
84       * @param  roles          roles or {@link it.tidalwave.util.RoleFactory} instances
85       * @since  3.2-ALPHA-3 (refactored)
86       **********************************************************************************************************************************************************/
87      public AsDelegate (@Nonnull final Object owner, @Nonnull final Collection<Object> roles)
88        {
89          this(o -> OwnerRoleFactoryProvider.getInstance().createRoleFactory(o), owner, roles);
90        }
91  
92      /***********************************************************************************************************************************************************
93       * Constructor for use in tests. This constructor doesn't call {@link OwnerRoleFactoryProvider#getInstance()}.
94       * @param  systemRoleFactoryFunction  the factory
95       * @param  owner          the owner
96       * @param  roles          roles or {@link it.tidalwave.util.RoleFactory} instances
97       * @since  3.2-ALPHA-3 (refactored)
98       **********************************************************************************************************************************************************/
99      public AsDelegate (@Nonnull final Function<Object, OwnerRoleFactory> systemRoleFactoryFunction,
100                        @Nonnull final Object owner,
101                        @Nonnull final Collection<Object> roles)
102       {
103         ownerRoleFactory = LazySupplier.of(() -> systemRoleFactoryFunction.apply(owner));
104         this.roles.addAll(RoleFactory.resolveFactories(owner, roles));
105       }
106 
107     /***********************************************************************************************************************************************************
108      * {@inheritDoc}
109      **********************************************************************************************************************************************************/
110     @Override @Nonnull
111     public <T> Optional<T> maybeAs (@Nonnull final Class<? extends T> type)
112       {
113         for (final var role : roles)
114           {
115             if (type.isAssignableFrom(role.getClass()))
116               {
117                 return Optional.of(type.cast(role));
118               }
119           }
120 
121         final var r = ownerRoleFactory.get().findRoles(type);
122         return r.isEmpty() ? Optional.empty() : Optional.of(r.iterator().next());
123       }
124 
125     /***********************************************************************************************************************************************************
126      * {@inheritDoc}
127      **********************************************************************************************************************************************************/
128     @Override @Nonnull
129     public <T> Collection<T> asMany (@Nonnull final Class<? extends T> type)
130       {
131         final var results = new ArrayList<T>();
132 
133         for (final var role : roles)
134           {
135             if (type.isAssignableFrom(role.getClass()))
136               {
137                 results.add(type.cast(role));
138               }
139           }
140 
141         results.addAll(ownerRoleFactory.get().findRoles(type));
142         return results;
143       }
144   }