You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by js...@apache.org on 2016/11/28 17:30:09 UTC

svn commit: r1771777 - in /sling/trunk/testing/junit/core/src/main/java/org/apache/sling/junit/rules: ServerSideTeleporter.java Service.java ServiceGetter.java

Author: jsedding
Date: Mon Nov 28 17:30:09 2016
New Revision: 1771777

URL: http://svn.apache.org/viewvc?rev=1771777&view=rev
Log:
SLING-6335 - Server-Side Tests: Use ServiceTracker to wait for services rather than polling

Modified:
    sling/trunk/testing/junit/core/src/main/java/org/apache/sling/junit/rules/ServerSideTeleporter.java
    sling/trunk/testing/junit/core/src/main/java/org/apache/sling/junit/rules/Service.java
    sling/trunk/testing/junit/core/src/main/java/org/apache/sling/junit/rules/ServiceGetter.java

Modified: sling/trunk/testing/junit/core/src/main/java/org/apache/sling/junit/rules/ServerSideTeleporter.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/junit/core/src/main/java/org/apache/sling/junit/rules/ServerSideTeleporter.java?rev=1771777&r1=1771776&r2=1771777&view=diff
==============================================================================
--- sling/trunk/testing/junit/core/src/main/java/org/apache/sling/junit/rules/ServerSideTeleporter.java (original)
+++ sling/trunk/testing/junit/core/src/main/java/org/apache/sling/junit/rules/ServerSideTeleporter.java Mon Nov 28 17:30:09 2016
@@ -23,25 +23,25 @@ import org.apache.sling.junit.Activator;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceReference;
+import org.osgi.framework.InvalidSyntaxException;
 
 /** Server-side variant of the TeleporterRule, which provides
  *  access to OSGi services for convenience, but does not do
  *  much more.
  */
 class ServerSideTeleporter extends TeleporterRule {
-    private final List<ServiceReference> toUnget = new ArrayList<ServiceReference>();
+    private final List<ServiceGetter<?>> serviceGettersToClose = new ArrayList<ServiceGetter<?>>();
     private final BundleContext bundleContext;
     private final Bundle bundleUnderTest;
-    
+
     private static final int WAITFOR_SERVICE_TIMEOUT_DEFAULT_SECONDS = 10;
-    
+
     ServerSideTeleporter(Class<?> classUnderTest) {
         bundleContext = Activator.getBundleContext();
         if (bundleContext == null) {
             throw new IllegalStateException("Null BundleContext, should not happen when this class is used");
         }
-        
+
         Bundle bundle = FrameworkUtil.getBundle(classUnderTest);
         if (bundle == null) {
             bundle = bundleContext.getBundle();
@@ -52,9 +52,9 @@ class ServerSideTeleporter extends Telep
     @Override
     protected void after() {
         super.after();
-        for(ServiceReference r : toUnget) {
-            if(r != null) {
-                bundleContext.ungetService(r);
+        for(ServiceGetter<?> serviceGetter : serviceGettersToClose) {
+            if(serviceGetter != null) {
+                serviceGetter.close();
             }
         }
     }
@@ -68,32 +68,25 @@ class ServerSideTeleporter extends Telep
             configuredTimeout = Integer.toString(WAITFOR_SERVICE_TIMEOUT_DEFAULT_SECONDS);
         }
         final long timeout = System.currentTimeMillis() + Integer.parseInt(configuredTimeout) * 1000;
-        
-        while (System.currentTimeMillis() < timeout) {
-            try {
-                T service = getServiceInternal(serviceClass, ldapFilter);
-                if (service != null) {
-                    return service;
-                }
-            }
-            catch (IllegalStateException ex) {
-                // ignore, try again
-            }
-            try {
-                Thread.sleep(50L);
-            }
-            catch (InterruptedException ex) {
-                // ignore
+        try {
+            T service = getServiceInternal(serviceClass, ldapFilter, timeout);
+            if (service != null) {
+                return service;
             }
+        } catch (InterruptedException e) {
+            throw new IllegalStateException(
+                    "unable to get a service reference before timeout, class=" + serviceClass.getName() + ", filter='" + ldapFilter + "'", e);
+        } catch (InvalidSyntaxException e) {
+            throw new IllegalArgumentException("Invalid syntax for argument ldapFilter", e);
         }
         throw new IllegalStateException(
                 "unable to get a service reference, class=" + serviceClass.getName() + ", filter='" + ldapFilter + "'");
     }
 
-    private <T> T getServiceInternal (Class<T> serviceClass, String ldapFilter) {
-        final ServiceGetter sg = new ServiceGetter(bundleContext, serviceClass, ldapFilter);
-        toUnget.add(sg.serviceReference);
-        return serviceClass.cast(sg.service);
+    private <T> T getServiceInternal (Class<T> serviceClass, String ldapFilter, long timeoutMs)
+            throws InterruptedException, InvalidSyntaxException {
+        ServiceGetter<T> serviceGetter = ServiceGetter.create(bundleContext, serviceClass, ldapFilter);
+        serviceGettersToClose.add(serviceGetter);
+        return serviceGetter.getService(timeoutMs);
     }
-
 }

Modified: sling/trunk/testing/junit/core/src/main/java/org/apache/sling/junit/rules/Service.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/junit/core/src/main/java/org/apache/sling/junit/rules/Service.java?rev=1771777&r1=1771776&r2=1771777&view=diff
==============================================================================
--- sling/trunk/testing/junit/core/src/main/java/org/apache/sling/junit/rules/Service.java (original)
+++ sling/trunk/testing/junit/core/src/main/java/org/apache/sling/junit/rules/Service.java Mon Nov 28 17:30:09 2016
@@ -34,7 +34,7 @@ public class Service implements TestRule
 
     private final Class<?> serviceClass;
 
-    private Object service;
+    private ServiceGetter<?> serviceGetter;
 
     public Service(Class<?> serviceClass) {
         this.serviceClass = serviceClass;
@@ -54,17 +54,12 @@ public class Service implements TestRule
                     base.evaluate();
                     return;
                 }
-                
-                final ServiceGetter sg = new ServiceGetter(bundleContext, serviceClass, null);
-                Service.this.service = serviceClass.cast(sg.service);
 
+                serviceGetter = ServiceGetter.create(bundleContext, serviceClass, null);
                 try {
                     base.evaluate();
                 } finally {
-                    Service.this.service = null;
-                    if(sg.serviceReference != null) {
-                        bundleContext.ungetService(sg.serviceReference);
-                    }
+                    serviceGetter.close();
                 }
             }
 
@@ -79,7 +74,7 @@ public class Service implements TestRule
      * @return The service object.
      */
     public <T> T getService(Class<T> serviceClass) {
-        return serviceClass.cast(service);
+        return serviceClass.cast(serviceGetter.getService());
     }
 
 }

Modified: sling/trunk/testing/junit/core/src/main/java/org/apache/sling/junit/rules/ServiceGetter.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/junit/core/src/main/java/org/apache/sling/junit/rules/ServiceGetter.java?rev=1771777&r1=1771776&r2=1771777&view=diff
==============================================================================
--- sling/trunk/testing/junit/core/src/main/java/org/apache/sling/junit/rules/ServiceGetter.java (original)
+++ sling/trunk/testing/junit/core/src/main/java/org/apache/sling/junit/rules/ServiceGetter.java Mon Nov 28 17:30:09 2016
@@ -17,61 +17,71 @@
 
 package org.apache.sling.junit.rules;
 
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
+import java.io.Closeable;
 
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
 
 /** Implements the logic used to get a service */
-class ServiceGetter {
-    final ServiceReference serviceReference;
-    final Object service;
+class ServiceGetter<T> implements Closeable {
+
+    private final ServiceTracker tracker;
+    private final BundleContext bundleContext;
+
+    public static <T> ServiceGetter<T> create(BundleContext bundleContext, Class<T> serviceClass, String ldapFilter) {
+        return new ServiceGetter<T>(bundleContext, serviceClass, ldapFilter);
+    }
 
     @SuppressWarnings("unchecked")
-    ServiceGetter(BundleContext bundleContext, Class<?> serviceClass, String ldapFilter) {
-        Object s;
-        
+    private ServiceGetter(BundleContext bundleContext, Class<T> serviceClass, String ldapFilter) {
         if (serviceClass.equals(BundleContext.class)) {
             // Special case to provide the BundleContext to tests
-            s = serviceClass.cast(bundleContext);
-            serviceReference = null;
+            this.bundleContext = bundleContext;
+            this.tracker = null;
         } else {
-            if(ldapFilter != null && !ldapFilter.isEmpty()) {
-                try {
-                    final ServiceReference [] services = bundleContext.getServiceReferences(serviceClass.getName(), ldapFilter);
-                    if(services == null) {
-                        serviceReference = null;
-                    } else {
-                        // Prefer services which have a higher ranking
-                        final List<ServiceReference> sorted = Arrays.asList(services);
-                        Collections.sort(sorted);
-                        serviceReference = sorted.get(sorted.size() - 1);
-                    }
-                } catch (InvalidSyntaxException e) {
-                    throw new IllegalStateException("Invalid filter syntax:" + ldapFilter, e);
-                }
+            this.bundleContext = null;
+            final String classFilter = String.format("(%s=%s)", Constants.OBJECTCLASS, serviceClass.getName());
+            final String combinedFilter;
+            if (ldapFilter == null || ldapFilter.trim().length() == 0) {
+                combinedFilter = classFilter;
             } else {
-                serviceReference = bundleContext.getServiceReference(serviceClass.getName());
+                combinedFilter = String.format("(&%s%s)", classFilter, ldapFilter);
             }
-            
-            if (serviceReference == null) {
-                throw new IllegalStateException(
-                        "unable to get a service reference, class=" + serviceClass.getName() + ", filter='" + ldapFilter + "'");
+            final Filter filter;
+            try {
+                filter = FrameworkUtil.createFilter(combinedFilter);
+                tracker = new ServiceTracker(bundleContext, filter, null);
+                tracker.open();
+            } catch (InvalidSyntaxException e) {
+                throw new IllegalArgumentException("Syntax of argument ldapFilter is invalid", e);
             }
+        }
+    }
 
-            final Object service = bundleContext.getService(serviceReference);
+    public T getService() {
+        if (tracker == null) {
+            return (T)bundleContext;
+        } else {
+            return (T)tracker.getService();
+        }
+    }
 
-            if (service == null) {
-                throw new IllegalStateException(
-                        "unable to get an instance of the service");
-            }
+    public T getService(long timeout) throws InterruptedException {
+        if (tracker == null) {
+            return (T)bundleContext;
+        } else {
+            return (T)tracker.waitForService(timeout);
+        }
+    }
 
-            s = serviceClass.cast(service);
+    @Override
+    public void close() {
+        if (tracker != null) {
+            tracker.close();
         }
-        
-        service = s;
     }
 }
\ No newline at end of file