raducotescu commented on a change in pull request #13: URL: https://github.com/apache/sling-org-apache-sling-scripting-core/pull/13#discussion_r802523466
########## File path: src/main/java/org/apache/sling/scripting/core/impl/ServiceCache.java ########## @@ -63,70 +70,151 @@ public void dispose() { * @return The service or <code>null</code> */ @SuppressWarnings("unchecked") + @Nullable public <ServiceType> ServiceType getService(Class<ServiceType> type) { - final String key = type.getName(); - Reference reference = this.cache.get(key); - if (reference == null) { - - // get the service - ServiceReference ref = this.bundleContext.getServiceReference(key); - if (ref != null) { - final Object service = this.bundleContext.getService(ref); - if (service != null) { - reference = new Reference(); - reference.service = service; - reference.reference = ref; - } else { - ref = null; - } - } - - // assume missing service - if (reference == null) { - reference = NULL_REFERENCE; + SortedSet<Reference> references = getCachedReferences(type); + for (Reference reference : references) { + ServiceType service = (ServiceType) reference.getService(); + if (service != null) { + return service; } + } + return null; + } - // check to see whether another thread has not done the same thing - synchronized (this) { - Reference existing = this.cache.get(key); - if (existing == null) { - this.cache.put(key, reference); - ref = null; - } else { - reference = existing; + @SuppressWarnings("unchecked") + @Nullable + public <ServiceType> ServiceType[] getServices(Class<ServiceType> type, String filter) { + List<ServiceType> result = new ArrayList<>(); + try { + SortedSet<Reference> cachedReferences = getCachedReferences(type); + final Collection<ServiceReference<ServiceType>> filteredReferences = this.bundleContext.getServiceReferences(type, filter); + if (!filteredReferences.isEmpty()) { + List<ServiceReference<ServiceType>> localFilteredReferences = new ArrayList<>(filteredReferences); + Collections.sort(localFilteredReferences); + // get the highest ranking first + Collections.reverse(localFilteredReferences); + for (ServiceReference<ServiceType> serviceReference : localFilteredReferences) { + Reference lookup = new Reference(serviceReference); + if (cachedReferences.contains(lookup)) { + for (Reference reference : cachedReferences) { + if (serviceReference.equals(reference.getServiceReference())) { + ServiceType service = (ServiceType) reference.getService(); + if (service != null) { + result.add(service); + } + break; + } + } + } else { + // concurrent change; restart + return getServices(type, filter); + } } } - - // unget the service if another thread was faster - if (ref != null) { - this.bundleContext.ungetService(ref); - } + } catch (InvalidSyntaxException e) { + LOGGER.error(String.format("Unable to retrieve the services of type %s.", type.getName()), e); } - - // return whatever we got (which may be null) - return (ServiceType) reference.service; + if (!result.isEmpty()) { + ServiceType[] srv = (ServiceType[]) Array.newInstance(type, result.size()); + return result.toArray(srv); + } + return null; } /** * @see org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent) */ public void serviceChanged(ServiceEvent event) { - final String[] objectClasses = (String[])event.getServiceReference().getProperty(Constants.OBJECTCLASS); - if ( objectClasses != null) { - for(final String key : objectClasses) { - Reference ref = null; - synchronized ( this ) { - ref = this.cache.remove(key); + ServiceReference<?> serviceReference = event.getServiceReference(); + final String[] objectClasses = (String[]) serviceReference.getProperty(Constants.OBJECTCLASS); + if (objectClasses != null) { + for (final String key : objectClasses) { + SortedSet<Reference> references; + synchronized (this) { + references = this.cache.remove(key); + if (references != null) { + for (Reference reference : references) { + bundleContext.ungetService(reference.getServiceReference()); + } + } } - if ( ref != null && ref != NULL_REFERENCE ) { - this.bundleContext.ungetService(ref.reference); + } + } + } + + private <ServiceType> SortedSet<Reference> getCachedReferences(Class<ServiceType> type) { + String key = type.getName(); + SortedSet<Reference> references = cache.get(key); + if (references == null) { + references = Collections.synchronizedSortedSet(new TreeSet<>((o1, o2) -> -1 * o1.compareTo(o2))); + try { + Collection<ServiceReference<ServiceType>> serviceReferences = this.bundleContext.getServiceReferences(type, null); + if (!serviceReferences.isEmpty()) { + List<ServiceReference<ServiceType>> localReferences = new ArrayList<>(serviceReferences); + Collections.sort(localReferences); + Collections.reverse(localReferences); + for (ServiceReference<ServiceType> ref : localReferences) { + references.add(new Reference(ref)); + } + synchronized (this) { + SortedSet<Reference> existing = this.cache.get(key); + if (existing != null) { + existing.addAll( + references.stream().filter(reference -> !existing.contains(reference)).collect(Collectors.toList())); Review comment: Got rid of this in [712b011](https://github.com/apache/sling-org-apache-sling-scripting-core/pull/13/commits/712b0115040cf239d59eeb8baad13a175ff17309). ########## File path: src/main/java/org/apache/sling/scripting/core/impl/ServiceCache.java ########## @@ -63,70 +70,151 @@ public void dispose() { * @return The service or <code>null</code> */ @SuppressWarnings("unchecked") + @Nullable public <ServiceType> ServiceType getService(Class<ServiceType> type) { - final String key = type.getName(); - Reference reference = this.cache.get(key); - if (reference == null) { - - // get the service - ServiceReference ref = this.bundleContext.getServiceReference(key); - if (ref != null) { - final Object service = this.bundleContext.getService(ref); - if (service != null) { - reference = new Reference(); - reference.service = service; - reference.reference = ref; - } else { - ref = null; - } - } - - // assume missing service - if (reference == null) { - reference = NULL_REFERENCE; + SortedSet<Reference> references = getCachedReferences(type); + for (Reference reference : references) { + ServiceType service = (ServiceType) reference.getService(); + if (service != null) { + return service; } + } + return null; + } - // check to see whether another thread has not done the same thing - synchronized (this) { - Reference existing = this.cache.get(key); - if (existing == null) { - this.cache.put(key, reference); - ref = null; - } else { - reference = existing; + @SuppressWarnings("unchecked") + @Nullable + public <ServiceType> ServiceType[] getServices(Class<ServiceType> type, String filter) { + List<ServiceType> result = new ArrayList<>(); + try { + SortedSet<Reference> cachedReferences = getCachedReferences(type); + final Collection<ServiceReference<ServiceType>> filteredReferences = this.bundleContext.getServiceReferences(type, filter); + if (!filteredReferences.isEmpty()) { + List<ServiceReference<ServiceType>> localFilteredReferences = new ArrayList<>(filteredReferences); + Collections.sort(localFilteredReferences); + // get the highest ranking first + Collections.reverse(localFilteredReferences); + for (ServiceReference<ServiceType> serviceReference : localFilteredReferences) { + Reference lookup = new Reference(serviceReference); + if (cachedReferences.contains(lookup)) { + for (Reference reference : cachedReferences) { + if (serviceReference.equals(reference.getServiceReference())) { + ServiceType service = (ServiceType) reference.getService(); + if (service != null) { + result.add(service); + } + break; + } + } + } else { + // concurrent change; restart + return getServices(type, filter); + } } } - - // unget the service if another thread was faster - if (ref != null) { - this.bundleContext.ungetService(ref); - } + } catch (InvalidSyntaxException e) { + LOGGER.error(String.format("Unable to retrieve the services of type %s.", type.getName()), e); } - - // return whatever we got (which may be null) - return (ServiceType) reference.service; + if (!result.isEmpty()) { + ServiceType[] srv = (ServiceType[]) Array.newInstance(type, result.size()); + return result.toArray(srv); + } + return null; } /** * @see org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent) */ public void serviceChanged(ServiceEvent event) { - final String[] objectClasses = (String[])event.getServiceReference().getProperty(Constants.OBJECTCLASS); - if ( objectClasses != null) { - for(final String key : objectClasses) { - Reference ref = null; - synchronized ( this ) { - ref = this.cache.remove(key); + ServiceReference<?> serviceReference = event.getServiceReference(); + final String[] objectClasses = (String[]) serviceReference.getProperty(Constants.OBJECTCLASS); + if (objectClasses != null) { + for (final String key : objectClasses) { + SortedSet<Reference> references; + synchronized (this) { + references = this.cache.remove(key); + if (references != null) { + for (Reference reference : references) { + bundleContext.ungetService(reference.getServiceReference()); + } + } } - if ( ref != null && ref != NULL_REFERENCE ) { - this.bundleContext.ungetService(ref.reference); + } + } + } + + private <ServiceType> SortedSet<Reference> getCachedReferences(Class<ServiceType> type) { + String key = type.getName(); + SortedSet<Reference> references = cache.get(key); + if (references == null) { + references = Collections.synchronizedSortedSet(new TreeSet<>((o1, o2) -> -1 * o1.compareTo(o2))); Review comment: Got rid of this in [712b011](https://github.com/apache/sling-org-apache-sling-scripting-core/pull/13/commits/712b0115040cf239d59eeb8baad13a175ff17309). -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: dev-unsubscr...@sling.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org