Update effects should execute in proper order
and only when update signal does not trigger a refresh
diff --git a/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/BaseOSGiImpl.java b/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/BaseOSGiImpl.java
index f9c658b..1f9a222 100644
--- a/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/BaseOSGiImpl.java
+++ b/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/BaseOSGiImpl.java
@@ -23,6 +23,7 @@
import java.util.HashMap;
import java.util.IdentityHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -259,13 +260,17 @@
}
},
() -> {
- boolean refresh = terminator.update();
+ AtomicBoolean atomicBoolean = new AtomicBoolean();
- if (!refresh) {
- onUpdate.accept(t);
- }
+ UpdateSupport.deferPublication(() -> {
+ if (!atomicBoolean.get()) {
+ onUpdate.accept(t);
+ }
+ });
- return refresh;
+ atomicBoolean.set(terminator.update());
+
+ return atomicBoolean.get();
}
);
diff --git a/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/ConfigurationOSGiImpl.java b/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/ConfigurationOSGiImpl.java
index 2690c05..54698dc 100644
--- a/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/ConfigurationOSGiImpl.java
+++ b/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/ConfigurationOSGiImpl.java
@@ -96,7 +96,7 @@
atomicReference.set(configuration);
}
else {
- if (!terminatorAtomicReference.get().update()) {
+ if (!UpdateSupport.sendUpdate(terminatorAtomicReference.get())) {
return;
}
}
diff --git a/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/ConfigurationsOSGiImpl.java b/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/ConfigurationsOSGiImpl.java
index d718560..d485c53 100644
--- a/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/ConfigurationsOSGiImpl.java
+++ b/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/ConfigurationsOSGiImpl.java
@@ -95,7 +95,7 @@
OSGiResult osgiResult = terminators.get(pid);
- if (osgiResult != null && !osgiResult.update()) {
+ if (osgiResult != null && !UpdateSupport.sendUpdate(osgiResult)) {
return;
}
}
diff --git a/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/EffectsOSGi.java b/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/EffectsOSGi.java
index ed6864a..8b87d38 100644
--- a/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/EffectsOSGi.java
+++ b/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/EffectsOSGi.java
@@ -19,6 +19,8 @@
import org.apache.aries.component.dsl.OSGiResult;
+import java.util.concurrent.atomic.AtomicBoolean;
+
/**
* @author Carlos Sierra Andrés
*/
@@ -58,11 +60,18 @@
}
},
() -> {
- onUpdate.run();
+ AtomicBoolean atomicBoolean = new AtomicBoolean();
- return terminator.update();
- }
- );
+ UpdateSupport.deferPublication(() -> {
+ if (!atomicBoolean.get()) {
+ onUpdate.run();
+ }
+ });
+
+ atomicBoolean.set(terminator.update());
+
+ return atomicBoolean.get();
+ } );
try {
onAddingAfter.run();
diff --git a/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/ServiceReferenceOSGi.java b/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/ServiceReferenceOSGi.java
index 998bbae..e60aa22 100644
--- a/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/ServiceReferenceOSGi.java
+++ b/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/ServiceReferenceOSGi.java
@@ -74,7 +74,7 @@
public void modifiedService(
ServiceReference<T> reference, Tracked<T> tracked) {
- if (tracked.runnable.update()) {
+ if (UpdateSupport.sendUpdate(tracked.runnable)) {
UpdateSupport.runUpdate(() -> {
tracked.runnable.run();
tracked.cachingServiceReference = new CachingServiceReference<>(
diff --git a/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/UpdateSupport.java b/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/UpdateSupport.java
index 253ca30..76bd163 100644
--- a/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/UpdateSupport.java
+++ b/component-dsl/src/main/java/org/apache/aries/component/dsl/internal/UpdateSupport.java
@@ -17,8 +17,11 @@
package org.apache.aries.component.dsl.internal;
+import org.apache.aries.component.dsl.OSGiResult;
+
import java.util.Deque;
import java.util.LinkedList;
+import java.util.function.Supplier;
/**
* @author Carlos Sierra Andrés
@@ -55,6 +58,14 @@
}
public static void runUpdate(Runnable runnable) {
+ UpdateSupport.<Void>runInUpdate(() -> {runnable.run(); return null;});
+ }
+
+ public static boolean sendUpdate(OSGiResult osgiResult) {
+ return runInUpdate(osgiResult::update);
+ }
+
+ public static <R> R runInUpdate(Supplier<R> supplier) {
isUpdate.set(true);
Deque<Deque<Runnable>> deferredPublishers =
@@ -66,7 +77,7 @@
deferredTerminators.addLast(new LinkedList<>());
try {
- runnable.run();
+ return supplier.get();
}
finally {
isUpdate.set(false);
@@ -88,4 +99,5 @@
isUpdate.set(!deferredTerminators.isEmpty());
}
}
+
}
diff --git a/itests/src/main/java/org/apache/aries/component/dsl/test/DSLTest.java b/itests/src/main/java/org/apache/aries/component/dsl/test/DSLTest.java
index 875dc3a..f644a3c 100644
--- a/itests/src/main/java/org/apache/aries/component/dsl/test/DSLTest.java
+++ b/itests/src/main/java/org/apache/aries/component/dsl/test/DSLTest.java
@@ -2202,6 +2202,92 @@
assertEquals(maps, gone);
}
+
+ @Test
+ public void testUpdateEffectsOrder() {
+ ArrayList<String> updateEffects = new ArrayList<>();
+
+ ServiceRegistration<Service> serviceRegistration =
+ bundleContext.registerService(
+ Service.class, new Service(),
+ new Hashtable<String, Object>() {{
+ put("property", "original");
+ }});
+
+ try {
+ OSGi<?> program =
+ serviceReferences(
+ Service.class, __ -> false
+ ).effects(
+ __ -> {},
+ __ -> {},
+ __ -> updateEffects.add("first")
+ ).effects(
+ __ -> {},
+ __ -> {},
+ __ -> updateEffects.add("second")
+ );
+
+ program.run(bundleContext);
+
+ assertEquals(Collections.emptyList(), updateEffects);
+
+ serviceRegistration.setProperties(
+ new Hashtable<String, Object>() {{
+ put("property", "updated");
+ }});
+
+ assertEquals(Arrays.asList("first", "second"), updateEffects);
+ }
+ finally {
+ serviceRegistration.unregister();
+ }
+ }
+
+ @Test
+ public void testUpdateEffectsAreOnlyExecutedWhenNoRefresh() {
+ ArrayList<String> updateEffects = new ArrayList<>();
+
+ ServiceRegistration<Service> serviceRegistration =
+ bundleContext.registerService(
+ Service.class, new Service(),
+ new Hashtable<String, Object>() {{
+ put("property", "original");
+ }});
+
+ try {
+ OSGi<?> program =
+ refreshWhen(
+ serviceReferences(
+ Service.class, __ -> false
+ ).effects(
+ __ -> {},
+ __ -> {},
+ __ -> updateEffects.add("first")
+ ).effects(
+ __ -> {},
+ __ -> {},
+ __ -> updateEffects.add("second")
+ ),
+ __ -> true
+ );
+
+ program.run(bundleContext);
+
+ assertEquals(Collections.emptyList(), updateEffects);
+
+ serviceRegistration.setProperties(
+ new Hashtable<String, Object>() {{
+ put("property", "updated");
+ }});
+
+ assertEquals(Collections.emptyList(), updateEffects);
+ }
+ finally {
+ serviceRegistration.unregister();
+ }
+ }
+
static BundleContext bundleContext = FrameworkUtil.getBundle(
DSLTest.class).getBundleContext();