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 }