You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@sling.apache.org by GitBox <gi...@apache.org> on 2022/02/09 09:04:19 UTC

[GitHub] [sling-org-apache-sling-scripting-core] jsedding commented on a change in pull request #13: SLING-11119 - Optimise the service retrieval for bundled scripts

jsedding commented on a change in pull request #13:
URL: https://github.com/apache/sling-org-apache-sling-scripting-core/pull/13#discussion_r802416993



##########
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:
       For the comparator, you could use [`Comparator.reverseOrder()`](https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html#reverseOrder--) instead. IMHO it's more readable.




-- 
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-unsubscribe@sling.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org