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 <[email protected]>
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;
     }
 }

Reply via email to