From b69693b7b2ba95e28c9a564606c35b8406ee2107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= Date: Fri, 16 Feb 2024 06:10:05 +0100 Subject: [PATCH] Add support for Coordinator to Equinox Configuration Admin Chapter 11 of the Configuration Admin Service Specification mandates the support of the Coordinator service but currently Equinox fails the TCK tests in that area. This adds support for participation in the coordinator for the Equinox Configuration Admin. --- .../META-INF/MANIFEST.MF | 3 +- .../cm/ConfigurationAdminFactory.java | 76 +++++++++++++++++-- .../cm/ManagedServiceFactoryTracker.java | 11 +-- .../internal/cm/ManagedServiceTracker.java | 27 ++++--- 4 files changed, 91 insertions(+), 26 deletions(-) diff --git a/bundles/org.eclipse.equinox.cm/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.cm/META-INF/MANIFEST.MF index 84a50cbb60e..6d95f2232bc 100644 --- a/bundles/org.eclipse.equinox.cm/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.equinox.cm/META-INF/MANIFEST.MF @@ -8,8 +8,9 @@ Bundle-Version: 1.6.0.qualifier Bundle-Activator: org.eclipse.equinox.internal.cm.Activator Import-Package: org.osgi.framework;version="1.7.0", org.osgi.service.cm;version="[1.6,1.7)", + org.osgi.service.coordinator;version="[1.0.0,2.0.0]", + org.osgi.service.event;version="1.0";resolution:=optional, org.osgi.service.log;version="1.3.0", - org.osgi.service.event;version="1.0"; resolution:=optional, org.osgi.util.tracker;version="1.3.1" Bundle-RequiredExecutionEnvironment: JavaSE-17 Provide-Capability: diff --git a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationAdminFactory.java b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationAdminFactory.java index 14e1dfce0e4..2731e567cb7 100644 --- a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationAdminFactory.java +++ b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationAdminFactory.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2019 Cognos Incorporated, IBM Corporation and others. + * Copyright (c) 2005, 2024 Cognos Incorporated, IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -11,14 +11,19 @@ * Contributors: * Cognos Incorporated - initial API and implementation * IBM Corporation - bug fixes and enhancements + * Christoph Läubrich - add support for Coordinator *******************************************************************************/ package org.eclipse.equinox.internal.cm; import java.security.Permission; -import java.util.Dictionary; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Predicate; import org.osgi.framework.*; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.cm.ConfigurationPermission; +import org.osgi.service.coordinator.*; +import org.osgi.util.tracker.ServiceTracker; /** * ConfigurationAdminFactory provides a Configuration Admin ServiceFactory but @@ -37,6 +42,9 @@ public class ConfigurationAdminFactory implements ServiceFactory coordinationServiceTracker; + + private final Map coordinationParticipants = new ConcurrentHashMap<>(); public ConfigurationAdminFactory(BundleContext context, LogTracker log) { this.log = log; @@ -45,9 +53,11 @@ public ConfigurationAdminFactory(BundleContext context, LogTracker log) { pluginManager = new PluginManager(context); managedServiceTracker = new ManagedServiceTracker(this, configurationStore, context); managedServiceFactoryTracker = new ManagedServiceFactoryTracker(this, configurationStore, context); + coordinationServiceTracker = new ServiceTracker<>(context, Coordinator.class, null); } void start() { + coordinationServiceTracker.open(); eventDispatcher.start(); pluginManager.start(); managedServiceTracker.open(); @@ -59,6 +69,7 @@ void stop() { managedServiceFactoryTracker.close(); eventDispatcher.stop(); pluginManager.stop(); + coordinationServiceTracker.close(); } @Override @@ -137,17 +148,24 @@ void dispatchEvent(int type, String factoryPid, String pid) { } void notifyConfigurationUpdated(ConfigurationImpl config, boolean isFactory) { - if (isFactory) + if (isFactory) { managedServiceFactoryTracker.notifyUpdated(config); - else + } else { managedServiceTracker.notifyUpdated(config); + } + } + + ConfigurationAdminParticipant coordinationParticipant(Coordination coordination) { + return coordinationParticipants.computeIfAbsent(coordination.getId(), + c -> new ConfigurationAdminParticipant(coordination)); } void notifyConfigurationDeleted(ConfigurationImpl config, boolean isFactory) { - if (isFactory) + if (isFactory) { managedServiceFactoryTracker.notifyDeleted(config); - else + } else { managedServiceTracker.notifyDeleted(config); + } } void notifyLocationChanged(ConfigurationImpl config, String oldLocation, boolean isFactory) { @@ -161,4 +179,50 @@ void notifyLocationChanged(ConfigurationImpl config, String oldLocation, boolean Dictionary modifyConfiguration(ServiceReference reference, ConfigurationImpl config) { return pluginManager.modifyConfiguration(reference, config); } + + Optional coordinate() { + return Optional.ofNullable(coordinationServiceTracker.getService()).map(Coordinator::peek) + .filter(Predicate.not(Coordination::isTerminated)); + } + + private final class ConfigurationAdminParticipant implements Participant { + + private Map tasks = new HashMap<>(); + + public ConfigurationAdminParticipant(Coordination coordination) { + coordination.addParticipant(this); + } + + @Override + public void ended(Coordination coordination) throws Exception { + finish(coordination); + } + + @Override + public void failed(Coordination coordination) throws Exception { + finish(coordination); + } + + private void finish(Coordination coordination) { + tasks.values().forEach(Runnable::run); + tasks.clear(); + } + + public void cancelTask(Object key) { + tasks.remove(key); + } + + public void addTask(Object key, Runnable runnable) { + tasks.put(key, runnable); + } + } + + void executeCoordinated(Object key, Runnable runnable) { + coordinate().ifPresentOrElse(coordination -> coordinationParticipant(coordination).addTask(key, runnable), + () -> runnable.run()); + } + + void cancelExecuteCoordinated(Object key) { + coordinate().ifPresent(coordination -> coordinationParticipant(coordination).cancelTask(key)); + } } diff --git a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ManagedServiceFactoryTracker.java b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ManagedServiceFactoryTracker.java index 11559251ad1..625f75e50c4 100644 --- a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ManagedServiceFactoryTracker.java +++ b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ManagedServiceFactoryTracker.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2018 Cognos Incorporated, IBM Corporation and others. + * Copyright (c) 2005, 2024 Cognos Incorporated, IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -11,6 +11,7 @@ * Contributors: * Cognos Incorporated - initial API and implementation * IBM Corporation - bug fixes and enhancements + * Christoph Läubrich - add support for Coordinator *******************************************************************************/ package org.eclipse.equinox.internal.cm; @@ -289,9 +290,9 @@ private void asynchUpdated(final ManagedServiceFactory service, final String pid if (properties == null) { return; } - queue.put(new Runnable() { - @Override - public void run() { + configurationAdminFactory.cancelExecuteCoordinated(service); + configurationAdminFactory.executeCoordinated(service, () -> { + queue.put(() -> { try { service.updated(pid, properties); } catch (ConfigurationException e) { @@ -301,7 +302,7 @@ public void run() { } catch (Throwable t) { configurationAdminFactory.error(t.getMessage(), t); } - } + }); }); } } diff --git a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ManagedServiceTracker.java b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ManagedServiceTracker.java index 5201f0034d9..0b9eb679682 100644 --- a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ManagedServiceTracker.java +++ b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ManagedServiceTracker.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2018 Cognos Incorporated, IBM Corporation and others. + * Copyright (c) 2005, 2024 Cognos Incorporated, IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -11,6 +11,7 @@ * Contributors: * Cognos Incorporated - initial API and implementation * IBM Corporation - bug fixes and enhancements + * Christoph Läubrich - add support for Coordinator *******************************************************************************/ package org.eclipse.equinox.internal.cm; @@ -283,19 +284,17 @@ private List> getManagedServiceReferences(Strin } private void asynchUpdated(final ManagedService service, final Dictionary properties) { - queue.put(new Runnable() { - @Override - public void run() { - try { - service.updated(properties); - } catch (ConfigurationException e) { - // we might consider doing more for ConfigurationExceptions - Throwable cause = e.getCause(); - configurationAdminFactory.error(e.getMessage(), cause != null ? cause : e); - } catch (Throwable t) { - configurationAdminFactory.error(t.getMessage(), t); - } + configurationAdminFactory.cancelExecuteCoordinated(service); + configurationAdminFactory.executeCoordinated(service, () -> queue.put(() -> { + try { + service.updated(properties); + } catch (ConfigurationException e) { + // we might consider doing more for ConfigurationExceptions + Throwable cause = e.getCause(); + configurationAdminFactory.error(e.getMessage(), cause != null ? cause : e); + } catch (Throwable t) { + configurationAdminFactory.error(t.getMessage(), t); } - }); + })); } }