AsDelegateProvider.java

  1. /*
  2.  * *********************************************************************************************************************
  3.  *
  4.  * TheseFoolishThings: Miscellaneous utilities
  5.  * http://tidalwave.it/projects/thesefoolishthings
  6.  *
  7.  * Copyright (C) 2009 - 2023 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
  12.  * the License. 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
  17.  * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the
  18.  * specific language governing permissions and limitations under the License.
  19.  *
  20.  * *********************************************************************************************************************
  21.  *
  22.  * git clone https://bitbucket.org/tidalwave/thesefoolishthings-src
  23.  * git clone https://github.com/tidalwave-it/thesefoolishthings-src
  24.  *
  25.  * *********************************************************************************************************************
  26.  */
  27. package it.tidalwave.util.spi;

  28. import javax.annotation.Nonnull;
  29. import java.util.ArrayList;
  30. import java.util.Collection;
  31. import java.util.Iterator;
  32. import java.util.ServiceLoader;
  33. import it.tidalwave.util.LazySupplier;
  34. import lombok.AccessLevel;
  35. import lombok.NoArgsConstructor;

  36. /***********************************************************************************************************************
  37.  *
  38.  * @author  Fabrizio Giudici
  39.  *
  40.  **********************************************************************************************************************/
  41. public interface AsDelegateProvider
  42.   {
  43.     public static final LazySupplier<EmptyAsDelegateProvider> EMPTY_REF =
  44.             LazySupplier.of(EmptyAsDelegateProvider::new);

  45.     @NoArgsConstructor(access = AccessLevel.PRIVATE)
  46.     public static final class Locator
  47.       {
  48.         private static final LazySupplier<AsDelegateProvider> AS_DELEGATE_PROVIDER_REF =
  49.                 LazySupplier.of(Locator::findAsSpiProvider);

  50.         @Nonnull
  51.         public static AsDelegateProvider find()
  52.           {
  53.             return AS_DELEGATE_PROVIDER_REF.get();
  54.           }

  55.         @Nonnull
  56.         private static AsDelegateProvider findAsSpiProvider()
  57.           {
  58.             final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  59.             final Iterator<AsDelegateProvider> i =
  60.                     ServiceLoader.load(AsDelegateProvider.class, classLoader).iterator();

  61.             if (!i.hasNext())
  62.               {
  63.                 final String message = "No ServiceProvider for AsDelegateProvider found in a ServiceLoader - if " +
  64.                                        "you are running tests perhaps you should first call " +
  65.                                        "AsDelegateProvider.Locator.set(AsDelegateProvider.empty()) or " +
  66.                                        "AsDelegateProvider.Locator.set(new MockSimpleAsDelegateProvider()) or " +
  67.                                        "another appropriate AsDelegateProvider";
  68.                 throw new RuntimeException(message);
  69.               }

  70.             return i.next();
  71.           }

  72.         /***************************************************************************************************************
  73.          *
  74.          * <b>This method is for testing only.</b> Sets the global {@link AsDelegateProvider}.
  75.          *
  76.          * @param   provider    the provider
  77.          * @see     #reset()
  78.          *
  79.          **************************************************************************************************************/
  80.         public static void set (@Nonnull final AsDelegateProvider provider)
  81.           {
  82.             AS_DELEGATE_PROVIDER_REF.set(provider);
  83.           }

  84.         /***************************************************************************************************************
  85.          *
  86.          * <b>This method is for testing only.</b> Resets the global {@link AsDelegateProvider}; it must be called at
  87.          * the test completion whenever {@link #set(AsDelegateProvider)} has been called, to avoid polluting the
  88.          * context of further tests.
  89.          *
  90.          * @see     #set(AsDelegateProvider)
  91.          *
  92.          **************************************************************************************************************/
  93.         public static void reset()
  94.           {
  95.             AS_DELEGATE_PROVIDER_REF.clear();
  96.           }
  97.       }

  98.     /*******************************************************************************************************************
  99.      *
  100.      * Creates an {@link AsDelegate} for the given object
  101.      *
  102.      * @param     datum   the object
  103.      * @return            {@code AsDelegate}
  104.      *
  105.      ******************************************************************************************************************/
  106.     @Nonnull
  107.     public AsDelegate createAsDelegate (@Nonnull Object datum);

  108.     /*******************************************************************************************************************
  109.      *
  110.      * Returns an empty implementation. Useful for setting up test environment.
  111.      *
  112.      * <pre>
  113.      * AsDelegateProvider.Locator.set(AsDelegateProvider.empty());
  114.      * </pre>
  115.      *
  116.      * @return    the empty implementation
  117.      * @since     3.2-ALPHA-1
  118.      *
  119.      ******************************************************************************************************************/
  120.     @Nonnull
  121.     public static AsDelegateProvider empty()
  122.       {
  123.         return EMPTY_REF.get();
  124.       }

  125.     /*******************************************************************************************************************
  126.      *
  127.      ******************************************************************************************************************/
  128.     static class EmptyAsDelegateProvider implements AsDelegateProvider
  129.       {
  130.         @Override @Nonnull
  131.         public AsDelegate createAsDelegate (@Nonnull final Object owner)
  132.           {
  133.             return new AsDelegate()
  134.               {
  135.                 @Override @Nonnull
  136.                 public <T> Collection<T> as (@Nonnull final Class<T> type)
  137.                   {
  138.                     return new ArrayList<>(); // must be mutable
  139.                   }
  140.               };
  141.           }
  142.       }
  143.   }