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;
27
28 import jakarta.annotation.Nonnull;
29 import java.util.Collection;
30 import java.util.Optional;
31 import it.tidalwave.util.impl.AsDelegate;
32 import lombok.EqualsAndHashCode;
33 import lombok.RequiredArgsConstructor;
34 import lombok.ToString;
35
36 /***************************************************************************************************************************************************************
37 *
38 * Objects implementing this interface can provide an adapter of the required type. The adapter can be found with a
39 * variety of approaches that depend on the implementation. This capability can be used to implement a design based
40 * on the Data, Context and Interaction pattern (DCI). For further details, please look at the
41 * <a href="http://tidalwave.it/projects/thesefoolishthings">project website</a>, where a tutorial is available.
42 *
43 * @author Fabrizio Giudici
44 * @it.tidalwave.javadoc.stable
45 *
46 **************************************************************************************************************************************************************/
47 public interface As
48 {
49 /***********************************************************************************************************************************************************
50 * A type reference for roles that can be used in place of a class literal, especially when roles with generics are
51 * used. Example of usage:
52 * <pre>
53 * interface DataRetriever<T>
54 * {
55 * public List<T> retrieve();
56 * }
57 *
58 * class CodeSample
59 * {
60 * private static final As.Type<DataRetriever<String>> _StringRetriever_ = As.type(DataRetriever.class);
61 *
62 * public void method (As object)
63 * {
64 * List<String> f3 = object.as(_StringRetriever_).retrieve();
65 * }
66 * }
67 * </pre>
68 *
69 * @param <T> the static type of the role
70 * @since 3.2-ALPHA-12
71 **********************************************************************************************************************************************************/
72 @RequiredArgsConstructor @EqualsAndHashCode @ToString
73 public static final class Type<T>
74 {
75 @Nonnull
76 private final Class<?> type;
77
78
79 @Nonnull @SuppressWarnings("unchecked")
80 /* package */ Class<T> getType()
81 {
82 return (Class<T>)type;
83 }
84 }
85
86 /***********************************************************************************************************************************************************
87 * Creates an {@code As} implementation delegate for the given object (or returns the object itself if it is the
88 * default implementation of {@code As}).
89 * @param object the object
90 * @return the implementation
91 * @since 3.2-ALPHA-12
92 **********************************************************************************************************************************************************/
93 @Nonnull
94 public static As forObject (@Nonnull final Object object)
95 {
96 return (object instanceof AsDelegate) ? (As)object : new AsDelegate(object);
97 }
98
99 /***********************************************************************************************************************************************************
100 * Creates an {@code As} implementation delegate for the given object. It accepts a single pre-instantiated role,
101 * or a {@link RoleFactory} that will be invoked to create additional roles.
102 * @param object the object
103 * @param role the role or {@link it.tidalwave.util.RoleFactory}
104 * @return the implementation
105 * @since 3.2-ALPHA-13
106 **********************************************************************************************************************************************************/
107 @Nonnull
108 public static As forObject (@Nonnull final Object object, @Nonnull final Object role)
109 {
110 return new AsDelegate(object, role);
111 }
112
113 /***********************************************************************************************************************************************************
114 * Creates an {@code As} implementation delegate for the given object. It accepts a collection of pre-instantiated
115 * roles, or instances of {@link RoleFactory} that will be invoked to create additional roles.
116 * @param object the object
117 * @param roles roles or {@link it.tidalwave.util.RoleFactory} instances
118 * @return the implementation
119 * @since 3.2-ALPHA-13
120 **********************************************************************************************************************************************************/
121 @Nonnull
122 public static As forObject (@Nonnull final Object object, @Nonnull final Collection<Object> roles)
123 {
124 return new AsDelegate(object, roles);
125 }
126
127 /***********************************************************************************************************************************************************
128 * Returns an adapter to this object of the specified type. If the implementation can find multiple compliant
129 * adapters, only one will be returned.
130 * @param <T> the static type
131 * @param type the dynamic type
132 * @return the adapter
133 * @throws AsException if no adapter is found
134 **********************************************************************************************************************************************************/
135 @Nonnull
136 public default <T> T as (@Nonnull final Class<? extends T> type)
137 {
138 return maybeAs(type).orElseThrow(() -> new AsException(type));
139 }
140
141 /***********************************************************************************************************************************************************
142 * Returns the requested role or an empty {@link Optional}.
143 * @param <T> the static type
144 * @param type the dynamic type
145 * @return the optional role
146 * @since 3.2-ALPHA-3
147 **********************************************************************************************************************************************************/
148 @Nonnull
149 public <T> Optional<T> maybeAs (@Nonnull Class<? extends T> type);
150
151 /***********************************************************************************************************************************************************
152 * Searches for multiple adapters of the given type and returns them.
153 * @param <T> the static type
154 * @param type the dynamic type
155 * @return a collection of adapters, possibly empty
156 **********************************************************************************************************************************************************/
157 @Nonnull
158 public <T> Collection<T> asMany (@Nonnull Class<? extends T> type);
159
160 /***********************************************************************************************************************************************************
161 * Creates a role type reference.
162 * @param <T> the static type
163 * @param type the dynamic type
164 * @return the type reference
165 * @since 3.2-ALPHA-12
166 **********************************************************************************************************************************************************/
167 @Nonnull
168 public static <T> Type<T> type (@Nonnull final Class<?> type) // FIXME: there's no static check of the argument
169 {
170 return new Type<>(type);
171 }
172
173 /***********************************************************************************************************************************************************
174 * Returns a role for this object of the specified type. If the implementation can find multiple compliant
175 * roles, only one will be returned.
176 * @param <T> the static type
177 * @param type the type reference
178 * @return the role
179 * @since 3.2-ALPHA-12
180 **********************************************************************************************************************************************************/
181 @Nonnull
182 public default <T> T as (@Nonnull final Type<? extends T> type)
183 {
184 return as(type.getType());
185 }
186
187 /***********************************************************************************************************************************************************
188 * Returns the requested role or an empty {@link Optional}.
189 * @param <T> the static type
190 * @param type the type reference
191 * @return the optional role
192 * @since 3.2-ALPHA-12
193 **********************************************************************************************************************************************************/
194 @Nonnull
195 public default <T> Optional<T> maybeAs (@Nonnull final Type<? extends T> type)
196 {
197 return maybeAs(type.getType());
198 }
199
200 /***********************************************************************************************************************************************************
201 * Searches for multiple roles of the given type and returns them.
202 * @param <T> the static type
203 * @param type the type reference
204 * @return a collection of roles, possibly empty
205 * @since 3.2-ALPHA-12
206 **********************************************************************************************************************************************************/
207 @Nonnull
208 public default <T> Collection<T> asMany (@Nonnull final Type<? extends T> type)
209 {
210 return asMany(type.getType());
211 }
212 }