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 }