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