ContextManager.java

  1. /*
  2.  * *********************************************************************************************************************
  3.  *
  4.  * TheseFoolishThings: Miscellaneous utilities
  5.  * http://tidalwave.it/projects/thesefoolishthings
  6.  *
  7.  * Copyright (C) 2009 - 2021 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.role;

  28. import javax.annotation.CheckForNull;
  29. import javax.annotation.Nonnull;
  30. import java.util.Iterator;
  31. import java.util.List;
  32. import java.util.Objects;
  33. import java.util.ServiceLoader;
  34. import it.tidalwave.util.NotFoundException;
  35. import it.tidalwave.util.Task;
  36. import it.tidalwave.role.spi.ContextManagerProvider;
  37. import lombok.AccessLevel;
  38. import lombok.NoArgsConstructor;
  39. import lombok.extern.slf4j.Slf4j;

  40. /***********************************************************************************************************************
  41.  *
  42.  * A facility to register and unregister global and local DCI contexts.
  43.  *
  44.  * @author  Fabrizio Giudici
  45.  *
  46.  **********************************************************************************************************************/
  47. public interface ContextManager
  48.   {
  49.     // We must compile with Java 7
  50.     public static interface Supplier<V>
  51.       {
  52.         public V get();
  53.       }

  54.     /*******************************************************************************************************************
  55.      *
  56.      * A locator for the {@link ContextManager} which uses the {@link ServiceLoader} facility to be independent of
  57.      * any DI framework.
  58.      *
  59.      * This locator caches the internal reference and this is ok for production use; during tests, since multiple
  60.      * contexts are typically created and destroyed for each test, you should call {@link #reset()} after each test
  61.      * has been completed.
  62.      *
  63.      ******************************************************************************************************************/
  64.     @Slf4j @NoArgsConstructor(access = AccessLevel.PRIVATE)
  65.     public static final class Locator
  66.       {
  67.         @CheckForNull
  68.         private static ContextManager contextManager;

  69.         @CheckForNull
  70.         private static ContextManagerProvider contextManagerProvider;

  71.         @Nonnull
  72.         public static synchronized ContextManager find ()
  73.           {
  74.             if (contextManager == null)
  75.               {
  76.                 if (contextManagerProvider == null)
  77.                   {
  78.                     final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  79.                     final Iterator<ContextManagerProvider> i =
  80.                             ServiceLoader.load(ContextManagerProvider.class, classLoader).iterator();

  81.                     if (!i.hasNext())
  82.                       {
  83.                         throw new RuntimeException("No ServiceProvider for ContextManagerProvider");
  84.                       }

  85.                     contextManagerProvider = Objects.requireNonNull(i.next());
  86.                     assert contextManagerProvider != null : "contextManagerProvider is null";
  87.                     log.trace("ContextManagerProvider instantiated from META-INF: {}", contextManagerProvider);
  88.                   }

  89.                 contextManager = Objects.requireNonNull(contextManagerProvider.getContextManager(),
  90.                                                         "Cannot find ContextManager");
  91.               }

  92.             assert contextManager != null : "contextManager is null";
  93.             return contextManager;
  94.           }

  95.         /***************************************************************************************************************
  96.          *
  97.          * <b>This method is for testing only.</b> Sets the global {@link ContextManagerProvider}. See note about
  98.          * {@link #reset()}.
  99.          *
  100.          * @param   provider    the provider
  101.          * @see     #reset()
  102.          *
  103.          **************************************************************************************************************/
  104.         public static void set (@Nonnull final ContextManagerProvider provider)
  105.           {
  106.             contextManager = null;
  107.             contextManagerProvider = provider;
  108.           }

  109.         /***************************************************************************************************************
  110.          *
  111.          * <b>This method is for testing only.</b> Resets the global {@link ContextManagerProvider}; it must be called
  112.          * at the test completion whenever {@link #set(ContextManagerProvider)} has been called, to avoid polluting the
  113.          * context of further tests.
  114.          *
  115.          * @see     #set(ContextManagerProvider)
  116.          *
  117.          **************************************************************************************************************/
  118.         public static void reset()
  119.           {
  120.             contextManager = null;
  121.             contextManagerProvider = null;
  122.           }
  123.       }

  124.     /*******************************************************************************************************************
  125.      *
  126.      * Returns the list of current contexts, ordered by their priority.
  127.      *
  128.      * @return  the list of current contexts
  129.      *
  130.      ******************************************************************************************************************/
  131.     @Nonnull
  132.     public List<Object> getContexts();

  133.     /*******************************************************************************************************************
  134.      *
  135.      * Finds a current context instance of the given type.
  136.      *
  137.      * @param   <T>                the static context type
  138.      * @param   contextType        the dynamic context type
  139.      * @return                     the requested context
  140.      * @throws  NotFoundException  if no context of that type is found
  141.      *
  142.      ******************************************************************************************************************/
  143.     @Nonnull
  144.     public <T> T findContextOfType (@Nonnull Class<T> contextType)
  145.       throws NotFoundException;

  146.     /*******************************************************************************************************************
  147.      *
  148.      * Adds a global context.
  149.      *
  150.      * @param  context             the new context
  151.      *
  152.      ******************************************************************************************************************/
  153.     public void addGlobalContext (@Nonnull Object context);

  154.     /*******************************************************************************************************************
  155.      *
  156.      * Removes a global context.
  157.      *
  158.      * @param  context            the context
  159.      *
  160.      ******************************************************************************************************************/
  161.     public void removeGlobalContext (@Nonnull Object context);

  162.     /*******************************************************************************************************************
  163.      *
  164.      * Adds a local context.
  165.      *
  166.      * @param  context            the new context
  167.      *
  168.      ******************************************************************************************************************/
  169.     public void addLocalContext (@Nonnull Object context);

  170.     /*******************************************************************************************************************
  171.      *
  172.      * Removes a local context.
  173.      *
  174.      * @param  context            the context
  175.      *
  176.      ******************************************************************************************************************/
  177.     public void removeLocalContext (@Nonnull Object context);

  178.     /*******************************************************************************************************************
  179.      *
  180.      * Runs a {@link Task} associated with a new local context.
  181.      *
  182.      * @param  <V>                the type of the returned value
  183.      * @param  <T>                the type of the exception that can be thrown
  184.      * @param  context            the context
  185.      * @param  task               the task
  186.      * @return                    the value produced by the task
  187.      * @throws T                  the exception(s) thrown by the task
  188.      *
  189.      ******************************************************************************************************************/
  190.     public <V, T extends Throwable> V runWithContext (@Nonnull Object context, @Nonnull Task<V, T> task)
  191.       throws T;

  192.     /*******************************************************************************************************************
  193.      *
  194.      * Runs a {@link Task} associated with a new bunch of local contexts.
  195.      *
  196.      * @param  <V>                the type of the returned value
  197.      * @param  <T>                the type of the exception that can be thrown
  198.      * @param  contexts           the contexts
  199.      * @param  task               the task
  200.      * @return                    the value produced by the task
  201.      * @throws T                  the exception(s) thrown by the task
  202.      *
  203.      ******************************************************************************************************************/
  204.     public <V, T extends Throwable> V runWithContexts (@Nonnull List<Object> contexts, @Nonnull Task<V, T> task)
  205.       throws T;

  206.     /*******************************************************************************************************************
  207.      *
  208.      * Runs a task associated with a new local context. This variant fits functional interfaces.
  209.      *
  210.      * @param  <V>                the type of the returned value of the task
  211.      * @param  context            the context
  212.      * @param  task               the task
  213.      * @return                    the value produced by the task
  214.      *
  215.      ******************************************************************************************************************/
  216.     public <V> V runWithContext (@Nonnull Object context, @Nonnull Supplier<V> task);

  217.     /*******************************************************************************************************************
  218.      *
  219.      * Runs a task associated with a new bunch of local contexts. This variant fits functional interfaces.
  220.      *
  221.      * @param  <V>                the type of the returned value
  222.      * @param  contexts           the context
  223.      * @param  task               the task
  224.      * @return                    the value produced by the task
  225.      *
  226.      ******************************************************************************************************************/
  227.     public <V> V runWithContexts (@Nonnull List<Object> contexts, @Nonnull Supplier<V> task);
  228.   }