SLING-6811 osgi-mock: Support ServiceFactory and System Bundle

git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1793112 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockBundle.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockBundle.java
index 1fc9483..89ad673 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/MockBundle.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockBundle.java
@@ -31,6 +31,7 @@
 
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.Version;
 
@@ -46,16 +47,26 @@
     private final long bundleId;
     private final BundleContext bundleContext;
     private Map<String, String> headers = ImmutableMap.<String, String>of();
-    private String symbolicName = "mock-bundle";
+    private String symbolicName;
     private long lastModified;
 
     /**
      * Constructor
      * @param bundleContext Bundle context
+     * @param bundleId Bundle ID
+     */
+    MockBundle(BundleContext bundleContext, long bundleId) {
+        this.bundleId = bundleId;
+        this.bundleContext = bundleContext;
+        this.symbolicName = (bundleId == Constants.SYSTEM_BUNDLE_ID ? Constants.SYSTEM_BUNDLE_SYMBOLICNAME : "mock-bundle");
+    }
+
+    /**
+     * Constructor
+     * @param bundleContext Bundle context
      */
     public MockBundle(BundleContext bundleContext) {
-        this.bundleId = ++bundleCounter;
-        this.bundleContext = bundleContext;
+        this(bundleContext, ++bundleCounter);
     }
 
     @Override
@@ -174,6 +185,16 @@
         return queryPath;
     }
     
+    @Override
+    public String getLocation() {
+        if (bundleId == Constants.SYSTEM_BUNDLE_ID) {
+            return Constants.SYSTEM_BUNDLE_LOCATION;
+        }
+        else {
+            return null;
+        }
+    }
+
     // --- unsupported operations ---
     @Override
     public Enumeration<URL> findEntries(final String path, final String filePattern, final boolean recurse) {
@@ -181,11 +202,6 @@
     }
 
     @Override
-    public String getLocation() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
     public ServiceReference<?>[] getRegisteredServices() {
         throw new UnsupportedOperationException();
     }
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockBundleContext.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockBundleContext.java
index 7c40afa..1c3033e 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/MockBundleContext.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockBundleContext.java
@@ -43,6 +43,7 @@
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleEvent;
 import org.osgi.framework.BundleListener;
+import org.osgi.framework.Constants;
 import org.osgi.framework.Filter;
 import org.osgi.framework.FrameworkListener;
 import org.osgi.framework.InvalidSyntaxException;
@@ -68,8 +69,11 @@
     private final Queue<BundleListener> bundleListeners = new ConcurrentLinkedQueue<BundleListener>();
     private final ConfigurationAdmin configAdmin = new MockConfigurationAdmin();
     private File dataFileBaseDir;
+    
+    private final Bundle systemBundle;
 
     public MockBundleContext() {
+        this.systemBundle = new MockBundle(this, Constants.SYSTEM_BUNDLE_ID);
         this.bundle = new MockBundle(this);
         
         // register configuration admin by default
@@ -120,6 +124,12 @@
         return registration;
     }
     
