DefaultCacheManager.java

  1. /*
  2.  * *********************************************************************************************************************
  3.  *
  4.  * blueMarine II: Semantic Media Centre
  5.  * http://tidalwave.it/projects/bluemarine2
  6.  *
  7.  * Copyright (C) 2015 - 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/bluemarine2-src
  23.  * git clone https://github.com/tidalwave-it/bluemarine2-src
  24.  *
  25.  * *********************************************************************************************************************
  26.  */
  27. package it.tidalwave.bluemarine2.model.impl;

  28. import javax.annotation.Nonnull;
  29. import java.util.Map;
  30. import java.util.concurrent.ConcurrentHashMap;
  31. import java.util.function.Supplier;
  32. import java.lang.ref.SoftReference;
  33. import it.tidalwave.messagebus.annotation.ListensTo;
  34. import it.tidalwave.messagebus.annotation.SimpleMessageSubscriber;
  35. import it.tidalwave.bluemarine2.message.PersistenceInitializedNotification;
  36. import it.tidalwave.bluemarine2.model.spi.CacheManager;
  37. import lombok.extern.slf4j.Slf4j;
  38. import lombok.RequiredArgsConstructor;
  39. import static java.util.Objects.*;

  40. /***********************************************************************************************************************
  41.  *
  42.  * @author  Fabrizio Giudici
  43.  *
  44.  **********************************************************************************************************************/
  45. @Slf4j @SimpleMessageSubscriber
  46. public class DefaultCacheManager implements CacheManager
  47.   {
  48.     private final Map<Object, Cache> cacheMap = new ConcurrentHashMap<>();

  49.     @RequiredArgsConstructor
  50.     static class DefaultCache implements Cache
  51.       {
  52.         @Nonnull
  53.         private final String name;
  54.         // TODO: use Spring ConcurrentReferenceHashMap?
  55.         private final Map<Object, SoftReference<?>> objectMap = new ConcurrentHashMap<>();

  56.         @Override @Nonnull
  57.         public <T> T getCachedObject (@Nonnull final Object key, @Nonnull final Supplier<T> supplier)
  58.           {
  59.             SoftReference<T> ref = (SoftReference<T>)(objectMap.computeIfAbsent(key, k -> computeObject(k, supplier)));
  60.             T object = ref.get();

  61.             if (object == null)
  62.               {
  63.                 objectMap.put(key, ref = computeObject(key, supplier));
  64.                 object = requireNonNull(ref.get(), "Cache returned null");
  65.               }

  66.             return object;
  67.           }

  68.         @Nonnull
  69.         private <T> SoftReference<T> computeObject (@Nonnull final Object key, @Nonnull final Supplier<T> supplier)
  70.           {
  71.             log.info(">>>> cache {} miss for {}", name, key);
  72.             return new SoftReference<>(requireNonNull(supplier.get(), "Supplier returned null"));
  73.           }
  74.       }

  75.     @Override @Nonnull
  76.     public Cache getCache (@Nonnull final Object cacheKey)
  77.       {
  78.         return cacheMap.computeIfAbsent(cacheKey, key -> new DefaultCache(cacheKey.toString()));
  79.       }

  80.     /* visible for testing FIXME */ public void onPersistenceUpdated (@ListensTo final PersistenceInitializedNotification notification)
  81.       {
  82.         log.debug("onPersistenceUpdated({})", notification);
  83.         cacheMap.clear();
  84.       }
  85.   }