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 d7b7d6b42c05c8f1dc9cd8106a45d5a12b0cee6c
Author: Amichai Rothman <[email protected]>
AuthorDate: Thu Mar 26 17:24:58 2026 +0200

    ARIES-2214 Fix provider config type handling
---
 .../apache/aries/rsa/provider/tcp/TcpEndpoint.java |  1 -
 .../rsa/core/DistributionProviderTracker.java      |  4 ++
 .../aries/rsa/core/RemoteServiceAdminCore.java     | 75 +++++++++-------------
 .../aries/rsa/core/RemoteServiceAdminCoreTest.java |  4 +-
 .../apache/aries/rsa/spi/DistributionProvider.java | 19 ++++--
 5 files changed, 50 insertions(+), 53 deletions(-)

diff --git 
a/provider/tcp/src/main/java/org/apache/aries/rsa/provider/tcp/TcpEndpoint.java 
b/provider/tcp/src/main/java/org/apache/aries/rsa/provider/tcp/TcpEndpoint.java
index e2edf05a..99ad5a17 100644
--- 
a/provider/tcp/src/main/java/org/apache/aries/rsa/provider/tcp/TcpEndpoint.java
+++ 
b/provider/tcp/src/main/java/org/apache/aries/rsa/provider/tcp/TcpEndpoint.java
@@ -61,7 +61,6 @@ public class TcpEndpoint implements Endpoint {
         Config config = new Config(effectiveProperties);
         String endpointId = String.format("tcp://%s:%s/%s", hostname, port, 
config.getId());
         effectiveProperties.put(RemoteConstants.ENDPOINT_ID, endpointId);
-        effectiveProperties.put(RemoteConstants.SERVICE_EXPORTED_CONFIGS, "");
         effectiveProperties.put(RemoteConstants.SERVICE_INTENTS, 
Arrays.asList("osgi.basic", "osgi.async"));
         // tck tests require at least one config-type specific property... so 
we provide this one
         // (it also tests that we throw IllegalArgumentException when any 
config-type property value is garbage)
diff --git 
a/rsa/src/main/java/org/apache/aries/rsa/core/DistributionProviderTracker.java 
b/rsa/src/main/java/org/apache/aries/rsa/core/DistributionProviderTracker.java
index 72714774..0ff478d6 100644
--- 
a/rsa/src/main/java/org/apache/aries/rsa/core/DistributionProviderTracker.java
+++ 
b/rsa/src/main/java/org/apache/aries/rsa/core/DistributionProviderTracker.java
@@ -63,6 +63,10 @@ public class DistributionProviderTracker extends 
ServiceTracker<DistributionProv
             // Can happen if the service is created by a service factory and 
an exception occurs
             return null;
         }