+    @SuppressWarnings("unchecked")
+    @Override
+    public <S> ServiceRegistration<S> registerService(Class<S> clazz, ServiceFactory<S> factory, Dictionary<String, ?> properties) {
+        return registerService(clazz.getName(), factory, properties);
+    }
+    
     /**
      * Check for already registered services that may be affected by the service registration - either
      * adding by additional optional references, or creating a conflict in the dependencies.
@@ -433,6 +443,24 @@
         }
     }
 
+    @Override
+    public Bundle getBundle(final long bundleId) {
+        if (bundleId == Constants.SYSTEM_BUNDLE_ID) {
+            return systemBundle;
+        }
+        // otherwise return null - no bundle found
+        return null;
+    }
+
+    @Override
+    public Bundle getBundle(String location) {
+        if (StringUtils.equals(location, Constants.SYSTEM_BUNDLE_LOCATION)) {
+            return systemBundle;
+        }
+        // otherwise return null - no bundle found
+        return null;
+    }
+
     // --- unsupported operations ---
     @Override
     public Bundle installBundle(final String s) {
@@ -445,21 +473,6 @@
     }
 
     @Override
-    public Bundle getBundle(final long l) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public Bundle getBundle(String location) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public <S> ServiceRegistration<S> registerService(Class<S> clazz, ServiceFactory<S> factory, Dictionary<String, ?> properties) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
     public <S> ServiceObjects<S> getServiceObjects(ServiceReference<S> reference) {
         throw new UnsupportedOperationException();
     }
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceRegistration.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceRegistration.java
index 7141949..7a2e87d 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceRegistration.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceRegistration.java
@@ -101,8 +101,15 @@
         return clazzes;
     }
 
+    @SuppressWarnings("unchecked")
     T getService() {
-        return this.service;
+        if (this.service instanceof ServiceFactory) {
+            ServiceFactory<T> factory = (ServiceFactory<T>)this.service;
+            return factory.getService(this.bundleContext.getBundle(), this);
+        }
+        else {
+            return this.service;
+        }
     }
     
     @Override
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextTest.java
index 5dba8d6..8161dea 100644
--- a/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextTest.java
@@ -39,6 +39,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.runners.MockitoJUnitRunner;
+import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleEvent;
 import org.osgi.framework.BundleListener;
@@ -46,6 +47,7 @@
 import org.osgi.framework.Filter;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceFactory;
 import org.osgi.framework.ServiceListener;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
@@ -124,6 +126,30 @@
     }
     
     @Test
+    public void testServiceFactoryRegistration() throws InvalidSyntaxException {
+        // prepare test services
+        Class<String> clazz = String.class;
+        final String service = "abc";
+        Dictionary<String, Object> properties1 = getServiceProperties(null);
+        ServiceRegistration reg = bundleContext.registerService(clazz, new ServiceFactory<String>() {
+            @Override
+            public String getService(Bundle bundle, ServiceRegistration<String> registration) {
+                return service;
+            }
+            @Override
+            public void ungetService(Bundle bundle, ServiceRegistration<String> registration, String service) {
+                // do nothing
+            }
+        }, properties1);
+
+        ServiceReference<String> ref = bundleContext.getServiceReference(clazz);
+        assertNotNull(ref);
+        assertSame(reg.getReference(), ref);
+        assertSame(service, bundleContext.getService(ref));
+        bundleContext.ungetService(ref);
+    }
+    
+    @Test
     public void testNoServiceReferences() throws InvalidSyntaxException {
         ServiceReference<?>[] refs = bundleContext.getServiceReferences(String.class.getName(), null);
         assertNull(refs);
@@ -233,4 +259,23 @@
         
         assertEquals(childFile.getParentFile(), rootFile);
     }
+
+    @Test
+    public void testSystemBundleById() {
+        Bundle systemBundle = bundleContext.getBundle(Constants.SYSTEM_BUNDLE_ID);
+        assertNotNull(systemBundle);
+        assertEquals(Constants.SYSTEM_BUNDLE_ID, systemBundle.getBundleId());
+        assertEquals(Constants.SYSTEM_BUNDLE_SYMBOLICNAME, systemBundle.getSymbolicName());
+        assertEquals(Constants.SYSTEM_BUNDLE_LOCATION, systemBundle.getLocation());
+    }
+
+    @Test
+    public void testSystemBundleByLocation() {
+        Bundle systemBundle = bundleContext.getBundle(Constants.SYSTEM_BUNDLE_LOCATION);
+        assertNotNull(systemBundle);
+        assertEquals(Constants.SYSTEM_BUNDLE_ID, systemBundle.getBundleId());
+        assertEquals(Constants.SYSTEM_BUNDLE_SYMBOLICNAME, systemBundle.getSymbolicName());
+        assertEquals(Constants.SYSTEM_BUNDLE_LOCATION, systemBundle.getLocation());
+    }
+
 }