MediaFormatProviderManagerImpl.java

  1. /*
  2.  * #%L
  3.  * wcm.io
  4.  * %%
  5.  * Copyright (C) 2014 wcm.io
  6.  * %%
  7.  * Licensed under the Apache License, Version 2.0 (the "License");
  8.  * you may not use this file except in compliance with the License.
  9.  * You may obtain a copy of the License at
  10.  *
  11.  *      http://www.apache.org/licenses/LICENSE-2.0
  12.  *
  13.  * Unless required by applicable law or agreed to in writing, software
  14.  * distributed under the License is distributed on an "AS IS" BASIS,
  15.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16.  * See the License for the specific language governing permissions and
  17.  * limitations under the License.
  18.  * #L%
  19.  */
  20. package io.wcm.handler.media.format.impl;

  21. import java.util.Collection;
  22. import java.util.SortedMap;
  23. import java.util.SortedSet;
  24. import java.util.TreeMap;
  25. import java.util.TreeSet;
  26. import java.util.concurrent.TimeUnit;
  27. import java.util.stream.Collectors;

  28. import org.apache.commons.lang3.StringUtils;
  29. import org.apache.sling.api.resource.Resource;
  30. import org.osgi.framework.Bundle;
  31. import org.osgi.framework.BundleContext;
  32. import org.osgi.framework.Constants;
  33. import org.osgi.framework.ServiceReference;
  34. import org.osgi.service.component.annotations.Activate;
  35. import org.osgi.service.component.annotations.Component;
  36. import org.osgi.service.component.annotations.Reference;
  37. import org.osgi.service.component.annotations.ReferenceCardinality;
  38. import org.osgi.service.component.annotations.ReferencePolicy;
  39. import org.osgi.service.component.annotations.ReferencePolicyOption;

  40. import com.github.benmanes.caffeine.cache.Cache;
  41. import com.github.benmanes.caffeine.cache.Caffeine;

  42. import io.wcm.handler.media.format.MediaFormat;
  43. import io.wcm.handler.media.format.MediaFormatProviderManager;
  44. import io.wcm.handler.media.spi.MediaFormatProvider;
  45. import io.wcm.sling.commons.caservice.ContextAwareServiceResolver;
  46. import io.wcm.sling.commons.caservice.ContextAwareServiceResolver.ResolveAllResult;

  47. /**
  48.  * Default implementation of {@link MediaFormatProviderManager}.
  49.  */
  50. @Component(service = MediaFormatProviderManager.class, immediate = true)
  51. public final class MediaFormatProviderManagerImpl implements MediaFormatProviderManager {

  52.   @Reference
  53.   private ContextAwareServiceResolver serviceResolver;

  54.   @Reference(cardinality = ReferenceCardinality.MULTIPLE,
  55.       policy = ReferencePolicy.STATIC,
  56.       policyOption = ReferencePolicyOption.GREEDY)
  57.   private Collection<ServiceReference<MediaFormatProvider>> mediaFormatProviderServiceReferences;

  58.   private BundleContext bundleContext;

  59.   // cache resolving of media formats per combined cache key of context-aware services
  60.   private final Cache<String, SortedSet<MediaFormat>> cache = Caffeine.newBuilder()
  61.       .expireAfterWrite(1, TimeUnit.HOURS)
  62.       .build();

  63.   @Activate
  64.   private void activate(BundleContext bc) {
  65.     this.bundleContext = bc;
  66.   }

  67.   @Override
  68.   public SortedSet<MediaFormat> getMediaFormats(Resource contextResource) {
  69.     ResolveAllResult<MediaFormatProvider> result = serviceResolver.resolveAll(MediaFormatProvider.class, contextResource);
  70.     String key = result.getCombinedKey();
  71.     return cache.get(key, theKey -> result.getServices()
  72.         .flatMap(provider -> provider.getMediaFormats().stream())
  73.         .collect(Collectors.toCollection(TreeSet::new)));
  74.   }

  75.   @Override
  76.   public SortedMap<String, SortedSet<MediaFormat>> getAllMediaFormats() {
  77.     SortedMap<String, SortedSet<MediaFormat>> result = new TreeMap<>();

  78.     for (ServiceReference<MediaFormatProvider> serviceReference : mediaFormatProviderServiceReferences) {
  79.       Bundle bundle = serviceReference.getBundle();
  80.       String bundleName = StringUtils.defaultString(bundle.getHeaders().get(Constants.BUNDLE_NAME), bundle.getSymbolicName());
  81.       SortedSet<MediaFormat> mediaFormats = result.getOrDefault(bundleName, new TreeSet<>());
  82.       result.putIfAbsent(bundleName, mediaFormats);
  83.       MediaFormatProvider mediaFormatProvider = bundleContext.getService(serviceReference);
  84.       try {
  85.         mediaFormats.addAll(mediaFormatProvider.getMediaFormats());
  86.       }
  87.       finally {
  88.         bundleContext.ungetService(serviceReference);
  89.       }
  90.     }

  91.     return result;
  92.   }

  93. }