RoleCollector.java

  1. /*
  2.  * *************************************************************************************************************************************************************
  3.  *
  4.  * SteelBlue: DCI User Interfaces
  5.  * http://tidalwave.it/projects/steelblue
  6.  *
  7.  * Copyright (C) 2015 - 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/steelblue-src
  22.  * git clone https://github.com/tidalwave-it/steelblue-src
  23.  *
  24.  * *************************************************************************************************************************************************************
  25.  */
  26. package it.tidalwave.ui.javafx.impl.common;

  27. import jakarta.annotation.Nonnull;
  28. import java.util.ArrayList;
  29. import java.util.Collection;
  30. import java.util.HashMap;
  31. import java.util.List;
  32. import java.util.Map;
  33. import java.util.Optional;
  34. import java.util.concurrent.CopyOnWriteArrayList;
  35. import javafx.application.Platform;
  36. import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
  37. import it.tidalwave.ui.core.role.UserAction;
  38. import it.tidalwave.util.As;
  39. import lombok.Getter;
  40. import lombok.extern.slf4j.Slf4j;
  41. import static it.tidalwave.ui.core.role.UserActionProvider._UserActionProvider_;
  42. import static java.util.stream.Collectors.*;
  43. import static it.tidalwave.util.ShortNames.*;

  44. /***************************************************************************************************************************************************************
  45.  *
  46.  * This class collects a bag of roles from a source. It is used to preload roles in a generic thread before using them in a JavaFX thread.
  47.  *
  48.  * @author  Fabrizio Giudici
  49.  *
  50.  **************************************************************************************************************************************************************/
  51. @Slf4j
  52. public class RoleCollector
  53.   {
  54.     private final Map<Class<?>, List<Object>> roleMapByTipe = new HashMap<>();

  55.     /** The default user action, which is the first action of the first {@link it.tidalwave.ui.core.role.UserActionProvider}. */
  56.     @Getter @Nonnull
  57.     private final Optional<UserAction> defaultUserAction;

  58.     /***********************************************************************************************************************************************************
  59.      *
  60.      **********************************************************************************************************************************************************/
  61.     public RoleCollector()
  62.       {
  63.         defaultUserAction = Optional.empty();
  64.       }

  65.     /***********************************************************************************************************************************************************
  66.      * Creates a new instances for the given source and role types.
  67.      * @param   source        the source
  68.      * @param   roleTypes     the types of roles to collect
  69.      **********************************************************************************************************************************************************/
  70.     @SuppressFBWarnings("CT_CONSTRUCTOR_THROW")
  71.     public RoleCollector (@Nonnull final As source, @Nonnull final Iterable<Class<?>> roleTypes)
  72.       {
  73.         if (Platform.isFxApplicationThread())
  74.           {
  75.             throw new IllegalStateException("RoleCollector must not be instantiated in the JavaFX thread");
  76.           }

  77.         if (log.isTraceEnabled())
  78.           {
  79.             log.trace("ctor({}, {})", source, shortNames(roleTypes));
  80.           }

  81.         roleTypes.forEach(roleType -> copyRoles(source, roleType));
  82.         // TODO: perhaps it could be associated to a dummy key, instead of being returned by a getter?
  83.         defaultUserAction = getMany(_UserActionProvider_).stream().flatMap(a -> a.getOptionalDefaultAction().stream()).findFirst();
  84.       }

  85.     /***********************************************************************************************************************************************************
  86.      * Adds a role. This method is useful for tests.
  87.      * @param   roleType      the type of the role
  88.      * @param   role          the role
  89.      **********************************************************************************************************************************************************/
  90.     public <R> void put (@Nonnull final Class<R> roleType, @Nonnull final R role)
  91.       {
  92.         putMany(roleType, List.of(role));
  93.       }

  94.     /***********************************************************************************************************************************************************
  95.      * Adds roles. This method is useful for tests.
  96.      * @param   roleType      the type of the role
  97.      * @param   roles         the roles
  98.      **********************************************************************************************************************************************************/
  99.     private <R> void putMany (@Nonnull final Class<R> roleType, @Nonnull final Collection<? extends R> roles)
  100.       {
  101.         roleMapByTipe.put(roleType, new ArrayList<>(roles));
  102.       }

  103.     /***********************************************************************************************************************************************************
  104.      * {@return a role of thw given type, if present}. If multiple roles for the same type are present, the first is returned.
  105.      * @param   roleType      the type of the role
  106.      **********************************************************************************************************************************************************/
  107.     @Nonnull
  108.     public <R> Optional<R> get (@Nonnull final Class<R> roleType)
  109.       {
  110.         return getMany(roleType).stream().findFirst();
  111.       }

  112.     /***********************************************************************************************************************************************************
  113.      * {@return multiple roles of thw given type}.
  114.      * @param   roleType      the type of the role
  115.      **********************************************************************************************************************************************************/
  116.     @Nonnull @SuppressWarnings("unchecked")
  117.     public <R> List<R> getMany (@Nonnull final Class<R> roleType)
  118.       {
  119.         return new CopyOnWriteArrayList<>((Collection<? extends R>)roleMapByTipe.getOrDefault(roleType, List.of()));
  120.       }

  121.     /***********************************************************************************************************************************************************
  122.      * {@inheritDoc}
  123.      **********************************************************************************************************************************************************/
  124.     @Nonnull
  125.     public String toString()
  126.       {
  127.         return roleMapByTipe.entrySet().stream().map(this::toString).collect(joining(", ", "RoleCollector(", ")"));
  128.       }

  129.     /***********************************************************************************************************************************************************
  130.      *
  131.      **********************************************************************************************************************************************************/
  132.     @Nonnull
  133.     private String toString (@Nonnull final Map.Entry<Class<?>, List<Object>> entry)
  134.       {
  135.         return shortName(entry.getKey()) + ": " + shortIds(entry.getValue());
  136.       }

  137.     /***********************************************************************************************************************************************************
  138.      * Copy roles of the given type.
  139.      * @param   source        the source
  140.      * @param   roleType      the type of roles to collect
  141.      **********************************************************************************************************************************************************/
  142.     private <R> void copyRoles (@Nonnull final As source, @Nonnull final Class<R> roleType)
  143.       {
  144.         putMany(roleType, source.asMany(roleType));
  145.       }
  146.   }