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..36861f8396a 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,18 @@ * 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.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,17 +41,20 @@ public class ConfigurationAdminFactory implements ServiceFactory coordinationServiceTracker; public ConfigurationAdminFactory(BundleContext context, LogTracker log) { this.log = log; configurationStore = new ConfigurationStore(this, context); - eventDispatcher = new EventDispatcher(context, log); + eventDispatcher = new EventDispatcher(context, log, this); 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 +66,7 @@ void stop() { managedServiceFactoryTracker.close(); eventDispatcher.stop(); pluginManager.stop(); + coordinationServiceTracker.close(); } @Override @@ -161,4 +169,56 @@ void notifyLocationChanged(ConfigurationImpl config, String oldLocation, boolean Dictionary modifyConfiguration(ServiceReference reference, ConfigurationImpl config) { return pluginManager.modifyConfiguration(reference, config); } + + ConfigurationAdminParticipant coordinationParticipant(Coordination coordination) { + return coordination.getParticipants().stream().filter(ConfigurationAdminParticipant.class::isInstance) + .map(ConfigurationAdminParticipant.class::cast).findFirst() + .orElseGet(() -> new ConfigurationAdminParticipant(coordination)); + } + + 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 LinkedHashMap<>(); + + 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/ConfigurationImpl.java b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationImpl.java index 32f51e7ab9c..ff38dc85cde 100644 --- a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationImpl.java +++ b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/ConfigurationImpl.java @@ -21,6 +21,7 @@ import java.util.concurrent.locks.ReentrantLock; import org.osgi.framework.*; import org.osgi.service.cm.*; +import org.osgi.service.coordinator.Coordination; /** * ConfigurationImpl provides the Configuration implementation. The lock and @@ -53,6 +54,7 @@ class ConfigurationImpl implements Configuration { /** @GuardedBy lock */ private boolean readOnly = false; private final ReentrantLock lock = new ReentrantLock(); + private final long coordinationId; public ConfigurationImpl(ConfigurationAdminFactory configurationAdminFactory, ConfigurationStore configurationStore, String factoryPid, String pid, String bundleLocation, boolean bind) { @@ -63,6 +65,7 @@ public ConfigurationImpl(ConfigurationAdminFactory configurationAdminFactory, Co this.bundleLocation = bundleLocation; this.changeCount = 0; this.bound = bind; + this.coordinationId = configurationAdminFactory.coordinate().map(Coordination::getId).orElse(-1l); } public ConfigurationImpl(ConfigurationAdminFactory configurationAdminFactory, ConfigurationStore configurationStore, @@ -83,6 +86,11 @@ public ConfigurationImpl(ConfigurationAdminFactory configurationAdminFactory, Co updateDictionary(dictionary); } this.storageToken = storageToken; + this.coordinationId = -1; + } + + long getCoordinationId() { + return coordinationId; } void lock() { diff --git a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/EventDispatcher.java b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/EventDispatcher.java index ad7004faee2..281cc1d1109 100644 --- a/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/EventDispatcher.java +++ b/bundles/org.eclipse.equinox.cm/src/org/eclipse/equinox/internal/cm/EventDispatcher.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; @@ -33,9 +34,11 @@ public class EventDispatcher { /** @GuardedBy this */ private ServiceReference configAdminReference; final LogTracker log; + private ConfigurationAdminFactory configurationAdminFactory; - public EventDispatcher(BundleContext context, LogTracker log) { + public EventDispatcher(BundleContext context, LogTracker log, ConfigurationAdminFactory configurationAdminFactory) { this.log = log; + this.configurationAdminFactory = configurationAdminFactory; tracker = new ServiceTracker<>(context, ConfigurationListener.class, null); syncTracker = new ServiceTracker<>(context, SynchronousConfigurationListener.class, null); } @@ -81,27 +84,32 @@ public void dispatchEvent(int type, String factoryPid, String pid) { return; for (final ServiceReference ref : refs) { - queue.put(new Runnable() { - @Override - public void run() { - ConfigurationListener listener = tracker.getService(ref); - if (listener == null) { - return; - } - try { - listener.configurationEvent(event); - } catch (Throwable t) { - log.error(t.getMessage(), t); - } - } - }); + configurationAdminFactory.executeCoordinated(new Object(), () -> enqueue(event, ref)); } } + protected void enqueue(final ConfigurationEvent event, final ServiceReference ref) { + queue.put(new Runnable() { + @Override + public void run() { + ConfigurationListener listener = tracker.getService(ref); + if (listener == null) { + return; + } + try { + listener.configurationEvent(event); + } catch (Throwable t) { + log.error(t.getMessage(), t); + } + } + }); + } + private synchronized ConfigurationEvent createConfigurationEvent(int type, String factoryPid, String pid) { if (configAdminReference == null) return null; return new ConfigurationEvent(configAdminReference, type, factoryPid, pid); } + } 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..b3658dc2a27 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; @@ -286,12 +287,12 @@ public void run() { private void asynchUpdated(final ManagedServiceFactory service, final String pid, final Dictionary properties) { + configurationAdminFactory.cancelExecuteCoordinated(service); if (properties == null) { return; } - queue.put(new Runnable() { - @Override - public void run() { + 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..809169e1dff 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; @@ -60,13 +61,29 @@ void notifyDeleted(ConfigurationImpl config) { synchronized (targets) { qualifiedPidLists = targets.getQualifiedPids(ref); } +// if (isDeletedInCoordination(config)) { +// // the configuration was created in a coordination but deleted before it was +// // finished, the update was never delivered to the managed service so we do not +// // need to propagate the delete either +// configurationAdminFactory.cancelExecuteCoordinated(service); +// } else { updateManagedService(qualifiedPidLists, ref, service); +// } } } } } } +// private boolean isDeletedInCoordination(ConfigurationImpl config) { +// long coordinationId = config.getCoordinationId(); +// if (coordinationId > 0) { +// long currentId = configurationAdminFactory.coordinate().map(Coordination::getId).orElse(-1l); +// return currentId == coordinationId; +// } +// return false; +// } + void notifyUpdated(ConfigurationImpl config) { config.checkLocked(); String configLoc = config.getLocation(); @@ -202,13 +219,14 @@ public void modifiedService(ServiceReference reference, ManagedS @Override public void removedService(ServiceReference reference, ManagedService service) { untrackManagedService(reference); - + configurationAdminFactory.cancelExecuteCoordinated(service); context.ungetService(reference); } private void addReference(ServiceReference reference, ManagedService service) { List> qualifiedPidLists = trackManagedService(reference); - updateManagedService(qualifiedPidLists, reference, service); + configurationAdminFactory.executeCoordinated(service, + () -> updateManagedService(qualifiedPidLists, reference, service)); } private void updateManagedService(List> qualifiedPidLists, ServiceReference reference, @@ -283,19 +301,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); } - }); + })); } }