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
