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;
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&lt;T&gt;
54       *       {
55       *         public List&lt;T&gt; retrieve();
56       *       }
57       *
58       *     class CodeSample
59       *       {
60       *         private static final As.Type&lt;DataRetriever&lt;String&gt;&gt; _StringRetriever_ = As.type(DataRetriever.class);
61       *
62       *         public void method (As object)
63       *           {
64       *             List&lt;String&gt; 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   }