diff --git a/docs/src/docs/asciidoc/user/osgi.adoc b/docs/src/docs/asciidoc/user/osgi.adoc index 2f22bd0e40..ee0d0003bd 100644 --- a/docs/src/docs/asciidoc/user/osgi.adoc +++ b/docs/src/docs/asciidoc/user/osgi.adoc @@ -53,6 +53,8 @@ Additional features can then be added by including one or more of: * `org.ehcache:ehcache-clustered` * `org.ehcache:ehcache-transactions` +In order to defer starting OSGi DS components which leverage `org.ehcache.core.CacheManager` (for example via `CacheManagerBuilder`) or `javax.cache.spi.CachingProvider` (for example via `javax.cache.Caching`) until all relevant services for Ehcache are available one can leverage the https://docs.osgi.org/specification/osgi.core/8.0.0/service.condition.html[OSGi condition] with id `ehcache`. + === Reverting to JDK Service Lookup If the `org.ehcache.core.osgi` property is set to `"false"` as either a framework or system property then Ehcache will diff --git a/ehcache-impl/build.gradle b/ehcache-impl/build.gradle index 94674d88ef..5d21670fed 100644 --- a/ehcache-impl/build.gradle +++ b/ehcache-impl/build.gradle @@ -54,6 +54,8 @@ dependencies { implementation group: 'org.ehcache', name: 'sizeof', version: parent.sizeofVersion implementation group: 'org.terracotta', name: 'terracotta-utilities-tools', version: parent.terracottaUtilitiesVersion compileOnly 'org.osgi:org.osgi.service.component.annotations:1.3.0' + compileOnly 'org.osgi:org.osgi.service.component:1.3.0' + implementation 'org.osgi:org.osgi.service.condition:1.0.0' testImplementation project(':core-spi-test') testImplementation 'org.ow2.asm:asm:6.2' testImplementation 'org.ow2.asm:asm-commons:6.2' @@ -65,7 +67,7 @@ jar { bnd ( 'Export-Package': '!org.ehcache.impl.internal.*, org.ehcache.impl.*, org.ehcache.config.builders, ' + 'org.ehcache.impl.internal.spi.loaderwriter', //ugly 107 induced internal export wart - 'Import-Package': '!sun.misc, !javax.annotation, *', + 'Import-Package': '!sun.misc, !javax.annotation, org.osgi.service.condition;resolution:=optional, *', ) } diff --git a/ehcache-impl/src/main/java/org/ehcache/impl/osgi/EhcacheReadyCondition.java b/ehcache-impl/src/main/java/org/ehcache/impl/osgi/EhcacheReadyCondition.java new file mode 100644 index 0000000000..d5edffd442 --- /dev/null +++ b/ehcache-impl/src/main/java/org/ehcache/impl/osgi/EhcacheReadyCondition.java @@ -0,0 +1,72 @@ +/* + * Copyright Terracotta, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.ehcache.impl.osgi; + +import org.ehcache.core.EhcacheManager; +import org.ehcache.core.events.CacheEventDispatcherFactory; +import org.ehcache.core.events.CacheEventListenerProvider; +import org.ehcache.core.spi.service.ServiceFactory; +import org.ehcache.core.spi.store.Store; +import org.ehcache.impl.internal.spi.resilience.DefaultResilienceStrategyProvider; +import org.ehcache.impl.internal.store.tiering.TieredStore; +import org.ehcache.impl.internal.store.tiering.TieredStoreProviderFactory; +import org.ehcache.spi.loaderwriter.CacheLoaderWriterProvider; +import org.ehcache.spi.loaderwriter.WriteBehindProvider; +import org.ehcache.spi.resilience.ResilienceStrategyProvider; +import org.ehcache.spi.serialization.SerializationProvider; +import org.osgi.service.component.ComponentConstants; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.condition.Condition; + +/** + * The condition is satisfied once all default {@link ServiceFactory} classes mentioned in {@link EhcacheManager} or {@link EhcacheCachingProvider} are registered. + * Those are + *
    + *
  1. {@link Store.Provider} provided through DS component {@link TieredStoreProviderFactory}
  2. + *
  3. {@link CacheLoaderWriterProvider} provided through DS component {@link DefaultCacheLoaderWriterProviderFactory}
  4. + *
  5. {@link WriteBehindProvider} provided through DS component {@link WriteBehindProviderFactory}
  6. + *
  7. {@link CacheEventDispatcherFactory} provided through DS component {@link CacheEventNotificationListenerServiceProviderFactory}
  8. + *
  9. {@link CacheEventListenerProvider} provided through DS component {@link DefaultCacheEventListenerProviderFactory}
  10. + *
  11. {@link ResilienceStrategyProvider} provided through DS component {@link DefaultResilienceStrategyProvider}
  12. + *
  13. {@link SerializationProvider} provided through DS component {@link DefaultSerializationProviderFactory}
  14. + *
+ * Because those services are not provided directly but through {@link ServiceFactory} this condition references directly the responsible default factories (via their component name) + */ +@Component(property = Condition.CONDITION_ID + "=ehcache") +public class EhcacheReadyCondition implements Condition { + + @Reference(target = "("+ComponentConstants.COMPONENT_NAME+"=org.ehcache.impl.internal.store.tiering.TieredStoreProviderFactory)") + private ServiceFactory storeProviderFactory; + + @Reference(target = "("+ComponentConstants.COMPONENT_NAME+"=org.ehcache.impl.internal.spi.loaderwriter.DefaultCacheLoaderWriterProviderFactory)") + private ServiceFactory cacheLoaderWriterProviderFactory; + + @Reference(target = "("+ComponentConstants.COMPONENT_NAME+"=org.ehcache.impl.internal.loaderwriter.writebehind.WriteBehindProviderFactory)") + private ServiceFactory writeBehindProviderFactory; + + @Reference(target = "("+ComponentConstants.COMPONENT_NAME+"=org.ehcache.impl.internal.events.CacheEventNotificationListenerServiceProviderFactory)") + private ServiceFactory cacheEventNotificationListenerServiceProviderFactory; + + @Reference(target = "("+ComponentConstants.COMPONENT_NAME+"=org.ehcache.impl.internal.spi.event.DefaultCacheEventListenerProviderFactory)") + private ServiceFactory cacheEventListenerProviderFactory; + + @Reference(target = "("+ComponentConstants.COMPONENT_NAME+"=org.ehcache.impl.internal.spi.resilience.DefaultResilienceStrategyProviderFactory)") + private ServiceFactory resilienceStrategyProviderFactory; + + @Reference(target = "("+ComponentConstants.COMPONENT_NAME+"=org.ehcache.impl.internal.spi.serialization.DefaultSerializationProviderFactory)") + private ServiceFactory serializationProviderFactory; +}