You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by am...@apache.org on 2026/05/17 08:47:30 UTC

(aries-rsa) branch master updated (81e772a0 -> aedb3c9d)

This is an automated email from the ASF dual-hosted git repository.

amichair pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/aries-rsa.git


    from 81e772a0 Bump asm.version from 9.9.1 to 9.10 (#112)
     new a6f7c940 Inline TopologyManagerExport methods
     new 4ea12909 ARIES-2218 Fix RSA/provider endpoint properties lost during service properties update
     new 50fa0de2 ARIES-2219 Fix imported services not reflecting updated service properties
     new 42a6a910 Ensure executor shutdown in TopologyManagerImport.stop()
     new aedb3c9d Fix EndpointListenerManager not unregistering hooks when stopped

The 5 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../aries/rsa/core/ExportRegistrationImpl.java     | 68 ++++++++++++++++++----
 .../exporter/TopologyManagerExport.java            | 24 ++------
 .../importer/TopologyManagerImport.java            | 50 +++++++++++++---
 .../importer/local/EndpointListenerManager.java    | 12 +++-
 .../importer/TopologyManagerImportTest.java        | 41 +++++++++++--
 5 files changed, 151 insertions(+), 44 deletions(-)


(aries-rsa) 01/05: Inline TopologyManagerExport methods

Posted by am...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

amichair pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/aries-rsa.git

commit a6f7c9408787f802b9f83703970cd1450e1636e7
Author: Amichai Rothman <am...@apache.org>
AuthorDate: Thu Mar 26 17:44:26 2026 +0200

    Inline TopologyManagerExport methods
---
 .../exporter/TopologyManagerExport.java            | 24 ++++++----------------
 1 file changed, 6 insertions(+), 18 deletions(-)

diff --git a/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/exporter/TopologyManagerExport.java b/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/exporter/TopologyManagerExport.java
index 7db6647a..4baf626e 100644
--- a/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/exporter/TopologyManagerExport.java
+++ b/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/exporter/TopologyManagerExport.java
@@ -87,40 +87,28 @@ public class TopologyManagerExport implements ServiceListener {
     public void serviceChanged(ServiceEvent event) {
         ServiceReference<?> sref = event.getServiceReference();
         if (!shouldExport(sref)) {
-            LOG.trace("Skipping service {}", sref);
+            LOG.trace("ignoring service {}", sref);
             return;
         }
         LOG.info("Received ServiceEvent type: {}, sref: {}", getTypeName(event), sref);
         switch (event.getType()) {
         case ServiceEvent.REGISTERED:
-            add(sref);
+            exportable.add(sref);
+            export(sref);
             break;
 
         case ServiceEvent.MODIFIED:
-            modified(sref);
+            endpointRepo.values().forEach(repo -> repo.modifyService(sref));
             break;
 
         case ServiceEvent.UNREGISTERING:
         case ServiceEvent.MODIFIED_ENDMATCH:
-            remove(sref);
+            exportable.remove(sref);
+            endpointRepo.values().forEach(repo -> repo.removeService(sref));
             break;
         }
     }
 
-    private void add(ServiceReference<?> sref) {
-        exportable.add(sref);
-        export(sref);
-    }
-
-    private void modified(ServiceReference<?> sref) {
-        endpointRepo.values().forEach(repo -> repo.modifyService(sref));
-    }
-
-    private void remove(ServiceReference<?> sref) {
-        exportable.remove(sref);
-        endpointRepo.values().forEach(repo -> repo.removeService(sref));
-    }
-
     public void add(RemoteServiceAdmin rsa) {
         endpointRepo.put(rsa, new ServiceExportsRepository(rsa, notifier));
         exportable.forEach(sref -> executor.execute(() -> export(sref)));


(aries-rsa) 04/05: Ensure executor shutdown in TopologyManagerImport.stop()

Posted by am...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

amichair pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/aries-rsa.git

commit 42a6a910abbabac67ca3a31e451fa3a1f2f163f4
Author: Amichai Rothman <am...@apache.org>
AuthorDate: Mon Mar 30 00:16:00 2026 +0300

    Ensure executor shutdown in TopologyManagerImport.stop()
---
 .../apache/aries/rsa/topologymanager/importer/TopologyManagerImport.java | 1 +
 1 file changed, 1 insertion(+)

diff --git a/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/TopologyManagerImport.java b/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/TopologyManagerImport.java
index 873f6415..07cd0e8e 100644
--- a/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/TopologyManagerImport.java
+++ b/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/TopologyManagerImport.java
@@ -91,6 +91,7 @@ public class TopologyManagerImport implements EndpointEventListener, RemoteServi
             LOG.info("Interrupted while waiting for {} to terminate", execService);
             Thread.currentThread().interrupt();
         }
+        execService.shutdownNow();
         // close all imports
         importPossibilities.clear();
         importedServices.allValues().forEach(this::unimportRegistration);


(aries-rsa) 02/05: ARIES-2218 Fix RSA/provider endpoint properties lost during service properties update

Posted by am...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

amichair pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/aries-rsa.git

commit 4ea12909c22321eba95cc14d6acec3882f072c58
Author: Amichai Rothman <am...@apache.org>
AuthorDate: Fri Mar 27 00:06:38 2026 +0200

    ARIES-2218 Fix RSA/provider endpoint properties lost during service properties update
---
 .../aries/rsa/core/ExportRegistrationImpl.java     | 68 ++++++++++++++++++----
 1 file changed, 58 insertions(+), 10 deletions(-)

diff --git a/rsa/src/main/java/org/apache/aries/rsa/core/ExportRegistrationImpl.java b/rsa/src/main/java/org/apache/aries/rsa/core/ExportRegistrationImpl.java
index 3f8a43d8..e7240aaf 100644
--- a/rsa/src/main/java/org/apache/aries/rsa/core/ExportRegistrationImpl.java
+++ b/rsa/src/main/java/org/apache/aries/rsa/core/ExportRegistrationImpl.java
@@ -22,19 +22,22 @@ import java.io.Closeable;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
 
 import org.apache.aries.rsa.core.event.EventProducer;
 import org.apache.aries.rsa.spi.Endpoint;
+import org.apache.aries.rsa.util.StringPlus;
+import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.remoteserviceadmin.EndpointDescription;
 import org.osgi.service.remoteserviceadmin.ExportReference;
 import org.osgi.service.remoteserviceadmin.ExportRegistration;
-import org.osgi.service.remoteserviceadmin.RemoteConstants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -233,19 +236,64 @@ public class ExportRegistrationImpl implements ExportRegistration, ExportReferen
         return s;
     }
 
+    /**
+     * Creates an updated set of endpoint properties by merging some
+     * of the old endpoint properties with updated service properties.
+     * <p>
+     * Endpoint properties include a mix of the regular service properties
+     * (unrelated to RSA), RSA-related properties that are included
+     * in the service properties (such as which provider/config to use
+     * for export), and RSA and distribution provider specific properties
+     * that are not included in the service properties but are added
+     * to the endpoint (or removed) during the export process (such as a
+     * url used by the provider to remotely connect to the endpoint).
+     * <p>
+     * When the original service properties are updated, we get notified
+     * with a copy of the new service properties, but without any
+     * RSA/provider changes or additions (since they did not go through
+     * a new export process). Original service properties may have been
+     * added, removed, or have modified values in the new service properties.
+     * <p>
+     * When we update an endpoint, we thus need to update the original service
+     * properties, but we must preserve the original RSA/provider properties
+     * in order for the updated endpoint to continue being usable by RSA.
+     * <p>
+     * There is no clear definition of how to determine which endpoint properties
+     * are service properties to be updated/added/removed and which are
+     * RSA/provider properties to be preserved, but a heuristic based on the
+     * property name prefix seems to be a reasonable solution.
+     *
+     * @param oldEndpointProps the properties from the existing (pre-update) endpoint
+     * @param newServiceProps the new service properties (without RSA/distribution additions)
+     * @return the merged set of old RSA/distribution properties with new custom properties
+     */
+    private Map<String, Object> merge(Map<String, Object> oldEndpointProps, Map<String, ?> newServiceProps) {
+        List<String> configTypes = StringPlus.normalize(oldEndpointProps.get(Constants.SERVICE_IMPORTED_CONFIGS));
+        // from old props, add only properties we think are RSA/distribution/framework related
+        Map<String, Object> props = oldEndpointProps.entrySet().stream()
+            .filter(e -> {
+                String k = e.getKey().toLowerCase(Locale.ROOT); // case-insensitive
+                return k.startsWith("endpoint.") || k.startsWith("service.") || k.startsWith("osgi.basic.")
+                    || k.equals("objectclass") || configTypes.stream().anyMatch(k::startsWith);
+            }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+        // from new service properties, add all public properties
+        // (plus override any rsa/distribution properties that may be present)
+        newServiceProps.entrySet().stream()
+            .filter(e -> !e.getKey().startsWith("."))
+            .forEach(e -> props.put(e.getKey(), e.getValue()));
+        return props;
+    }
+
     @Override
     public EndpointDescription update(Map<String, ?> properties) {
         if (isInvalid()) {
             throw new IllegalStateException("export registration is invalid or closed");
         }
-
-        Map<String, Object> oldProps = shared.endpoint.getProperties();
-        Map<String, Object> props = new HashMap<>(properties);
-        props.putIfAbsent(RemoteConstants.ENDPOINT_ID, oldProps.get(RemoteConstants.ENDPOINT_ID));
-        props.putIfAbsent(RemoteConstants.SERVICE_IMPORTED_CONFIGS, oldProps.get(RemoteConstants.SERVICE_IMPORTED_CONFIGS));
-
-        shared.endpoint = new EndpointDescription(shared.serviceReference, props);
+        EndpointDescription endpoint = shared.endpoint;
+        Map<String, Object> props = merge(endpoint.getProperties(), properties);
+        endpoint = new EndpointDescription(props);
+        shared.endpoint = endpoint;
         shared.eventProducer.notifyUpdate(this);
-        return shared.endpoint;
+        return endpoint;
     }
 }


(aries-rsa) 05/05: Fix EndpointListenerManager not unregistering hooks when stopped

Posted by am...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

amichair pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/aries-rsa.git

commit aedb3c9dbf535982cb018af04aed22b32e806284
Author: Amichai Rothman <am...@apache.org>
AuthorDate: Mon Mar 30 12:38:58 2026 +0300

    Fix EndpointListenerManager not unregistering hooks when stopped
---
 .../importer/local/EndpointListenerManager.java              | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/local/EndpointListenerManager.java b/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/local/EndpointListenerManager.java
index 03cfcfdf..751e317f 100644
--- a/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/local/EndpointListenerManager.java
+++ b/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/local/EndpointListenerManager.java
@@ -46,6 +46,8 @@ public class EndpointListenerManager implements ServiceInterestListener {
 
     private final BundleContext bctx;
     private volatile ServiceRegistration<?> serviceRegistration;
+    private volatile ServiceRegistration<?> listenerHookeRegistration;
+    private volatile ServiceRegistration<?> findHookRegistration;
 
     private final List<String> filters = new ArrayList<>();
     private final EndpointEventListener endpointListener;
@@ -67,14 +69,20 @@ public class EndpointListenerManager implements ServiceInterestListener {
     public void start() {
         String[] ifAr = { EndpointEventListener.class.getName() };
         serviceRegistration = bctx.registerService(ifAr, endpointListener, getEELProperties());
-        bctx.registerService(ListenerHook.class, listenerHook, null);
-        bctx.registerService(FindHook.class, findHook, null);
+        listenerHookeRegistration = bctx.registerService(ListenerHook.class, listenerHook, null);
+        findHookRegistration = bctx.registerService(FindHook.class, findHook, null);
     }
 
     public void stop() {
         if (serviceRegistration != null) {
             serviceRegistration.unregister();
         }
+        if (listenerHookeRegistration != null) {
+            listenerHookeRegistration.unregister();
+        }
+        if (findHookRegistration != null) {
+            findHookRegistration.unregister();
+        }
     }
 
     protected void extendScope(String filter) {


(aries-rsa) 03/05: ARIES-2219 Fix imported services not reflecting updated service properties

Posted by am...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

amichair pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/aries-rsa.git

commit 50fa0de23d47acc29d0e23bab3729f22be2919e4
Author: Amichai Rothman <am...@apache.org>
AuthorDate: Sun Mar 29 19:55:32 2026 +0300

    ARIES-2219 Fix imported services not reflecting updated service properties
---
 .../importer/TopologyManagerImport.java            | 49 ++++++++++++++++++----
 .../importer/TopologyManagerImportTest.java        | 41 +++++++++++++++---
 2 files changed, 76 insertions(+), 14 deletions(-)

diff --git a/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/TopologyManagerImport.java b/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/TopologyManagerImport.java
index b57d494b..873f6415 100644
--- a/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/TopologyManagerImport.java
+++ b/topology-manager/src/main/java/org/apache/aries/rsa/topologymanager/importer/TopologyManagerImport.java
@@ -19,12 +19,16 @@
 package org.apache.aries.rsa.topologymanager.importer;
 
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceRegistration;
@@ -132,27 +136,42 @@ public class TopologyManagerImport implements EndpointEventListener, RemoteServi
         try {
             // we have a set of all current imports, and a set of all possible imports (with overlap)
             Set<ImportRegistration> imported = importedServices.get(filter);
-            Set<EndpointDescription> possible = importPossibilities.get(filter);
-            // first we iterate over all current imports, and split them into two groups:
+            Set<EndpointDescription> possibleSet = importPossibilities.get(filter);
+            Map<EndpointDescription, EndpointDescription> possible = possibleSet.stream()
+                .collect(Collectors.toMap(e -> e, e -> e)); // convert to map for getting the value
+            // first we iterate over all current imports, and split them into three groups:
             // - still valid (no null references) and possible (in possible set)
+            // - still valid and possible but with changed properties
             // - invalid (contain null references) or no longer possible (not in possible set)
             // note that this part should be concurrency-safe (get every reference only once and don't modify anything)
             Set<EndpointDescription> valid = new HashSet<>(); // imports that are still valid and possible
             Set<ImportRegistration> invalid = new LinkedHashSet<>(); // imports that are no longer valid/possible
+            Map<ImportRegistration, EndpointDescription> updated = new LinkedHashMap<>(); // valid with changed props
             for (ImportRegistration reg : imported) {
                 ImportReference ref = reg.getImportReference();
                 EndpointDescription endpoint = ref == null ? null : ref.getImportedEndpoint();
                 // check if the currently imported endpoint is still valid and possible
-                if (endpoint != null && possible.contains(endpoint)) {
-                    valid.add(endpoint); // valid and possible
+                EndpointDescription pe = possible.get(endpoint); // get the new (maybe modified) possible endpoint
+                if (pe != null) {
+                    if (getChangedProps(endpoint.getProperties(), pe.getProperties()).isEmpty())
+                        valid.add(endpoint); // valid and possible
+                    else
+                        updated.put(reg, pe); // valid and possible and changed properties
                 } else {
                     invalid.add(reg); // invalid (reg or ref or endpoint is null) or no longer possible
                 }
             }
-            // now that we figured out what needs to be done, apply the changes
+            // now that we figured out what needs to be done, apply the changes to each group
             invalid.forEach(this::unimportRegistration); // remove invalid/non-possible imports
-            possible.forEach(endpoint -> { // import all possible endpoints that are not already imported
-                if (!valid.contains(endpoint)) {
+            updated.forEach((reg, e) -> { // update modified properties for existing imports
+                try {
+                    reg.update(e);
+                } catch (IllegalStateException ise) {
+                    LOG.warn("can't update closed endpoint {}", e, ise);
+                }
+            });
+            possible.keySet().forEach(endpoint -> { // import all possible endpoints that are not already imported
+                if (!valid.contains(endpoint) && !updated.containsValue(endpoint)) {
                     importService(filter, endpoint);
                 }
             });
@@ -188,7 +207,21 @@ public class TopologyManagerImport implements EndpointEventListener, RemoteServi
         importedServices.remove(reg);
         reg.close();
     }
-    
+
+    private static Set<String> getChangedProps(Map<String, Object> p1, Map<String, Object> p2) {
+        Set<String> changed = new LinkedHashSet<>();
+        for (Map.Entry<String, Object> entry : p1.entrySet()) {
+            Object v = p2.get(entry.getKey());
+            if (!Objects.deepEquals(entry.getValue(), v) || v == null && !p2.containsKey(entry.getKey()))
+                changed.add(entry.getKey());
+        }
+        for (String k : p2.keySet()) {
+            if (!p1.containsKey(k))
+                changed.add(k);
+        }
+        return changed;
+    }
+
     @Override
     public void endpointChanged(EndpointEvent event, String filter) {
         if (stopped) {
diff --git a/topology-manager/src/test/java/org/apache/aries/rsa/topologymanager/importer/TopologyManagerImportTest.java b/topology-manager/src/test/java/org/apache/aries/rsa/topologymanager/importer/TopologyManagerImportTest.java
index 857729a9..af29da5c 100644
--- a/topology-manager/src/test/java/org/apache/aries/rsa/topologymanager/importer/TopologyManagerImportTest.java
+++ b/topology-manager/src/test/java/org/apache/aries/rsa/topologymanager/importer/TopologyManagerImportTest.java
@@ -22,6 +22,7 @@ import static org.easymock.EasyMock.*;
 import static org.easymock.EasyMock.expect;
 import static org.junit.Assert.assertEquals;
 
+import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -31,11 +32,13 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.remoteserviceadmin.EndpointDescription;
 import org.osgi.service.remoteserviceadmin.EndpointEvent;
 import org.osgi.service.remoteserviceadmin.ImportReference;
 import org.osgi.service.remoteserviceadmin.ImportRegistration;
+import org.osgi.service.remoteserviceadmin.RemoteConstants;
 import org.osgi.service.remoteserviceadmin.RemoteServiceAdmin;
 import org.osgi.service.remoteserviceadmin.RemoteServiceAdminListener;
 
@@ -52,19 +55,26 @@ public class TopologyManagerImportTest {
         return bc;
     }
 
-    private ImportRegistration mockImportRegistration(IMocksControl c, EndpointDescription endpoint) {
+    private ImportRegistration mockImportRegistration(IMocksControl c, EndpointDescription endpoint, boolean expectUpdate) {
         final ImportRegistration ireg = c.createMock(ImportRegistration.class);
         expect(ireg.getException()).andReturn(null).anyTimes();
-        expect(ireg.update(anyObject())).andReturn(true).anyTimes();
+        if (expectUpdate) {
+            expect(ireg.update(anyObject())).andReturn(true);
+        }
         ImportReference iref = c.createMock(ImportReference.class);
         expect(ireg.getImportReference()).andReturn(iref).anyTimes();
         expect(iref.getImportedEndpoint()).andReturn(endpoint).anyTimes();
         return ireg;
     }
 
-    private EndpointDescription createEndpoint() {
-        EndpointDescription endpoint = c.createMock(EndpointDescription.class);
-        final ImportRegistration ir = mockImportRegistration(c, endpoint);
+    private EndpointDescription createEndpoint(boolean expectUpdate, String id) {
+        HashMap<String, Object> props = new HashMap<>();
+        props.put(RemoteConstants.ENDPOINT_ID, id);
+        props.put(Constants.OBJECTCLASS, new String[]{String.class.getName()});
+        props.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, "config1");
+        EndpointDescription endpoint = new EndpointDescription(props);
+
+        final ImportRegistration ir = mockImportRegistration(c, endpoint, expectUpdate);
         ir.close(); // must be closed
         expectLastCall().andAnswer(() -> {
             endpoints.get(endpoint).decrementAndGet();
@@ -78,6 +88,10 @@ public class TopologyManagerImportTest {
         return endpoint;
     }
 
+    private EndpointDescription createEndpoint() {
+        return createEndpoint(false, "id1");
+    }
+
     IMocksControl c;
     BundleContext bc;
     RemoteServiceAdmin rsa;
@@ -144,7 +158,7 @@ public class TopologyManagerImportTest {
         tm.endpointChanged(event, "myFilter");
         assertImports(endpoint, 1);
         tm.endpointChanged(event, "myFilter");
-        assertImports(endpoint, 1); // still one one import
+        assertImports(endpoint, 1); // still one import
     }
 
     @Test
@@ -158,4 +172,19 @@ public class TopologyManagerImportTest {
         tm.endpointChanged(new EndpointEvent(EndpointEvent.REMOVED, endpoint), "myFilter");
         assertImports(endpoint, 0);
     }
+
+    @Test
+    public void testModifyEndpoint() throws InterruptedException {
+        EndpointDescription endpoint = createEndpoint(true,  "id1");
+        start();
+
+        tm.add(rsa);
+        tm.endpointChanged(new EndpointEvent(EndpointEvent.ADDED, endpoint), "myFilter");
+        assertImports(endpoint, 1);
+        Map<String, Object> props = new HashMap<>(endpoint.getProperties());
+        props.put("newProp", "newValue");
+        endpoint = new EndpointDescription(props);
+        tm.endpointChanged(new EndpointEvent(EndpointEvent.MODIFIED, endpoint), "myFilter");
+        assertImports(endpoint, 1);
+    }
 }