+        if (provider.getSupportedTypes() == null || 
provider.getSupportedTypes().length == 0) {
+            LOG.warn("Invalid DistributionProvider {}: no supported config 
types", provider);
+            return null;
+        }
         LOG.debug("Initializing RemoteServiceAdmin for DistributionProvider {} 
({})",
             provider, Arrays.asList(provider.getSupportedTypes()));
         BundleContext apiContext = getAPIContext();
diff --git 
a/rsa/src/main/java/org/apache/aries/rsa/core/RemoteServiceAdminCore.java 
b/rsa/src/main/java/org/apache/aries/rsa/core/RemoteServiceAdminCore.java
index 77b7188d..be719ae2 100644
--- a/rsa/src/main/java/org/apache/aries/rsa/core/RemoteServiceAdminCore.java
+++ b/rsa/src/main/java/org/apache/aries/rsa/core/RemoteServiceAdminCore.java
@@ -105,27 +105,35 @@ public class RemoteServiceAdminCore implements 
RemoteServiceAdmin {
 
     @Override
     @SuppressWarnings("unchecked")
-    public List<ExportRegistration> exportService(ServiceReference 
serviceReference, Map additionalProperties)
+    public List<ExportRegistration> exportService(ServiceReference sref, Map 
additionalProperties)
         throws IllegalArgumentException, UnsupportedOperationException {
-        Map<String, Object> serviceProperties = 
getProperties(serviceReference);
+        Map<String, Object> serviceProperties = getProperties(sref);
         if (additionalProperties != null) {
             overlayProperties(serviceProperties, additionalProperties);
         }
 
         List<String> interfaceNames = getInterfaceNames(serviceProperties);
+        List<String> exportedConfigs = StringPlus.normalize(
+            serviceProperties.get(RemoteConstants.SERVICE_EXPORTED_CONFIGS));
+        List<String> configTypes = matchConfigTypes(exportedConfigs, true); // 
empty means pick one
 
-        if (isImportedService(serviceReference) || 
!isExportConfigSupported(serviceProperties)) {
+        if (isImportedService(sref) || configTypes.isEmpty()) {
             return Collections.emptyList();
         }
 
         Map<String, Object> key = makeKey(serviceProperties);
         List<ExportRegistration> regs = getExistingOrLock(key, interfaceNames);
         if (regs == null) {
-            regs = new ArrayList<>();
             try {
-                ExportRegistration reg = exportService(interfaceNames, 
serviceReference, serviceProperties);
-                if (reg != null) {
-                    regs.add(reg);
+                regs = new ArrayList<>();
+                for (String configType : configTypes) {
+                    ExportRegistration reg = 
exportService(Arrays.asList(configType),
+                        interfaceNames, sref, serviceProperties);
+                    if (reg != null) {
+                        regs.add(reg);
+                    }
+                }
+                if (!regs.isEmpty()) {
                     store(key, regs);
                 }
             } finally {
@@ -135,27 +143,6 @@ public class RemoteServiceAdminCore implements 
RemoteServiceAdmin {
         return regs;
     }
 
-    private boolean isExportConfigSupported(Map<String, Object> 
serviceProperties) {
-        if (provider == null) {
-            return false;
-        }
-        List<String> exportedConfigs = 
StringPlus.normalize(serviceProperties.get(RemoteConstants.SERVICE_EXPORTED_CONFIGS));
-        if (exportedConfigs == null || exportedConfigs.isEmpty()) {
-            return true;
-        }
-        String[] supportedTypes = provider.getSupportedTypes();
-        if (supportedTypes == null || supportedTypes.length == 0) {
-            //if not set, all services should be accepted
-            return true;
-        }
-        for (String supportedType : supportedTypes) {
-            if (exportedConfigs.contains(supportedType)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     private void store(Map<String, Object> key, List<ExportRegistration> regs) 
{
         // enlist initial export registrations in global list of 
exportRegistrations
         synchronized (exportedServices) {
@@ -208,6 +195,7 @@ public class RemoteServiceAdminCore implements 
RemoteServiceAdmin {
     }
 
     private ExportRegistration exportService(
+            final List<String> configTypes,
             final List<String> interfaceNames,
             final ServiceReference<?> serviceReference,
             final Map<String, Object> serviceProperties) {
@@ -221,7 +209,7 @@ public class RemoteServiceAdminCore implements 
RemoteServiceAdmin {
                 throw new IllegalStateException("service object is null 
(service was unregistered?)");
             }
             final Class<?>[] interfaces = getInterfaces(serviceO, 
interfaceNames);
-            final Map<String, Object> eprops = 
createEndpointProps(serviceProperties, interfaces);
+            final Map<String, Object> eprops = 
createEndpointProps(serviceProperties, configTypes, interfaces);
 
             Endpoint endpoint = AccessController.doPrivileged(
                 (PrivilegedAction<Endpoint>) () -> 
provider.exportService(serviceO, serviceContext, eprops, interfaces));
@@ -404,8 +392,9 @@ public class RemoteServiceAdminCore implements 
RemoteServiceAdmin {
                 return ir;
             }
 
-            if (determineConfigTypesForImport(endpoint).isEmpty()) {
-                LOG.info("No matching handler can be found for remote endpoint 
{}.", endpoint.getId());
+            if (matchConfigTypes(endpoint.getConfigurationTypes(), 
false).isEmpty()) {
+                LOG.info("Ignoring endpoint {} as it has no compatible 
configuration types: {}",
+                    endpoint.getId(), endpoint.getConfigurationTypes());
                 return null;
             }
 
@@ -431,21 +420,14 @@ public class RemoteServiceAdminCore implements 
RemoteServiceAdmin {
         }
     }
 
-    private List<String> determineConfigTypesForImport(EndpointDescription 
endpoint) {
-        List<String> remoteConfigurationTypes = 
endpoint.getConfigurationTypes();
-
-        List<String> usableConfigurationTypes = new ArrayList<>();
-        for (String ct : provider.getSupportedTypes()) {
-            if (remoteConfigurationTypes.contains(ct)) {
-                usableConfigurationTypes.add(ct);
-            }
-        }
-
-        if (usableConfigurationTypes.isEmpty()) {
-            LOG.info("Ignoring endpoint {} as it has no compatible 
configuration types: {}.",
-                endpoint.getId(), remoteConfigurationTypes);
+    private List<String> matchConfigTypes(List<String> types, boolean first) {
+        List<String> matched = new ArrayList<>();
+        Collections.addAll(matched, provider.getSupportedTypes());
+        if (types == null || types.isEmpty()) {
+            return matched.subList(0, first ? 1 : 0);
         }
-        return usableConfigurationTypes;
+        matched.retainAll(types);
+        return matched;
     }
 
     protected ImportRegistrationImpl exposeServiceFactory(String[] 
interfaceNames,
@@ -567,10 +549,11 @@ public class RemoteServiceAdminCore implements 
RemoteServiceAdmin {
     }
 
     protected Map<String, Object> createEndpointProps(Map<String, Object> 
effectiveProps,
-                                                      Class<?>[] ifaces) {
+            List<String> configTypes, Class<?>[] ifaces) {
         Map<String, Object> props = new HashMap<>();
         copyEndpointProperties(effectiveProps, props);
         props.remove(org.osgi.framework.Constants.SERVICE_ID);
+        props.put(RemoteConstants.SERVICE_EXPORTED_CONFIGS, configTypes);
         EndpointHelper.addObjectClass(props, ifaces);
         props.put(RemoteConstants.ENDPOINT_SERVICE_ID, 
effectiveProps.get(org.osgi.framework.Constants.SERVICE_ID));
         String frameworkUUID = 
bctx.getProperty(org.osgi.framework.Constants.FRAMEWORK_UUID);
diff --git 
a/rsa/src/test/java/org/apache/aries/rsa/core/RemoteServiceAdminCoreTest.java 
b/rsa/src/test/java/org/apache/aries/rsa/core/RemoteServiceAdminCoreTest.java
index bbccfb27..4b97c3f9 100644
--- 
a/rsa/src/test/java/org/apache/aries/rsa/core/RemoteServiceAdminCoreTest.java
+++ 
b/rsa/src/test/java/org/apache/aries/rsa/core/RemoteServiceAdminCoreTest.java
@@ -329,13 +329,15 @@ public class RemoteServiceAdminCoreTest {
         c.replay();
         Map<String, Object> sd = new HashMap<>();
         sd.put(org.osgi.framework.Constants.SERVICE_ID, 42);
-        Map<String, Object> props = rsaCore.createEndpointProps(sd, new 
Class[]{String.class});
+        Map<String, Object> props = rsaCore.createEndpointProps(
+            sd, Arrays.asList("myconfig"), new Class[]{String.class});
 
         
Assert.assertFalse(props.containsKey(org.osgi.framework.Constants.SERVICE_ID));
         assertEquals(42, props.get(RemoteConstants.ENDPOINT_SERVICE_ID));
         assertEquals("some_uuid1", 
props.get(RemoteConstants.ENDPOINT_FRAMEWORK_UUID));
         assertEquals(Arrays.asList("java.lang.String"),
             Arrays.asList((Object[]) 
props.get(org.osgi.framework.Constants.OBJECTCLASS)));
+        assertEquals(Arrays.asList("myconfig"), 
props.get(RemoteConstants.SERVICE_EXPORTED_CONFIGS));
         assertEquals("1.2.3", props.get("endpoint.package.version.java.lang"));
         c.verify();
     }
diff --git 
a/spi/src/main/java/org/apache/aries/rsa/spi/DistributionProvider.java 
b/spi/src/main/java/org/apache/aries/rsa/spi/DistributionProvider.java
index 772add85..590f945a 100644
--- a/spi/src/main/java/org/apache/aries/rsa/spi/DistributionProvider.java
+++ b/spi/src/main/java/org/apache/aries/rsa/spi/DistributionProvider.java
@@ -26,6 +26,11 @@ import 
org.osgi.service.remoteserviceadmin.EndpointDescription;
 @SuppressWarnings("rawtypes")
 public interface DistributionProvider {
 
+    /**
+     * Returns config types supported by this provider.
+     *
+     * @return the config types supported by this provider
+     */
     String[] getSupportedTypes();
 
     /**
@@ -34,11 +39,15 @@ public interface DistributionProvider {
      * The Distribution provider will be called if it supports the
      * specified config type, or if no config type was specified.
      * <p>
-     * All config-type specific configuration properties in the returned 
endpoint
-     * must have names of the form {@code <config>.*}, i.e. the property name
-     * must be prefixed with the config type string itself.
-     * If any of the config-type specific properties are invalid,
-     * an IllegalArgumentException must be thrown.
+     * All config-type specific configuration properties in the returned
+     * endpoint must have names of the form {@code <config>.*}, i.e. the
+     * property name must be prefixed with the config type string itself.
+     * If any of the config-type specific properties are invalid, an
+     * IllegalArgumentException must be thrown.
+     * <p>
+     * The provider must set the {@code "service.imported.configs"}
+     * endpoint property to the config type that was actually exported
+     * (and its alias names, if any).
      *
      * @param serviceObject service instance to be exported
      * @param serviceContext bundle context of the bundle exporting the service

Reply via email to