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 7a992709ff845c84a12e01641e0cac509fd71ac1 Author: Amichai Rothman <[email protected]> AuthorDate: Tue Mar 31 01:45:03 2026 +0300 Optimize LocalDiscovery by creating Filters only once --- .../aries/rsa/discovery/local/LocalDiscovery.java | 73 ++++++++++++---------- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/discovery/local/src/main/java/org/apache/aries/rsa/discovery/local/LocalDiscovery.java b/discovery/local/src/main/java/org/apache/aries/rsa/discovery/local/LocalDiscovery.java index 4aa57d2e..5b0bdd4f 100644 --- a/discovery/local/src/main/java/org/apache/aries/rsa/discovery/local/LocalDiscovery.java +++ b/discovery/local/src/main/java/org/apache/aries/rsa/discovery/local/LocalDiscovery.java @@ -34,6 +34,7 @@ import org.osgi.framework.BundleEvent; import org.osgi.framework.BundleListener; import org.osgi.framework.Filter; import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; @@ -44,12 +45,16 @@ import org.osgi.service.component.annotations.ReferencePolicy; import org.osgi.service.remoteserviceadmin.EndpointDescription; import org.osgi.service.remoteserviceadmin.EndpointEvent; import org.osgi.service.remoteserviceadmin.EndpointEventListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @Component(immediate = true) public class LocalDiscovery implements BundleListener { + private static final Logger LOG = LoggerFactory.getLogger(LocalDiscovery.class); + final Map<Bundle, Collection<EndpointDescription>> endpoints = new ConcurrentHashMap<>(); - final Map<EndpointEventListener, Collection<String>> listenerToFilters = new HashMap<>(); + final Map<EndpointEventListener, Collection<Filter>> listenerToFilters = new HashMap<>(); EndpointDescriptionBundleParser parser; @@ -57,6 +62,20 @@ public class LocalDiscovery implements BundleListener { this.parser = new EndpointDescriptionBundleParser(); } + private static List<Filter> createFilters(ServiceReference<EndpointEventListener> ref) { + List<String> values = StringPlus.normalize(ref.getProperty(EndpointEventListener.ENDPOINT_LISTENER_SCOPE)); + List<Filter> filters = new ArrayList<>(values.size()); + for (String value : values) { + try { + filters.add(FrameworkUtil.createFilter(value)); + } catch (InvalidSyntaxException ise) { + // invalid filter syntax means it can't match anything anyway, so we just ignore it + LOG.trace("ignoring invalid filter '{}'", value); + } + } + return filters; + } + @Activate public void activate(BundleContext context) { context.addBundleListener(this); @@ -78,7 +97,7 @@ public class LocalDiscovery implements BundleListener { @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC) void bindListener(ServiceReference<EndpointEventListener> sref, EndpointEventListener listener) { - List<String> filters = StringPlus.normalize(sref.getProperty(EndpointEventListener.ENDPOINT_LISTENER_SCOPE)); + List<Filter> filters = createFilters(sref); if (filters.isEmpty()) { return; } @@ -116,13 +135,14 @@ public class LocalDiscovery implements BundleListener { } } - private Map<String, Collection<EndpointEventListener>> getMatchingListeners(EndpointDescription endpoint) { + private Map<Filter, Collection<EndpointEventListener>> getMatchingListeners(EndpointDescription endpoint) { // return a copy of matched filters/listeners so that caller doesn't need to hold locks while triggering events - Map<String, Collection<EndpointEventListener>> matched = new HashMap<>(); + Hashtable<String, Object> props = new Hashtable<>(endpoint.getProperties()); + Map<Filter, Collection<EndpointEventListener>> matched = new HashMap<>(); synchronized (listenerToFilters) { - for (Entry<EndpointEventListener, Collection<String>> entry : listenerToFilters.entrySet()) { - for (String filter : entry.getValue()) { - if (matchFilter(filter, endpoint)) { + for (Entry<EndpointEventListener, Collection<Filter>> entry : listenerToFilters.entrySet()) { + for (Filter filter : entry.getValue()) { + if (filter.match(props)) { // don't use matches() which is case-sensitive matched.computeIfAbsent(filter, f -> new ArrayList<>()).add(entry.getKey()); } } @@ -161,37 +181,24 @@ public class LocalDiscovery implements BundleListener { } private void publishToAllListeners(EndpointEvent event) { - Map<String, Collection<EndpointEventListener>> matched = getMatchingListeners(event.getEndpoint()); - for (Map.Entry<String, Collection<EndpointEventListener>> entry : matched.entrySet()) { + Map<Filter, Collection<EndpointEventListener>> matched = getMatchingListeners(event.getEndpoint()); + for (Map.Entry<Filter, Collection<EndpointEventListener>> entry : matched.entrySet()) { for (EndpointEventListener listener : entry.getValue()) { - publishIfMatched(listener, entry.getKey(), event); + listener.endpointChanged(event, entry.getKey().toString()); } } } - private void publishAllToListener(Collection<String> filters, EndpointEventListener listener) { + private void publishAllToListener(Collection<Filter> filters, EndpointEventListener listener) { endpoints.values().stream().flatMap(Collection::stream) - .forEach(endpoint -> filters.forEach(filter -> - publishIfMatched(listener, filter, new EndpointEvent(EndpointEvent.ADDED, endpoint)))); - } - - private void publishIfMatched(EndpointEventListener listener, String filter, EndpointEvent event) { - if (LocalDiscovery.matchFilter(filter, event.getEndpoint())) { - listener.endpointChanged(event, filter); - } - } - - private static boolean matchFilter(String filter, EndpointDescription endpoint) { - if (filter == null) { - return false; - } - - try { - Filter f = FrameworkUtil.createFilter(filter); - return f.match(new Hashtable<>(endpoint.getProperties())); - } catch (Exception e) { - return false; - } + .forEach(endpoint -> { + EndpointEvent event = new EndpointEvent(EndpointEvent.ADDED, endpoint); + Hashtable<String, Object> props = new Hashtable<>(event.getEndpoint().getProperties()); + filters.forEach(filter -> { + if (filter.match(props)) { + listener.endpointChanged(event, filter.toString()); + } + }); + }); } - }
