You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 10:18:12 UTC

[sling-org-apache-sling-testing-osgi-mock] annotated tag org.apache.sling.testing.osgi-mock-1.0.0 created (now f97f50e)

This is an automated email from the ASF dual-hosted git repository.

rombert pushed a change to annotated tag org.apache.sling.testing.osgi-mock-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git.


      at f97f50e  (tag)
 tagging 182cbff4718c9641b08943b99166b9b8d5885b7f (commit)
      by sseifert
      on Fri Oct 17 08:17:40 2014 +0000

- Log -----------------------------------------------------------------
org.apache.sling.testing.osgi-mock-1.0.0
-----------------------------------------------------------------------

This annotated tag includes the following new commits:

     new ced4ea7  SLING-4042 Donate sling-mock, jcr-mock, osgi-mock implementation
     new 3dc3e50  svn:ignore
     new 2e65a19  SLING-4042 move all mock projects to mocks/ subdirectory
     new d7c4834  SLING-4042 add missing package-info files
     new 3af0410  SLING-4042 make sure dependency injection is continued even if not all injections succeeded, and report root cause of invocation target exceptions
     new 48a1b95  SLING-4042 add README files
     new 5bc29ad  add/update SCM urls
     new d2636f1  [maven-release-plugin] prepare release org.apache.sling.testing.osgi-mock-1.0.0
     new 182cbff  [maven-release-plugin]  copy for tag org.apache.sling.testing.osgi-mock-1.0.0

The 9 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


-- 
To stop receiving notification emails like this one, please contact
['"commits@sling.apache.org" <co...@sling.apache.org>'].

[sling-org-apache-sling-testing-osgi-mock] 01/09: SLING-4042 Donate sling-mock, jcr-mock, osgi-mock implementation

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit ced4ea745cb4c6e17f5fd4481e07d83a2097b809
Author: sseifert <ss...@unknown>
AuthorDate: Mon Oct 13 11:54:39 2014 +0000

    SLING-4042 Donate sling-mock, jcr-mock, osgi-mock implementation
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/osgi-mock@1631356 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml                                            | 119 ++++++++
 .../apache/sling/testing/mock/osgi/MockBundle.java | 182 +++++++++++++
 .../sling/testing/mock/osgi/MockBundleContext.java | 220 +++++++++++++++
 .../testing/mock/osgi/MockComponentContext.java    |  98 +++++++
 .../apache/sling/testing/mock/osgi/MockFilter.java |  46 ++++
 .../sling/testing/mock/osgi/MockLogService.java    |  87 ++++++
 .../apache/sling/testing/mock/osgi/MockOsgi.java   | 250 +++++++++++++++++
 .../testing/mock/osgi/MockServiceReference.java    | 131 +++++++++
 .../testing/mock/osgi/MockServiceRegistration.java | 105 +++++++
 .../sling/testing/mock/osgi/OsgiMetadataUtil.java  | 278 +++++++++++++++++++
 .../testing/mock/osgi/ReflectionServiceUtil.java   | 301 +++++++++++++++++++++
 src/main/resources/simplelogger.properties         |  18 ++
 src/site/markdown/index.md                         |  35 +++
 src/site/markdown/usage.md                         |  59 ++++
 .../testing/mock/osgi/MockBundleContextTest.java   | 159 +++++++++++
 .../sling/testing/mock/osgi/MockBundleTest.java    |  60 ++++
 .../mock/osgi/MockComponentContextTest.java        |  84 ++++++
 .../sling/testing/mock/osgi/MockFilterTest.java    |  46 ++++
 .../testing/mock/osgi/MockLogServiceTest.java      |  70 +++++
 .../mock/osgi/MockServiceReferenceTest.java        |  81 ++++++
 .../testing/mock/osgi/OsgiMetadataUtilTest.java    |  93 +++++++
 .../mock/osgi/ReflectionServiceUtilTest.java       | 226 ++++++++++++++++
 .../sling/testing/mock/osgi/package-info.java      |  23 ++
 src/test/resources/META-INF/test.txt               |   1 +
 ...ling.testing.mock.osgi.OsgiMetadataUtilTest.xml |  14 +
 ...testing.mock.osgi.ReflectionServiceUtilTest.xml |  32 +++
 src/test/resources/simplelogger.properties         |  18 ++
 27 files changed, 2836 insertions(+)

diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..708d885
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.sling</groupId>
+        <artifactId>sling</artifactId>
+        <version>22</version>
+        <relativePath>../../parent/pom.xml</relativePath>
+    </parent>
+
+    <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
+    <version>1.0.0-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <name>Apache Sling Testing OSGi Mock</name>
+    <description>Mock implementation of selected OSGi APIs.</description>
+
+    <properties>
+        <sling.java.version>6</sling.java.version>
+    </properties>
+
+    <dependencies>
+  
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr.annotations</artifactId>
+            <scope>compile</scope>
+        </dependency>
+    
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <scope>compile</scope>
+        </dependency>
+    
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>15.0</version>
+            <scope>compile</scope>
+        </dependency>
+  
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.0.1</version>
+            <scope>compile</scope>
+        </dependency>
+    
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <scope>compile</scope>
+        </dependency>
+    
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <version>1.9.5</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+  
+    <build>
+        <plugins>
+    
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+            </plugin>
+      
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-scr-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>generate-scr-scrdescriptor</id>
+                        <goals>
+                            <goal>scr</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+    
+        </plugins>
+    </build>
+  
+</project>
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
new file mode 100644
index 0000000..6c1f22e
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockBundle.java
@@ -0,0 +1,182 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.osgi;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.Version;
+
+/**
+ * Mock {@link Bundle} implementation.
+ */
+class MockBundle implements Bundle {
+
+    private static volatile long bundleCounter;
+
+    private final long bundleId;
+    private final BundleContext bundleContext;
+
+    /**
+     * Constructor
+     */
+    public MockBundle(BundleContext bundleContext) {
+        this.bundleId = ++bundleCounter;
+        this.bundleContext = bundleContext;
+    }
+
+    @Override
+    public long getBundleId() {
+        return this.bundleId;
+    }
+
+    @Override
+    public BundleContext getBundleContext() {
+        return this.bundleContext;
+    }
+
+    @Override
+    public URL getEntry(final String name) {
+        // try to load resource from classpath
+        return getClass().getResource(name);
+    }
+
+    @Override
+    public int getState() {
+        return Bundle.ACTIVE;
+    }
+
+    // --- unsupported operations ---
+    @Override
+    public Enumeration<?> findEntries(final String path, final String filePattern, final boolean recurse) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Enumeration<?> getEntryPaths(final String path) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Dictionary<?, ?> getHeaders() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Dictionary<?, ?> getHeaders(final String locale) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public long getLastModified() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getLocation() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ServiceReference[] getRegisteredServices() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public URL getResource(final String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Enumeration<?> getResources(final String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ServiceReference[] getServicesInUse() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getSymbolicName() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean hasPermission(final Object permission) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Class<?> loadClass(final String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void start() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void stop() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void uninstall() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void update() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void update(final InputStream inputStream) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void start(final int options) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void stop(final int options) {
+        throw new UnsupportedOperationException();
+    }
+
+    // this is part of org.osgi 4.2.0
+    public Map getSignerCertificates(final int signersType) {
+        throw new UnsupportedOperationException();
+    }
+
+    // this is part of org.osgi 4.2.0
+    public Version getVersion() {
+        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
new file mode 100644
index 0000000..cbaa13d
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockBundleContext.java
@@ -0,0 +1,220 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.osgi;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.commons.lang3.StringUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Mock {@link BundleContext} implementation.
+ */
+class MockBundleContext implements BundleContext {
+
+    private final MockBundle bundle;
+    private final List<MockServiceRegistration> registeredServices = new ArrayList<MockServiceRegistration>();
+    private final List<ServiceListener> serviceListeners = new ArrayList<ServiceListener>();
+    private final List<BundleListener> bundleListeners = new ArrayList<BundleListener>();
+
+    public MockBundleContext() {
+        this.bundle = new MockBundle(this);
+    }
+
+    @Override
+    public Bundle getBundle() {
+        return this.bundle;
+    }
+
+    @Override
+    public Filter createFilter(final String s) {
+        // return filter that denies all
+        return new MockFilter();
+    }
+
+    @Override
+    public ServiceRegistration registerService(final String clazz, final Object service, final Dictionary properties) {
+        String[] clazzes;
+        if (StringUtils.isBlank(clazz)) {
+            clazzes = new String[0];
+        } else {
+            clazzes = new String[] { clazz };
+        }
+        return registerService(clazzes, service, properties);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public ServiceRegistration registerService(final String[] clazzes, final Object service, final Dictionary properties) {
+        MockServiceRegistration registration = new MockServiceRegistration(this.bundle, clazzes, service, properties);
+        this.registeredServices.add(registration);
+        notifyServiceListeners(ServiceEvent.REGISTERED, registration.getReference());
+        return registration;
+    }
+
+    @Override
+    public ServiceReference getServiceReference(final String clazz) {
+        ServiceReference[] serviceRefs = getServiceReferences(clazz, null);
+        if (serviceRefs != null && serviceRefs.length > 0) {
+            return serviceRefs[0];
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public ServiceReference[] getServiceReferences(final String clazz, final String filter) {
+        Set<ServiceReference> result = new TreeSet<ServiceReference>();
+        for (MockServiceRegistration serviceRegistration : this.registeredServices) {
+            if (serviceRegistration.matches(clazz, filter)) {
+                result.add(serviceRegistration.getReference());
+            }
+        }
+        if (result.isEmpty()) {
+            return null;
+        } else {
+            return result.toArray(new ServiceReference[result.size()]);
+        }
+    }
+
+    @Override
+    public ServiceReference[] getAllServiceReferences(final String clazz, final String filter) {
+        // for now just do the same as getServiceReferences
+        return getServiceReferences(clazz, filter);
+    }
+
+    @Override
+    public Object getService(final ServiceReference serviceReference) {
+        return ((MockServiceReference) serviceReference).getService();
+    }
+
+    @Override
+    public boolean ungetService(final ServiceReference serviceReference) {
+        // do nothing for now
+        return false;
+    }
+
+    @Override
+    public void addServiceListener(final ServiceListener serviceListener) {
+        addServiceListener(serviceListener, null);
+    }
+
+    @Override
+    public void addServiceListener(final ServiceListener serviceListener, final String s) {
+        if (!serviceListeners.contains(serviceListener)) {
+            serviceListeners.add(serviceListener);
+        }
+    }
+
+    @Override
+    public void removeServiceListener(final ServiceListener serviceListener) {
+        serviceListeners.remove(serviceListener);
+    }
+
+    private void notifyServiceListeners(int eventType, ServiceReference serviceReference) {
+        final ServiceEvent event = new ServiceEvent(eventType, serviceReference);
+        for (ServiceListener serviceListener : serviceListeners) {
+            serviceListener.serviceChanged(event);
+        }
+    }
+
+    @Override
+    public void addBundleListener(final BundleListener bundleListener) {
+        if (!bundleListeners.contains(bundleListener)) {
+            bundleListeners.add(bundleListener);
+        }
+    }
+
+    @Override
+    public void removeBundleListener(final BundleListener bundleListener) {
+        bundleListeners.remove(bundleListener);
+    }
+
+    void sendBundleEvent(BundleEvent bundleEvent) {
+        for (BundleListener bundleListener : bundleListeners) {
+            bundleListener.bundleChanged(bundleEvent);
+        }
+    }
+
+    @Override
+    public void addFrameworkListener(final FrameworkListener frameworkListener) {
+        // accept method, but ignore it
+    }
+
+    @Override
+    public void removeFrameworkListener(final FrameworkListener frameworkListener) {
+        // accept method, but ignore it
+    }
+
+    Object locateService(final String name, final ServiceReference reference) {
+        for (MockServiceRegistration serviceRegistration : this.registeredServices) {
+            if (serviceRegistration.getReference() == reference) {
+                return serviceRegistration.getService();
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Bundle[] getBundles() {
+        return new Bundle[0];
+    }
+
+    // --- unsupported operations ---
+    @Override
+    public String getProperty(final String s) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Bundle installBundle(final String s) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Bundle installBundle(final String s, final InputStream inputStream) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Bundle getBundle(final long l) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public File getDataFile(final String s) {
+        throw new UnsupportedOperationException();
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockComponentContext.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockComponentContext.java
new file mode 100644
index 0000000..cf70b1d
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockComponentContext.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.osgi;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.ComponentInstance;
+
+/**
+ * Mock {@link ComponentContext} implementation.
+ */
+class MockComponentContext implements ComponentContext {
+
+    private final MockBundleContext bundleContext;
+    private final Dictionary<String, Object> properties;
+
+    public MockComponentContext(final MockBundleContext mockBundleContext) {
+        this(mockBundleContext, new Hashtable<String, Object>());
+    }
+
+    public MockComponentContext(final MockBundleContext mockBundleContext, final Dictionary<String, Object> properties) {
+        this.bundleContext = mockBundleContext;
+        this.properties = properties;
+    }
+
+    @Override
+    public Dictionary<String, Object> getProperties() {
+        return this.properties;
+    }
+
+    @Override
+    public Object locateService(final String name, final ServiceReference reference) {
+        return this.bundleContext.locateService(name, reference);
+    }
+
+    @Override
+    public BundleContext getBundleContext() {
+        return this.bundleContext;
+    }
+
+    @Override
+    public void disableComponent(final String name) {
+        // allow calling, but ignore
+    }
+
+    @Override
+    public void enableComponent(final String name) {
+        // allow calling, but ignore
+    }
+
+    // --- unsupported operations ---
+    @Override
+    public ComponentInstance getComponentInstance() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ServiceReference getServiceReference() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Bundle getUsingBundle() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Object locateService(final String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Object[] locateServices(final String name) {
+        throw new UnsupportedOperationException();
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockFilter.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockFilter.java
new file mode 100644
index 0000000..b0f585c
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockFilter.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.osgi;
+
+import java.util.Dictionary;
+
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Mock {@link Filter} implementation.
+ */
+class MockFilter implements Filter {
+
+    @Override
+    public boolean match(final ServiceReference reference) {
+        return false;
+    }
+
+    @Override
+    public boolean match(final Dictionary dictionary) {
+        return false;
+    }
+
+    @Override
+    public boolean matchCase(final Dictionary dictionary) {
+        return false;
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockLogService.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockLogService.java
new file mode 100644
index 0000000..28d1433
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockLogService.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.osgi;
+
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Mock {@link LogService} implementation.
+ */
+class MockLogService implements LogService {
+
+    private final Logger log;
+
+    public MockLogService(final Class<?> loggerContext) {
+        this.log = LoggerFactory.getLogger(loggerContext);
+    }
+
+    @Override
+    public void log(final int level, final String message) {
+        switch (level) {
+        case LogService.LOG_ERROR:
+            this.log.error(message);
+            break;
+        case LogService.LOG_WARNING:
+            this.log.warn(message);
+            break;
+        case LogService.LOG_INFO:
+            this.log.info(message);
+            break;
+        case LogService.LOG_DEBUG:
+            this.log.debug(message);
+            break;
+        default:
+            throw new IllegalArgumentException("Invalid log level: " + level);
+        }
+    }
+
+    @Override
+    public void log(final int level, final String message, final Throwable exception) {
+        switch (level) {
+        case LogService.LOG_ERROR:
+            this.log.error(message, exception);
+            break;
+        case LogService.LOG_WARNING:
+            this.log.warn(message, exception);
+            break;
+        case LogService.LOG_INFO:
+            this.log.info(message, exception);
+            break;
+        case LogService.LOG_DEBUG:
+            this.log.debug(message, exception);
+            break;
+        default:
+            throw new IllegalArgumentException("Invalid log level: " + level);
+        }
+    }
+
+    @Override
+    public void log(final ServiceReference sr, final int level, final String message) {
+        log(level, message);
+    }
+
+    @Override
+    public void log(final ServiceReference sr, final int level, final String message, final Throwable exception) {
+        log(level, message, exception);
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java
new file mode 100644
index 0000000..fd65fe1
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java
@@ -0,0 +1,250 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.osgi;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.log.LogService;
+
+/**
+ * Factory for mock OSGi objects.
+ */
+public final class MockOsgi {
+
+    private MockOsgi() {
+        // static methods only
+    }
+
+    /**
+     * @return Mocked {@link BundleContext} instance
+     */
+    public static BundleContext newBundleContext() {
+        return new MockBundleContext();
+    }
+
+    /**
+     * Simulates a bundle event on the given bundle context (that is forwarded
+     * to registered bundle listeners).
+     * @param bundleContext Bundle context
+     * @param bundleEvent Bundle event
+     */
+    public static void sendBundleEvent(BundleContext bundleContext, BundleEvent bundleEvent) {
+        ((MockBundleContext) bundleContext).sendBundleEvent(bundleEvent);
+    }
+
+    /**
+     * @return Mocked {@link ComponentContext} instance
+     */
+    public static ComponentContext newComponentContext() {
+        return new MockComponentContext((MockBundleContext) newBundleContext());
+    }
+
+    /**
+     * @param properties Properties
+     * @return Mocked {@link ComponentContext} instance
+     */
+    public static ComponentContext newComponentContext(Dictionary<String, Object> properties) {
+        return newComponentContext(newBundleContext(), properties);
+    }
+
+    /**
+     * @param properties Properties
+     * @return Mocked {@link ComponentContext} instance
+     */
+    public static ComponentContext newComponentContext(Map<String, Object> properties) {
+        return newComponentContext(toDictionary(properties));
+    }
+
+    /**
+     * @param bundleContext Bundle context
+     * @param properties Properties
+     * @return Mocked {@link ComponentContext} instance
+     */
+    public static ComponentContext newComponentContext(BundleContext bundleContext,
+            Dictionary<String, Object> properties) {
+        return new MockComponentContext((MockBundleContext) bundleContext, properties);
+    }
+
+    /**
+     * @param bundleContext Bundle context
+     * @param properties Properties
+     * @return Mocked {@link ComponentContext} instance
+     */
+    public static ComponentContext newComponentContext(BundleContext bundleContext, Map<String, Object> properties) {
+        return newComponentContext(bundleContext, toDictionary(properties));
+    }
+
+    /**
+     * @param loggerContext Context class for logging
+     * @return Mocked {@link LogService} instance
+     */
+    public static LogService newLogService(final Class<?> loggerContext) {
+        return new MockLogService(loggerContext);
+    }
+
+    /**
+     * Simulate OSGi service dependency injection. Injects direct references and
+     * multiple references. If a some references could not be injected no error
+     * is thrown.
+     * @param target Service instance
+     * @param bundleContext Bundle context from which services are fetched to inject.
+     * @return true if all dependencies could be injected
+     */
+    public static boolean injectServices(Object target, BundleContext bundleContext) {
+        return ReflectionServiceUtil.injectServices(target, bundleContext);
+    }
+
+    /**
+     * Simulate activation of service instance. Invokes the @Activate annotated
+     * method.
+     * @param target Service instance.
+     * @return true if activation method was called. False if such a method did
+     *         not exist.
+     */
+    public static boolean activate(Object target) {
+        ComponentContext componentContext = newComponentContext();
+        return ReflectionServiceUtil.activateDeactivate(target, componentContext, true);
+    }
+
+    /**
+     * Simulate activation of service instance. Invokes the @Activate annotated
+     * method.
+     * @param target Service instance.
+     * @param properties Properties
+     * @return true if activation method was called. False if such a method did
+     *         not exist.
+     */
+    public static boolean activate(Object target, Dictionary<String, Object> properties) {
+        ComponentContext componentContext = newComponentContext(properties);
+        return ReflectionServiceUtil.activateDeactivate(target, componentContext, true);
+    }
+
+    /**
+     * Simulate activation of service instance. Invokes the @Activate annotated
+     * method.
+     * @param target Service instance.
+     * @param properties Properties
+     * @return true if activation method was called. False if such a method did
+     *         not exist.
+     */
+    public static boolean activate(Object target, Map<String, Object> properties) {
+        return activate(target, toDictionary(properties));
+    }
+
+    /**
+     * Simulate activation of service instance. Invokes the @Activate annotated
+     * method.
+     * @param target Service instance.
+     * @param bundleContext Bundle context
+     * @param properties Properties
+     * @return true if activation method was called. False if such a method did
+     *         not exist.
+     */
+    public static boolean activate(Object target, BundleContext bundleContext, Dictionary<String, Object> properties) {
+        ComponentContext componentContext = newComponentContext(bundleContext, properties);
+        return ReflectionServiceUtil.activateDeactivate(target, componentContext, true);
+    }
+
+    /**
+     * Simulate activation of service instance. Invokes the @Activate annotated
+     * method.
+     * @param target Service instance.
+     * @param bundleContext Bundle context
+     * @param properties Properties
+     * @return true if activation method was called. False if such a method did
+     *         not exist.
+     */
+    public static boolean activate(Object target, BundleContext bundleContext, Map<String, Object> properties) {
+        return activate(target, bundleContext, toDictionary(properties));
+    }
+
+    /**
+     * Simulate deactivation of service instance. Invokes the @Activate
+     * annotated method.
+     * @param target Service instance.
+     * @return true if deactivation method was called. False if such a method
+     *         did not exist.
+     */
+    public static boolean deactivate(Object target) {
+        ComponentContext componentContext = newComponentContext();
+        return ReflectionServiceUtil.activateDeactivate(target, componentContext, false);
+    }
+
+    /**
+     * Simulate deactivation of service instance. Invokes the @Activate
+     * annotated method.
+     * @param target Service instance.
+     * @param properties Properties
+     * @return true if deactivation method was called. False if such a method
+     *         did not exist.
+     */
+    public static boolean deactivate(Object target, Dictionary<String, Object> properties) {
+        ComponentContext componentContext = newComponentContext(properties);
+        return ReflectionServiceUtil.activateDeactivate(target, componentContext, false);
+    }
+
+    /**
+     * Simulate deactivation of service instance. Invokes the @Activate
+     * annotated method.
+     * @param target Service instance.
+     * @param properties Properties
+     * @return true if deactivation method was called. False if such a method
+     *         did not exist.
+     */
+    public static boolean deactivate(Object target, Map<String, Object> properties) {
+        return deactivate(target, toDictionary(properties));
+    }
+
+    /**
+     * Simulate deactivation of service instance. Invokes the @Activate
+     * annotated method.
+     * @param target Service instance.
+     * @param bundleContext Bundle context
+     * @param properties Properties
+     * @return true if deactivation method was called. False if such a method
+     *         did not exist.
+     */
+    public static boolean deactivate(Object target, BundleContext bundleContext, Dictionary<String, Object> properties) {
+        ComponentContext componentContext = newComponentContext(bundleContext, properties);
+        return ReflectionServiceUtil.activateDeactivate(target, componentContext, false);
+    }
+
+    /**
+     * Simulate activation of service instance. Invokes the @Activate annotated
+     * method.
+     * @param target Service instance.
+     * @param bundleContext Bundle context
+     * @param properties Properties
+     * @return true if activation method was called. False if such a method did
+     *         not exist.
+     */
+    public static boolean deactivate(Object target, BundleContext bundleContext, Map<String, Object> properties) {
+        return deactivate(target, bundleContext, toDictionary(properties));
+    }
+
+    private static Dictionary<String, Object> toDictionary(Map<String, Object> map) {
+        return new Hashtable<String, Object>(map);
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceReference.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceReference.java
new file mode 100644
index 0000000..c7568be
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceReference.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.osgi;
+
+import java.util.Collections;
+import java.util.Dictionary;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Mock {@link ServiceReference} implementation.
+ */
+class MockServiceReference implements ServiceReference {
+
+    private final Bundle bundle;
+    private final MockServiceRegistration serviceRegistration;
+
+    public MockServiceReference(final Bundle bundle, final MockServiceRegistration serviceRegistration) {
+        this.bundle = bundle;
+        this.serviceRegistration = serviceRegistration;
+    }
+
+    @Override
+    public Bundle getBundle() {
+        return this.bundle;
+    }
+
+    /**
+     * Set service reference property
+     * @param key Key
+     * @param value Value
+     */
+    public void setProperty(final String key, final Object value) {
+        this.serviceRegistration.getProperties().put(key, value);
+    }
+
+    @Override
+    public Object getProperty(final String key) {
+        return this.serviceRegistration.getProperties().get(key);
+    }
+
+    @Override
+    public String[] getPropertyKeys() {
+        Dictionary<String, Object> props = this.serviceRegistration.getProperties();
+        return Collections.list(props.keys()).toArray(new String[props.size()]);
+    }
+
+    @Override
+    public int hashCode() {
+        return ((Long) getServiceId()).hashCode();
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (!(obj instanceof MockServiceReference)) {
+            return false;
+        }
+        return ((Long) getServiceId()).equals(((MockServiceReference) obj).getServiceId());
+    }
+
+    @Override
+    public int compareTo(final Object obj) {
+        if (!(obj instanceof MockServiceReference)) {
+            return 0;
+        }
+        // sort by decreasing by service ranking, and secondary increasing by
+        // service id
+        Integer serviceRanking = getServiceRanking();
+        Integer otherServiceRanking = ((MockServiceReference) obj).getServiceRanking();
+        int serviceRankingCompare = otherServiceRanking.compareTo(serviceRanking);
+        if (serviceRankingCompare == 0) {
+            Long serviceId = getServiceId();
+            Long otherServiceId = ((MockServiceReference) obj).getServiceId();
+            return serviceId.compareTo(otherServiceId);
+        } else {
+            return serviceRankingCompare;
+        }
+    }
+
+    long getServiceId() {
+        Number serviceID = (Number) getProperty(Constants.SERVICE_ID);
+        if (serviceID != null) {
+            return serviceID.longValue();
+        } else {
+            return 0L;
+        }
+    }
+
+    int getServiceRanking() {
+        Number serviceRanking = (Number) getProperty(Constants.SERVICE_RANKING);
+        if (serviceRanking != null) {
+            return serviceRanking.intValue();
+        } else {
+            return 0;
+        }
+    }
+
+    Object getService() {
+        return this.serviceRegistration.getService();
+    }
+
+    // --- unsupported operations ---
+    @Override
+    public Bundle[] getUsingBundles() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isAssignableTo(final Bundle otherBundle, final String className) {
+        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
new file mode 100644
index 0000000..a3bdaf5
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceRegistration.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.osgi;
+
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.w3c.dom.Document;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Mock {@link ServiceRegistration} implementation.
+ */
+class MockServiceRegistration implements ServiceRegistration {
+
+    private static volatile long serviceCounter;
+
+    private final Set<String> clazzes;
+    private final Object service;
+    private Dictionary<String, Object> properties;
+    private final ServiceReference serviceReference;
+
+    @SuppressWarnings("unchecked")
+    public MockServiceRegistration(final Bundle bundle, final String[] clazzes, final Object service,
+            final Dictionary<String, Object> properties) {
+        this.clazzes = new HashSet<String>(ImmutableList.copyOf(clazzes));
+        this.service = service;
+        this.properties = properties != null ? properties : new Hashtable();
+        this.properties.put(Constants.SERVICE_ID, ++serviceCounter);
+        this.serviceReference = new MockServiceReference(bundle, this);
+        readOsgiMetadata();
+    }
+
+    @Override
+    public ServiceReference getReference() {
+        return this.serviceReference;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void setProperties(final Dictionary properties) {
+        this.properties = properties;
+    }
+
+    @Override
+    public void unregister() {
+        // do nothing for now
+    }
+
+    Dictionary<String, Object> getProperties() {
+        return this.properties;
+    }
+
+    boolean matches(final String clazz, final String filter) {
+        // ignore filter for now
+        return this.clazzes.contains(clazz);
+    }
+
+    Object getService() {
+        return this.service;
+    }
+
+    /**
+     * Try to read OSGI-metadata from /OSGI-INF and read all implemented
+     * interfaces and service properties
+     */
+    private void readOsgiMetadata() {
+        Class<?> serviceClass = service.getClass();
+        Document doc = OsgiMetadataUtil.getMetadata(serviceClass);
+
+        // add service interfaces from OSGi metadata
+        clazzes.addAll(OsgiMetadataUtil.getServiceInterfaces(serviceClass, doc));
+
+        // add properties from OSGi metadata
+        Map<String, Object> props = OsgiMetadataUtil.getProperties(serviceClass, doc);
+        for (Map.Entry<String, Object> entry : props.entrySet()) {
+            properties.put(entry.getKey(), entry.getValue());
+        }
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtil.java b/src/main/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtil.java
new file mode 100644
index 0000000..da8bca0
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtil.java
@@ -0,0 +1,278 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.osgi;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+
+/**
+ * Helper methods to parse OSGi metadata.
+ */
+final class OsgiMetadataUtil {
+
+    private static final Logger log = LoggerFactory.getLogger(OsgiMetadataUtil.class);
+
+    private static final DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY;
+    static {
+        DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance();
+        DOCUMENT_BUILDER_FACTORY.setNamespaceAware(true);
+    }
+
+    private static final XPathFactory XPATH_FACTORY = XPathFactory.newInstance();
+
+    private static final BiMap<String, String> NAMESPACES = HashBiMap.create();
+    static {
+        NAMESPACES.put("scr", "http://www.osgi.org/xmlns/scr/v1.1.0");
+    }
+
+    private OsgiMetadataUtil() {
+        // static methods only
+    }
+
+    private static final NamespaceContext NAMESPACE_CONTEXT = new NamespaceContext() {
+        @Override
+        public String getNamespaceURI(String prefix) {
+            return NAMESPACES.get(prefix);
+        }
+
+        @Override
+        public String getPrefix(String namespaceURI) {
+            return NAMESPACES.inverse().get(namespaceURI);
+        }
+
+        @Override
+        public Iterator getPrefixes(String namespaceURI) {
+            return NAMESPACES.keySet().iterator();
+        }
+    };
+
+    /**
+     * Try to read OSGI-metadata from /OSGI-INF and read all implemented
+     * interfaces and service properties
+     * @param clazz OSGi service implementation class
+     * @return Metadata document or null
+     */
+    public static Document getMetadata(Class clazz) {
+        String metadataPath = "/OSGI-INF/" + StringUtils.substringBefore(clazz.getName(), "$") + ".xml";
+        InputStream metadataStream = clazz.getResourceAsStream(metadataPath);
+        if (metadataStream == null) {
+            log.debug("No OSGi metadata found at {}", metadataPath);
+            return null;
+        }
+        try {
+            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
+            return documentBuilder.parse(metadataStream);
+        } catch (ParserConfigurationException ex) {
+            throw new RuntimeException("Unable to read classpath resource: " + metadataPath, ex);
+        } catch (SAXException ex) {
+            throw new RuntimeException("Unable to read classpath resource: " + metadataPath, ex);
+        } catch (IOException ex) {
+            throw new RuntimeException("Unable to read classpath resource: " + metadataPath, ex);
+        } finally {
+            try {
+                metadataStream.close();
+            } catch (IOException ex) {
+                // ignore
+            }
+        }
+    }
+
+    public static Set<String> getServiceInterfaces(Class clazz, Document metadata) {
+        Set<String> serviceInterfaces = new HashSet<String>();
+        if (metadata != null) {
+            String query = "/components/component[@name='" + clazz.getName() + "']/service/provide[@interface!='']";
+            NodeList nodes = queryNodes(metadata, query);
+            if (nodes != null) {
+                for (int i = 0; i < nodes.getLength(); i++) {
+                    Node node = nodes.item(i);
+                    String serviceInterface = getAttributeValue(node, "interface");
+                    if (StringUtils.isNotBlank(serviceInterface)) {
+                        serviceInterfaces.add(serviceInterface);
+                    }
+                }
+            }
+        }
+        return serviceInterfaces;
+    }
+
+    public static Map<String, Object> getProperties(Class clazz, Document metadata) {
+        Map<String, Object> props = new HashMap<String, Object>();
+        if (metadata != null) {
+            String query = "/components/component[@name='" + clazz.getName() + "']/property[@name!='' and @value!='']";
+            NodeList nodes = queryNodes(metadata, query);
+            if (nodes != null) {
+                for (int i = 0; i < nodes.getLength(); i++) {
+                    Node node = nodes.item(i);
+                    String name = getAttributeValue(node, "name");
+                    String value = getAttributeValue(node, "value");
+                    String type = getAttributeValue(node, "type");
+                    if (StringUtils.equals("Integer", type)) {
+                        props.put(name, Integer.parseInt(value));
+                    } else {
+                        props.put(name, value);
+                    }
+                }
+            }
+        }
+        return props;
+    }
+
+    public static List<Reference> getReferences(Class clazz, Document metadata) {
+        List<Reference> references = new ArrayList<Reference>();
+        if (metadata != null) {
+            String query = "/components/component[@name='" + clazz.getName() + "']/reference[@name!='']";
+            NodeList nodes = queryNodes(metadata, query);
+            if (nodes != null) {
+                for (int i = 0; i < nodes.getLength(); i++) {
+                    Node node = nodes.item(i);
+                    references.add(new Reference(node));
+                }
+            }
+        }
+        return references;
+    }
+
+    public static String getActivateMethodName(Class clazz, Document metadata) {
+        if (metadata != null) {
+            String query = "/components/component[@name='" + clazz.getName() + "']";
+            Node node = queryNode(metadata, query);
+            if (node != null) {
+                return getAttributeValue(node, "activate");
+            }
+        }
+        return null;
+    }
+
+    public static String getDeactivateMethodName(Class clazz, Document metadata) {
+        if (metadata != null) {
+            String query = "/components/component[@name='" + clazz.getName() + "']";
+            Node node = queryNode(metadata, query);
+            if (node != null) {
+                return getAttributeValue(node, "deactivate");
+            }
+        }
+        return null;
+    }
+
+    private static NodeList queryNodes(Document metadata, String xpathQuery) {
+        try {
+            XPath xpath = XPATH_FACTORY.newXPath();
+            xpath.setNamespaceContext(NAMESPACE_CONTEXT);
+            return (NodeList) xpath.evaluate(xpathQuery, metadata, XPathConstants.NODESET);
+        } catch (XPathExpressionException ex) {
+            throw new RuntimeException("Error evaluating XPath: " + xpathQuery, ex);
+        }
+    }
+
+    private static Node queryNode(Document metadata, String xpathQuery) {
+        try {
+            XPath xpath = XPATH_FACTORY.newXPath();
+            xpath.setNamespaceContext(NAMESPACE_CONTEXT);
+            return (Node) xpath.evaluate(xpathQuery, metadata, XPathConstants.NODE);
+        } catch (XPathExpressionException ex) {
+            throw new RuntimeException("Error evaluating XPath: " + xpathQuery, ex);
+        }
+    }
+
+    private static String getAttributeValue(Node node, String attributeName) {
+        Node namedItem = node.getAttributes().getNamedItem(attributeName);
+        if (namedItem != null) {
+            return namedItem.getNodeValue();
+        } else {
+            return null;
+        }
+    }
+
+    public static class Reference {
+
+        private final String name;
+        private final String interfaceType;
+        private final ReferenceCardinality cardinality;
+        private final String bind;
+        private final String unbind;
+
+        public Reference(Node node) {
+            this.name = getAttributeValue(node, "name");
+            this.interfaceType = getAttributeValue(node, "interface");
+            this.cardinality = toCardinality(getAttributeValue(node, "cardinality"));
+            this.bind = getAttributeValue(node, "bind");
+            this.unbind = getAttributeValue(node, "unbind");
+        }
+
+        private ReferenceCardinality toCardinality(String value) {
+            for (ReferenceCardinality item : ReferenceCardinality.values()) {
+                if (StringUtils.equals(item.getCardinalityString(), value)) {
+                    return item;
+                }
+            }
+            return ReferenceCardinality.MANDATORY_UNARY;
+        }
+
+        public String getName() {
+            return this.name;
+        }
+
+        public String getInterfaceType() {
+            return this.interfaceType;
+        }
+
+        public ReferenceCardinality getCardinality() {
+            return this.cardinality;
+        }
+
+        public String getBind() {
+            return this.bind;
+        }
+
+        public String getUnbind() {
+            return this.unbind;
+        }
+
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java b/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
new file mode 100644
index 0000000..aa338a3
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
@@ -0,0 +1,301 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.osgi;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.Reference;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+
+/**
+ * Helper methods to inject dependencies and activate services via reflection.
+ */
+final class ReflectionServiceUtil {
+
+    private static final Logger log = LoggerFactory.getLogger(ReflectionServiceUtil.class);
+
+    private ReflectionServiceUtil() {
+        // static methods only
+    }
+
+    /**
+     * Simulate activation or deactivation of OSGi service instance.
+     * @param target Service instance.
+     * @param componentContext Component context
+     * @return true if activation method was called. False if such a method did
+     *         not exist.
+     */
+    public static boolean activateDeactivate(Object target, ComponentContext componentContext, boolean activate) {
+        Class<?> targetClass = target.getClass();
+
+        // get method name for activation/deactivation from osgi metadata
+        Document metadata = OsgiMetadataUtil.getMetadata(targetClass);
+        String methodName;
+        if (activate) {
+            methodName = OsgiMetadataUtil.getActivateMethodName(targetClass, metadata);
+        } else {
+            methodName = OsgiMetadataUtil.getDeactivateMethodName(targetClass, metadata);
+        }
+        if (StringUtils.isEmpty(methodName)) {
+            return false;
+        }
+
+        // if method is defined try to execute it
+        Method method = getMethod(targetClass, methodName, new Class<?>[] { ComponentContext.class }, activate);
+        if (method != null) {
+            try {
+                method.setAccessible(true);
+                method.invoke(target, componentContext);
+                return true;
+            } catch (IllegalAccessException ex) {
+                throw new RuntimeException("Unable to invoke activate/deactivate method for class "
+                        + targetClass.getName(), ex);
+            } catch (IllegalArgumentException ex) {
+                throw new RuntimeException("Unable to invoke activate/deactivate method for class "
+                        + targetClass.getName(), ex);
+            } catch (InvocationTargetException ex) {
+                throw new RuntimeException("Unable to invoke activate/deactivate method for class "
+                        + targetClass.getName(), ex);
+            }
+        }
+        log.warn("Method {}(ComponentContext) not found in class {}", methodName, targetClass.getName());
+        return false;
+    }
+
+    private static Method getMethod(Class clazz, String methodName, Class<?>[] signature, boolean activate) {
+        Method[] methods = clazz.getDeclaredMethods();
+        for (Method method : methods) {
+            if (StringUtils.equals(method.getName(), methodName)
+                    && Arrays.equals(method.getParameterTypes(), signature)) {
+                return method;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Simulate OSGi service dependency injection. Injects direct references and
+     * multiple references.
+     * @param target Service instance
+     * @param bundleContext Bundle context from which services are fetched to inject.
+     * @return true if all dependencies could be injected
+     */
+    public static boolean injectServices(Object target, BundleContext bundleContext) {
+
+        // collect all declared reference annotations on class and field level
+        Class<?> targetClass = target.getClass();
+        List<Reference> references = getReferences(targetClass);
+
+        // try to inject services
+        boolean allInjected = true;
+        for (Reference reference : references) {
+            allInjected = allInjected && injectServiceReference(reference, target, bundleContext);
+        }
+        return allInjected;
+    }
+
+    private static List<Reference> getReferences(Class clazz) {
+        Document metadata = OsgiMetadataUtil.getMetadata(clazz);
+        return OsgiMetadataUtil.getReferences(clazz, metadata);
+    }
+
+    private static boolean injectServiceReference(Reference reference, Object target, BundleContext bundleContext) {
+        Class<?> targetClass = target.getClass();
+
+        // get reference type
+        Class<?> type;
+        try {
+            type = Class.forName(reference.getInterfaceType());
+        } catch (ClassNotFoundException ex) {
+            throw new RuntimeException("Unable to instantiate reference type: " + reference.getInterfaceType(), ex);
+        }
+
+        // get matching service references
+        List<ServiceInfo> matchingServices = getMatchingServices(type, bundleContext);
+
+        // no references found? check if reference was optional
+        if (matchingServices.isEmpty()) {
+            boolean isOptional = (reference.getCardinality() == ReferenceCardinality.OPTIONAL_UNARY || reference
+                    .getCardinality() == ReferenceCardinality.OPTIONAL_MULTIPLE);
+            if (!isOptional) {
+                log.warn("Unable to inject mandatory reference '{}' for class {}", reference.getName(),
+                        targetClass.getName());
+            }
+            return isOptional;
+        }
+
+        // multiple references found? check if reference is not multiple
+        if (matchingServices.size() > 1
+                && (reference.getCardinality() == ReferenceCardinality.MANDATORY_UNARY || reference.getCardinality() == ReferenceCardinality.OPTIONAL_UNARY)) {
+            log.warn("Multiple matches found for unary reference '{}' for class {}", reference.getName(),
+                    targetClass.getName());
+            return false;
+        }
+
+        // try to invoke bind method
+        String bindMethodName = reference.getBind();
+        if (StringUtils.isNotEmpty(bindMethodName)) {
+            Method bindMethod = getFirstMethodWithNameAndSignature(targetClass, bindMethodName, new Class<?>[] { type });
+            if (bindMethod != null) {
+                bindMethod.setAccessible(true);
+                for (ServiceInfo matchingService : matchingServices) {
+                    try {
+                        bindMethod.invoke(target, matchingService.getServiceInstance());
+                    } catch (IllegalAccessException ex) {
+                        throw new RuntimeException("Unable to invoke method " + bindMethodName + " for class "
+                                + targetClass.getName(), ex);
+                    } catch (IllegalArgumentException ex) {
+                        throw new RuntimeException("Unable to invoke method " + bindMethodName + " for class "
+                                + targetClass.getName(), ex);
+                    } catch (InvocationTargetException ex) {
+                        throw new RuntimeException("Unable to invoke method " + bindMethodName + " for class "
+                                + targetClass.getName(), ex);
+                    }
+                }
+                return true;
+            } else {
+                Method bindMethodWithConfig = getFirstMethodWithNameAndSignature(targetClass, bindMethodName,
+                        new Class<?>[] { type, Map.class });
+                if (bindMethodWithConfig != null) {
+                    bindMethodWithConfig.setAccessible(true);
+                    for (ServiceInfo matchingService : matchingServices) {
+                        try {
+                            bindMethodWithConfig.invoke(target, matchingService.getServiceInstance(),
+                                    matchingService.getServiceConfig());
+                        } catch (IllegalAccessException ex) {
+                            throw new RuntimeException("Unable to invoke method " + bindMethodName + " for class "
+                                    + targetClass.getName(), ex);
+                        } catch (IllegalArgumentException ex) {
+                            throw new RuntimeException("Unable to invoke method " + bindMethodName + " for class "
+                                    + targetClass.getName(), ex);
+                        } catch (InvocationTargetException ex) {
+                            throw new RuntimeException("Unable to invoke method " + bindMethodName + " for class "
+                                    + targetClass.getName(), ex);
+                        }
+                    }
+                    return true;
+                } else {
+                    Method bindMethodServiceReference = getFirstMethodWithNameAndSignature(targetClass, bindMethodName,
+                            new Class<?>[] { ServiceReference.class });
+                    if (bindMethodServiceReference != null) {
+                        bindMethodServiceReference.setAccessible(true);
+                        for (ServiceInfo matchingService : matchingServices) {
+                            if (matchingService.getServiceReference() != null) {
+                                try {
+                                    bindMethodServiceReference.invoke(target, matchingService.getServiceReference());
+                                } catch (IllegalAccessException ex) {
+                                    throw new RuntimeException("Unable to invoke method " + bindMethodName
+                                            + " for class " + targetClass.getName(), ex);
+                                } catch (IllegalArgumentException ex) {
+                                    throw new RuntimeException("Unable to invoke method " + bindMethodName
+                                            + " for class " + targetClass.getName(), ex);
+                                } catch (InvocationTargetException ex) {
+                                    throw new RuntimeException("Unable to invoke method " + bindMethodName
+                                            + " for class " + targetClass.getName(), ex);
+                                }
+                            }
+                        }
+                        return true;
+                    }
+                }
+            }
+        }
+
+        log.warn("Bind method not found for reference '{}' for class {}", reference.getName(), targetClass.getName());
+        return false;
+    }
+
+    private static Method getFirstMethodWithNameAndSignature(Class<?> clazz, String methodName, Class<?>[] signature) {
+        Method[] methods = clazz.getDeclaredMethods();
+        for (Method method : methods) {
+            if (StringUtils.equals(method.getName(), methodName)
+                    && Arrays.equals(method.getParameterTypes(), signature)) {
+                return method;
+            }
+        }
+        // not found? check super classes
+        Class<?> superClass = clazz.getSuperclass();
+        if (superClass != null && superClass != Object.class) {
+            return getFirstMethodWithNameAndSignature(superClass, methodName, signature);
+        }
+        return null;
+    }
+
+    private static List<ServiceInfo> getMatchingServices(Class<?> type, BundleContext bundleContext) {
+        List<ServiceInfo> matchingServices = new ArrayList<ServiceInfo>();
+        try {
+            ServiceReference[] references = bundleContext.getServiceReferences(type.getName(), null);
+            if (references != null) {
+                for (ServiceReference serviceReference : references) {
+                    Object serviceInstance = bundleContext.getService(serviceReference);
+                    Map<String, Object> serviceConfig = new HashMap<String, Object>();
+                    String[] keys = serviceReference.getPropertyKeys();
+                    for (String key : keys) {
+                        serviceConfig.put(key, serviceReference.getProperty(key));
+                    }
+                    matchingServices.add(new ServiceInfo(serviceInstance, serviceConfig, serviceReference));
+                }
+            }
+        } catch (InvalidSyntaxException ex) {
+            // ignore
+        }
+        return matchingServices;
+    }
+
+    private static class ServiceInfo {
+
+        private final Object serviceInstance;
+        private final Map<String, Object> serviceConfig;
+        private final ServiceReference serviceReference;
+
+        public ServiceInfo(Object serviceInstance, Map<String, Object> serviceConfig, ServiceReference serviceReference) {
+            this.serviceInstance = serviceInstance;
+            this.serviceConfig = serviceConfig;
+            this.serviceReference = serviceReference;
+        }
+
+        public Object getServiceInstance() {
+            return this.serviceInstance;
+        }
+
+        public Map<String, Object> getServiceConfig() {
+            return this.serviceConfig;
+        }
+
+        public ServiceReference getServiceReference() {
+            return serviceReference;
+        }
+
+    }
+
+}
diff --git a/src/main/resources/simplelogger.properties b/src/main/resources/simplelogger.properties
new file mode 100644
index 0000000..1507469
--- /dev/null
+++ b/src/main/resources/simplelogger.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+org.slf4j.simpleLogger.defaultLogLevel=warn
diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md
new file mode 100644
index 0000000..acf7d98
--- /dev/null
+++ b/src/site/markdown/index.md
@@ -0,0 +1,35 @@
+## About OSGi Mocks
+
+Mock implementation of selected OSGi APIs.
+
+### Maven Dependency
+
+```xml
+<dependency>
+  <groupId>org.apache.sling</groupId>
+  <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
+  <version>1.0.0-SNAPHOT</version>
+</dependency>
+```
+
+### Documentation
+
+* [Usage](usage.html)
+* [API Documentation](apidocs/)
+* [Changelog](changes-report.html)
+
+### Implemented mock features
+
+The mock implementation supports:
+
+* Instantiating OSGi `Bundle`, `BundleContext` and `ComponentContext` objects and navigate between them.
+* Read and write properties on them.
+* Register OSGi services and get references to service instances
+* Service and bundle listener implementation
+* When adding services to BundleContext OSGi metadata from `/OSGI-INF/<pid>.xml` is read (e.g. for service ranking property)
+* Mock implementation of `LogService` which logs to SLF4J in JUnit context
+
+The following features are *not supported*:
+
+* Activation and deactivation methods of services are not called automatically (but helper methods exist)
+* Dependency injection does not take place automatically (but helper methods exist)
diff --git a/src/site/markdown/usage.md b/src/site/markdown/usage.md
new file mode 100644
index 0000000..c7e8bb8
--- /dev/null
+++ b/src/site/markdown/usage.md
@@ -0,0 +1,59 @@
+## Usage
+
+### Getting OSGi mock objects
+
+The factory class `MockOsgi` allows to instantiate the different mock implementations.
+
+Example:
+
+```java
+// get bundle context
+BundleContext bundleContext = MockOsgi.newBundleContext();
+
+// get component context
+Dictionary<String,Object> properties = new Hashtable<>();
+properties.put("prop1", "value1");
+BundleContext bundleContext = MockOsgi.newComponentContext(properties);
+```
+
+It is possible to simulate registering of OSGi services (backed by a simple hash map internally):
+
+```java
+// register service
+bundleContext.registerService(MyClass.class, myService, properties);
+
+// get service instance
+ServiceReference ref = bundleContext.getServiceReference(MyClass.class.getName());
+MyClass service = bundleContext.getService(ref);
+```
+
+### Activation and Dependency Injection
+
+It is possible to simulate OSGi service activation, deactivation and dependency injection and the mock implementation
+tries to to its best to execute all as expected for an OSGi environment.
+
+Example:
+
+```java
+// get bundle context
+BundleContext bundleContext = MockOsgi.newBundleContext();
+
+// create service instance manually
+MyService service = new MyService();
+
+// inject dependencies
+MockOsgi.injectServices(service, bundleContext);
+
+// activate service
+MockOsgi.activate(service, props);
+
+// operate with service...
+
+// deactivate service
+MockOsgi.deactivate(service);
+```
+
+Please note: The injectServices, activate and deactivate Methods can only work properly when the SCR XML metadata files
+are preset in the classpath at `/OSGI-INF`. They are generated automatically by the Maven SCR plugin, but might be
+missing if your clean and build the project within your IDE (e.g. Eclipse). In this case you have to compile the
+project again with maven and can run the tests - or use a Maven IDE Integration like m2eclipse.
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
new file mode 100644
index 0000000..6eef138
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextTest.java
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.osgi;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+@RunWith(MockitoJUnitRunner.class)
+public class MockBundleContextTest {
+
+    private BundleContext bundleContext;
+
+    @Before
+    public void setUp() {
+        this.bundleContext = MockOsgi.newBundleContext();
+    }
+
+    @Test
+    public void testBundle() {
+        assertNotNull(this.bundleContext.getBundle());
+    }
+
+    @Test
+    public void testServiceRegistration() throws InvalidSyntaxException {
+        // prepare test services
+        String clazz1 = String.class.getName();
+        Object service1 = new Object();
+        Dictionary properties1 = getServiceProperties(null);
+        ServiceRegistration reg1 = this.bundleContext.registerService(clazz1, service1, properties1);
+
+        String[] clazzes2 = new String[] { String.class.getName(), Integer.class.getName() };
+        Object service2 = new Object();
+        Dictionary properties2 = getServiceProperties(null);
+        ServiceRegistration reg2 = this.bundleContext.registerService(clazzes2, service2, properties2);
+
+        String clazz3 = Integer.class.getName();
+        Object service3 = new Object();
+        Dictionary properties3 = getServiceProperties(100L);
+        ServiceRegistration reg3 = this.bundleContext.registerService(clazz3, service3, properties3);
+
+        // test get service references
+        ServiceReference refString = this.bundleContext.getServiceReference(String.class.getName());
+        assertSame(reg1.getReference(), refString);
+
+        ServiceReference refInteger = this.bundleContext.getServiceReference(Integer.class.getName());
+        assertSame(reg3.getReference(), refInteger);
+
+        ServiceReference[] refsString = this.bundleContext.getServiceReferences(String.class.getName(), null);
+        assertEquals(2, refsString.length);
+        assertSame(reg1.getReference(), refsString[0]);
+        assertSame(reg2.getReference(), refsString[1]);
+
+        ServiceReference[] refsInteger = this.bundleContext.getServiceReferences(Integer.class.getName(), null);
+        assertEquals(2, refsInteger.length);
+        assertSame(reg3.getReference(), refsInteger[0]);
+        assertSame(reg2.getReference(), refsInteger[1]);
+
+        ServiceReference[] allRefsString = this.bundleContext.getAllServiceReferences(String.class.getName(), null);
+        assertArrayEquals(refsString, allRefsString);
+
+        // test get services
+        assertSame(service1, this.bundleContext.getService(refsString[0]));
+        assertSame(service2, this.bundleContext.getService(refsString[1]));
+        assertSame(service3, this.bundleContext.getService(refInteger));
+
+        // unget does nothing
+        this.bundleContext.ungetService(refsString[0]);
+        this.bundleContext.ungetService(refsString[1]);
+        this.bundleContext.ungetService(refInteger);
+    }
+
+    private Dictionary getServiceProperties(final Long serviceRanking) {
+        Dictionary<String, Object> props = new Hashtable<String, Object>();
+        if (serviceRanking != null) {
+            props.put(Constants.SERVICE_RANKING, serviceRanking);
+        }
+        return props;
+    }
+
+    @Test
+    public void testGetBundles() throws Exception {
+        assertEquals(0, this.bundleContext.getBundles().length);
+    }
+
+    @Test
+    public void testServiceListener() throws Exception {
+        ServiceListener serviceListener = mock(ServiceListener.class);
+        bundleContext.addServiceListener(serviceListener);
+
+        // prepare test services
+        String clazz1 = String.class.getName();
+        Object service1 = new Object();
+        this.bundleContext.registerService(clazz1, service1, null);
+
+        verify(serviceListener).serviceChanged(any(ServiceEvent.class));
+
+        bundleContext.removeServiceListener(serviceListener);
+    }
+
+    @Test
+    public void testBundleListener() throws Exception {
+        BundleListener bundleListener = mock(BundleListener.class);
+        BundleEvent bundleEvent = mock(BundleEvent.class);
+
+        bundleContext.addBundleListener(bundleListener);
+
+        MockOsgi.sendBundleEvent(bundleContext, bundleEvent);
+        verify(bundleListener).bundleChanged(bundleEvent);
+
+        bundleContext.removeBundleListener(bundleListener);
+    }
+
+    @Test
+    public void testFrameworkListener() throws Exception {
+        // ensure that listeners can be called (although they are not expected
+        // to to anything)
+        this.bundleContext.addFrameworkListener(null);
+        this.bundleContext.removeFrameworkListener(null);
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleTest.java
new file mode 100644
index 0000000..7402241
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleTest.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.osgi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+
+public class MockBundleTest {
+
+    private Bundle bundle;
+
+    @Before
+    public void setUp() {
+        this.bundle = MockOsgi.newBundleContext().getBundle();
+    }
+
+    @Test
+    public void testBundleId() {
+        assertTrue(this.bundle.getBundleId() > 0);
+    }
+
+    @Test
+    public void testBundleContxt() {
+        assertNotNull(this.bundle.getBundleContext());
+    }
+
+    @Test
+    public void testGetEntry() {
+        assertNotNull(this.bundle.getEntry("/META-INF/test.txt"));
+        assertNull(this.bundle.getEntry("/invalid"));
+    }
+
+    @Test
+    public void testGetStatie() {
+        assertEquals(Bundle.ACTIVE, bundle.getState());
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/MockComponentContextTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/MockComponentContextTest.java
new file mode 100644
index 0000000..18f7ba4
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/MockComponentContextTest.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.osgi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentContext;
+
+public class MockComponentContextTest {
+
+    private ComponentContext underTest;
+
+    @Before
+    public void setUp() {
+        underTest = MockOsgi.newComponentContext();
+    }
+
+    @Test
+    public void testBundleContext() {
+        assertNotNull(underTest.getBundleContext());
+    }
+
+    @Test
+    public void testInitialProperties() {
+        assertEquals(0, underTest.getProperties().size());
+    }
+
+    @Test
+    public void testProvidedProperties() {
+        Dictionary<String, Object> props = new Hashtable<String, Object>();
+        props.put("prop1", "value1");
+        props.put("prop2", 25);
+        ComponentContext componentContextWithProperties = MockOsgi.newComponentContext(props);
+
+        Dictionary contextProps = componentContextWithProperties.getProperties();
+        assertEquals(2, contextProps.size());
+        assertEquals("value1", contextProps.get("prop1"));
+        assertEquals(25, contextProps.get("prop2"));
+    }
+
+    @Test
+    public void testLocateService() {
+        // prepare test service
+        String clazz = String.class.getName();
+        Object service = new Object();
+        underTest.getBundleContext().registerService(clazz, service, null);
+        ServiceReference ref = underTest.getBundleContext().getServiceReference(clazz);
+
+        // test locate service
+        Object locatedService = underTest.locateService(null, ref);
+        assertSame(service, locatedService);
+    }
+
+    @Test
+    public void testIgnoredMethods() {
+        underTest.enableComponent("myComponent");
+        underTest.disableComponent("myComponent");
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/MockFilterTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/MockFilterTest.java
new file mode 100644
index 0000000..9c4a955
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/MockFilterTest.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.osgi;
+
+import static org.junit.Assert.assertFalse;
+
+import java.util.Hashtable;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+
+public class MockFilterTest {
+
+    private Filter filter;
+
+    @Before
+    public void setUp() {
+        this.filter = new MockFilter();
+    }
+
+    @Test
+    public void testDenyAll() {
+        assertFalse(this.filter.match((ServiceReference) null));
+        assertFalse(this.filter.match((Hashtable) null));
+        assertFalse(this.filter.matchCase(null));
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/MockLogServiceTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/MockLogServiceTest.java
new file mode 100644
index 0000000..7fbd7ab
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/MockLogServiceTest.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.osgi;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.service.log.LogService;
+
+public class MockLogServiceTest {
+
+    private LogService logService;
+
+    @Before
+    public void setUp() throws Exception {
+        this.logService = new MockLogService(getClass());
+    }
+
+    @Test
+    public void testLog() {
+        this.logService.log(LogService.LOG_ERROR, "message 1");
+        this.logService.log(LogService.LOG_WARNING, "message 1");
+        this.logService.log(LogService.LOG_INFO, "message 1");
+        this.logService.log(LogService.LOG_DEBUG, "message 1");
+
+        this.logService.log(null, LogService.LOG_ERROR, "message 1");
+        this.logService.log(null, LogService.LOG_WARNING, "message 1");
+        this.logService.log(null, LogService.LOG_INFO, "message 1");
+        this.logService.log(null, LogService.LOG_DEBUG, "message 1");
+    }
+
+    @Test
+    public void testLogException() {
+        this.logService.log(LogService.LOG_ERROR, "message 2", new Exception());
+        this.logService.log(LogService.LOG_WARNING, "message 2", new Exception());
+        this.logService.log(LogService.LOG_INFO, "message 2", new Exception());
+        this.logService.log(LogService.LOG_DEBUG, "message 2", new Exception());
+
+        this.logService.log(null, LogService.LOG_ERROR, "message 2", new Exception());
+        this.logService.log(null, LogService.LOG_WARNING, "message 2", new Exception());
+        this.logService.log(null, LogService.LOG_INFO, "message 2", new Exception());
+        this.logService.log(null, LogService.LOG_DEBUG, "message 2", new Exception());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testLogInvalidLevel() {
+        this.logService.log(0, "message 1");
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testLogExceptionInvalidLevel() {
+        this.logService.log(0, "message 2", new Exception());
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/MockServiceReferenceTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/MockServiceReferenceTest.java
new file mode 100644
index 0000000..c525575
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/MockServiceReferenceTest.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.osgi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.sling.testing.mock.osgi.OsgiMetadataUtilTest.ServiceWithMetadata;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+public class MockServiceReferenceTest {
+
+    private BundleContext bundleContext;
+    private ServiceReference serviceReference;
+    private Object service;
+
+    @Before
+    public void setUp() {
+        this.bundleContext = MockOsgi.newBundleContext();
+
+        this.service = new Object();
+        String clazz = String.class.getName();
+        Dictionary<String, Object> props = new Hashtable<String, Object>();
+        props.put("customProp1", "value1");
+
+        this.bundleContext.registerService(clazz, this.service, props);
+        this.serviceReference = this.bundleContext.getServiceReference(clazz);
+    }
+
+    @Test
+    public void testBundle() {
+        assertSame(this.bundleContext.getBundle(), this.serviceReference.getBundle());
+    }
+
+    @Test
+    public void testServiceId() {
+        assertNotNull(this.serviceReference.getProperty(Constants.SERVICE_ID));
+    }
+
+    @Test
+    public void testProperties() {
+        assertEquals(2, this.serviceReference.getPropertyKeys().length);
+        assertEquals("value1", this.serviceReference.getProperty("customProp1"));
+    }
+
+    @Test
+    public void testWithOsgiMetadata() {
+        ServiceWithMetadata serviceWithMetadata = new OsgiMetadataUtilTest.ServiceWithMetadata();
+        bundleContext.registerService((String) null, serviceWithMetadata, null);
+        ServiceReference reference = this.bundleContext.getServiceReference(Comparable.class.getName());
+
+        assertEquals(5000, reference.getProperty("service.ranking"));
+        assertEquals("The Apache Software Foundation", reference.getProperty("service.vendor"));
+        assertEquals("org.apache.sling.models.impl.injectors.OSGiServiceInjector", reference.getProperty("service.pid"));
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtilTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtilTest.java
new file mode 100644
index 0000000..52f9011
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtilTest.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.osgi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.Reference;
+import org.junit.Test;
+import org.w3c.dom.Document;
+
+public class OsgiMetadataUtilTest {
+
+    @Test
+    public void testMetadata() {
+        Document doc = OsgiMetadataUtil.getMetadata(ServiceWithMetadata.class);
+
+        Set<String> serviceInterfaces = OsgiMetadataUtil.getServiceInterfaces(ServiceWithMetadata.class, doc);
+        assertEquals(3, serviceInterfaces.size());
+        assertTrue(serviceInterfaces.contains("org.apache.sling.models.spi.Injector"));
+        assertTrue(serviceInterfaces
+                .contains("org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessorFactory"));
+        assertTrue(serviceInterfaces.contains("java.lang.Comparable"));
+
+        Map<String, Object> props = OsgiMetadataUtil.getProperties(ServiceWithMetadata.class, doc);
+        assertEquals(3, props.size());
+        assertEquals(5000, props.get("service.ranking"));
+        assertEquals("The Apache Software Foundation", props.get("service.vendor"));
+        assertEquals("org.apache.sling.models.impl.injectors.OSGiServiceInjector", props.get("service.pid"));
+    }
+
+    @Test
+    public void testNoMetadata() {
+        Document doc = OsgiMetadataUtil.getMetadata(ServiceWithoutMetadata.class);
+
+        Set<String> serviceInterfaces = OsgiMetadataUtil.getServiceInterfaces(ServiceWithoutMetadata.class, doc);
+        assertEquals(0, serviceInterfaces.size());
+
+        Map<String, Object> props = OsgiMetadataUtil.getProperties(ServiceWithoutMetadata.class, doc);
+        assertEquals(0, props.size());
+    }
+
+    @Test
+    public void testReferences() {
+        Document doc = OsgiMetadataUtil.getMetadata(ReflectionServiceUtilTest.Service3.class);
+        List<Reference> references = OsgiMetadataUtil.getReferences(ReflectionServiceUtilTest.Service3.class, doc);
+        assertEquals(3, references.size());
+
+        Reference ref1 = references.get(0);
+        assertEquals("reference2", ref1.getName());
+        assertEquals("org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$ServiceInterface2", ref1.getInterfaceType());
+        assertEquals(ReferenceCardinality.MANDATORY_MULTIPLE, ref1.getCardinality());
+        assertEquals("bindReference2", ref1.getBind());
+        assertEquals("unbindReference2", ref1.getUnbind());
+    }
+
+    @Test
+    public void testActivateMethodName() {
+        Document doc = OsgiMetadataUtil.getMetadata(ReflectionServiceUtilTest.Service3.class);
+        String methodName = OsgiMetadataUtil.getActivateMethodName(ReflectionServiceUtilTest.Service3.class, doc);
+        assertEquals("activate", methodName);
+    }
+
+    static class ServiceWithMetadata {
+        // empty class
+    }
+
+    static class ServiceWithoutMetadata {
+        // empty class
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtilTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtilTest.java
new file mode 100644
index 0000000..ff29037
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtilTest.java
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.osgi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.References;
+import org.apache.felix.scr.annotations.Service;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentContext;
+
+public class ReflectionServiceUtilTest {
+
+    private BundleContext bundleContext = MockOsgi.newBundleContext();
+    private Service1 service1;
+    private Service2 service2;
+
+    @Before
+    public void setUp() {
+        service1 = new Service1();
+        service2 = new Service2();
+        bundleContext.registerService(ServiceInterface1.class.getName(), service1, null);
+        bundleContext.registerService(ServiceInterface2.class.getName(), service2, null);
+    }
+
+    @Test
+    public void testService3() {
+        Service3 service3 = new Service3();
+        assertTrue(MockOsgi.injectServices(service3, bundleContext));
+
+        Dictionary<String, Object> service3Config = new Hashtable<String, Object>();
+        service3Config.put("prop1", "value1");
+        assertTrue(MockOsgi.activate(service3, bundleContext, service3Config));
+
+        assertNotNull(service3.getComponentContext());
+        assertEquals(service3Config, service3.getComponentContext().getProperties());
+
+        assertSame(service1, service3.getReference1());
+
+        List<ServiceInterface2> references2 = service3.getReferences2();
+        assertEquals(1, references2.size());
+        assertSame(service2, references2.get(0));
+
+        List<ServiceInterface3> references3 = service3.getReferences3();
+        assertEquals(1, references3.size());
+        assertSame(service2, references3.get(0));
+
+        List<Map<String, Object>> reference3Configs = service3.getReference3Configs();
+        assertEquals(1, reference3Configs.size());
+        assertEquals(200, reference3Configs.get(0).get(Constants.SERVICE_RANKING));
+
+        assertTrue(MockOsgi.deactivate(service3));
+        assertNull(service3.getComponentContext());
+    }
+
+    @Test
+    public void testService4() {
+        Service4 service4 = new Service4();
+
+        assertTrue(MockOsgi.injectServices(service4, bundleContext));
+        assertFalse(MockOsgi.activate(service4));
+
+        assertSame(service1, service4.getReference1());
+    }
+
+    public interface ServiceInterface1 {
+        // no methods
+    }
+
+    public interface ServiceInterface2 {
+        // no methods
+    }
+
+    public interface ServiceInterface3 {
+        // no methods
+    }
+
+    @Component
+    @Service(ServiceInterface1.class)
+    @Property(name = Constants.SERVICE_RANKING, intValue = 100)
+    public static class Service1 implements ServiceInterface1 {
+        // dummy interface
+    }
+
+    @Component
+    @Service({ ServiceInterface2.class, ServiceInterface3.class })
+    @Property(name = Constants.SERVICE_RANKING, intValue = 200)
+    public static class Service2 implements ServiceInterface2, ServiceInterface3 {
+        // dummy interface
+    }
+
+    @Component
+    @References({ @Reference(name = "reference2", referenceInterface = ServiceInterface2.class, cardinality = ReferenceCardinality.MANDATORY_MULTIPLE) })
+    public static class Service3 {
+
+        @Reference
+        private ServiceInterface1 reference1;
+
+        private List<ServiceReference> references2 = new ArrayList<ServiceReference>();
+
+        @Reference(name = "reference3", referenceInterface = ServiceInterface3.class, cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE)
+        private List<ServiceInterface3> references3 = new ArrayList<ServiceInterface3>();
+        private List<Map<String, Object>> reference3Configs = new ArrayList<Map<String, Object>>();
+
+        private ComponentContext componentContext;
+
+        @Activate
+        private void activate(ComponentContext ctx) {
+            this.componentContext = ctx;
+        }
+
+        @Deactivate
+        private void deactivate(ComponentContext ctx) {
+            this.componentContext = null;
+        }
+
+        public ServiceInterface1 getReference1() {
+            return this.reference1;
+        }
+
+        public List<ServiceInterface2> getReferences2() {
+            List<ServiceInterface2> services = new ArrayList<ServiceInterface2>();
+            for (ServiceReference serviceReference : references2) {
+                services.add((ServiceInterface2)componentContext.getBundleContext().getService(serviceReference));
+            }
+            return services;
+        }
+
+        public List<ServiceInterface3> getReferences3() {
+            return this.references3;
+        }
+
+        public List<Map<String, Object>> getReference3Configs() {
+            return this.reference3Configs;
+        }
+
+        public ComponentContext getComponentContext() {
+            return this.componentContext;
+        }
+
+        protected void bindReference1(ServiceInterface1 service) {
+            reference1 = service;
+        }
+
+        protected void unbindReference1(ServiceInterface1 service) {
+            reference1 = null;
+        }
+
+        protected void bindReference2(ServiceReference serviceReference) {
+            references2.add(serviceReference);
+        }
+
+        protected void unbindReference2(ServiceReference serviceReference) {
+            references2.remove(serviceReference);
+        }
+
+        protected void bindReference3(ServiceInterface3 service, Map<String, Object> serviceConfig) {
+            references3.add(service);
+            reference3Configs.add(serviceConfig);
+        }
+
+        protected void unbindReference3(ServiceInterface3 service, Map<String, Object> serviceConfig) {
+            references3.remove(service);
+            reference3Configs.remove(serviceConfig);
+        }
+
+    }
+
+    @Component
+    @Reference(referenceInterface = ServiceInterface1.class, name = "customName", bind = "customBind", unbind = "customUnbind")
+    public static class Service4 {
+
+        private ServiceInterface1 reference1;
+
+        public ServiceInterface1 getReference1() {
+            return this.reference1;
+        }
+
+        protected void customBind(ServiceInterface1 service) {
+            reference1 = service;
+        }
+
+        protected void customUnbind(ServiceInterface1 service) {
+            reference1 = null;
+        }
+
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/package-info.java b/src/test/java/org/apache/sling/testing/mock/osgi/package-info.java
new file mode 100644
index 0000000..9c9ff28
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/**
+ * Mock implementation of selected OSGi APIs.
+ */
+package org.apache.sling.testing.mock.osgi;
+
diff --git a/src/test/resources/META-INF/test.txt b/src/test/resources/META-INF/test.txt
new file mode 100644
index 0000000..af27ff4
--- /dev/null
+++ b/src/test/resources/META-INF/test.txt
@@ -0,0 +1 @@
+This is a test file.
\ No newline at end of file
diff --git a/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.OsgiMetadataUtilTest.xml b/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.OsgiMetadataUtilTest.xml
new file mode 100644
index 0000000..95ac503
--- /dev/null
+++ b/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.OsgiMetadataUtilTest.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<components xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0">
+  <scr:component name="org.apache.sling.testing.mock.osgi.OsgiMetadataUtilTest$ServiceWithMetadata" activate="activate">
+    <implementation class="org.apache.sling.testing.mock.osgi.OsgiMetadataUtilTest$ServiceWithMetadata"/>
+    <service servicefactory="false">
+      <provide interface="org.apache.sling.models.spi.Injector"/>
+      <provide interface="org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessorFactory"/>
+      <provide interface="java.lang.Comparable"/>
+    </service>
+    <property name="service.ranking" type="Integer" value="5000"/>
+    <property name="service.vendor" value="The Apache Software Foundation"/>
+    <property name="service.pid" value="org.apache.sling.models.impl.injectors.OSGiServiceInjector"/>
+  </scr:component>
+</components>
diff --git a/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest.xml b/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest.xml
new file mode 100644
index 0000000..923b90f
--- /dev/null
+++ b/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<components xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0">
+  <scr:component name="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service1">
+    <implementation class="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service1"/>
+    <service servicefactory="false">
+      <provide interface="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$ServiceInterface1"/>
+    </service>
+    <property name="service.ranking" type="Integer" value="100"/>
+    <property name="service.pid" value="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service1"/>
+  </scr:component>
+  <scr:component name="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service2">
+    <implementation class="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service2"/>
+    <service servicefactory="false">
+      <provide interface="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$ServiceInterface2"/>
+      <provide interface="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$ServiceInterface3"/>
+    </service>
+    <property name="service.ranking" type="Integer" value="200"/>
+    <property name="service.pid" value="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service2"/>
+  </scr:component>
+  <scr:component name="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service3" activate="activate" deactivate="deactivate">
+    <implementation class="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service3"/>
+    <property name="service.pid" value="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service3"/>
+    <reference name="reference2" interface="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$ServiceInterface2" cardinality="1..n" policy="static" bind="bindReference2" unbind="unbindReference2"/>
+    <reference name="reference1" interface="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$ServiceInterface1" cardinality="1..1" policy="static" bind="bindReference1" unbind="unbindReference1"/>
+    <reference name="reference3" interface="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$ServiceInterface3" cardinality="0..n" policy="static" bind="bindReference3" unbind="unbindReference3"/>
+  </scr:component>
+  <scr:component name="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service4">
+    <implementation class="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service4"/>
+    <property name="service.pid" value="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$Service4"/>
+    <reference name="customName" interface="org.apache.sling.testing.mock.osgi.ReflectionServiceUtilTest$ServiceInterface1" cardinality="1..1" policy="static" bind="customBind" unbind="customUnbind"/>
+  </scr:component>
+</components>
diff --git a/src/test/resources/simplelogger.properties b/src/test/resources/simplelogger.properties
new file mode 100644
index 0000000..1299698
--- /dev/null
+++ b/src/test/resources/simplelogger.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+org.slf4j.simpleLogger.defaultLogLevel=error

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 05/09: SLING-4042 make sure dependency injection is continued even if not all injections succeeded, and report root cause of invocation target exceptions

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit 3af04103a9f6b0be701a64018f9ace937d56f7ca
Author: sseifert <ss...@unknown>
AuthorDate: Thu Oct 16 16:10:16 2014 +0000

    SLING-4042 make sure dependency injection is continued even if not all injections succeeded, and report root cause of invocation target exceptions
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1632374 13f79535-47bb-0310-9956-ffa450edef68
---
 .../apache/sling/testing/mock/osgi/ReflectionServiceUtil.java | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java b/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
index aa338a3..fe363ab 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/ReflectionServiceUtil.java
@@ -85,7 +85,7 @@ final class ReflectionServiceUtil {
                         + targetClass.getName(), ex);
             } catch (InvocationTargetException ex) {
                 throw new RuntimeException("Unable to invoke activate/deactivate method for class "
-                        + targetClass.getName(), ex);
+                        + targetClass.getName(), ex.getCause());
             }
         }
         log.warn("Method {}(ComponentContext) not found in class {}", methodName, targetClass.getName());
@@ -119,7 +119,8 @@ final class ReflectionServiceUtil {
         // try to inject services
         boolean allInjected = true;
         for (Reference reference : references) {
-            allInjected = allInjected && injectServiceReference(reference, target, bundleContext);
+            boolean injectSuccess = injectServiceReference(reference, target, bundleContext);
+            allInjected = allInjected && injectSuccess;
         }
         return allInjected;
     }
@@ -179,7 +180,7 @@ final class ReflectionServiceUtil {
                                 + targetClass.getName(), ex);
                     } catch (InvocationTargetException ex) {
                         throw new RuntimeException("Unable to invoke method " + bindMethodName + " for class "
-                                + targetClass.getName(), ex);
+                                + targetClass.getName(), ex.getCause());
                     }
                 }
                 return true;
@@ -200,7 +201,7 @@ final class ReflectionServiceUtil {
                                     + targetClass.getName(), ex);
                         } catch (InvocationTargetException ex) {
                             throw new RuntimeException("Unable to invoke method " + bindMethodName + " for class "
-                                    + targetClass.getName(), ex);
+                                    + targetClass.getName(), ex.getCause());
                         }
                     }
                     return true;
@@ -221,7 +222,7 @@ final class ReflectionServiceUtil {
                                             + " for class " + targetClass.getName(), ex);
                                 } catch (InvocationTargetException ex) {
                                     throw new RuntimeException("Unable to invoke method " + bindMethodName
-                                            + " for class " + targetClass.getName(), ex);
+                                            + " for class " + targetClass.getName(), ex.getCause());
                                 }
                             }
                         }

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 09/09: [maven-release-plugin] copy for tag org.apache.sling.testing.osgi-mock-1.0.0

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit 182cbff4718c9641b08943b99166b9b8d5885b7f
Author: sseifert <ss...@unknown>
AuthorDate: Fri Oct 17 08:17:40 2014 +0000

    [maven-release-plugin]  copy for tag org.apache.sling.testing.osgi-mock-1.0.0
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.testing.osgi-mock-1.0.0@1632498 13f79535-47bb-0310-9956-ffa450edef68

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 07/09: add/update SCM urls

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit 5bc29ad78f0593a50de264b6733ab523ac7105d2
Author: sseifert <ss...@unknown>
AuthorDate: Fri Oct 17 08:10:43 2014 +0000

    add/update SCM urls
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1632490 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/pom.xml b/pom.xml
index b4060c4..4083ee6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -38,6 +38,12 @@
         <sling.java.version>6</sling.java.version>
     </properties>
 
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/trunk/testing/mocks/osgi-mock</url>
+    </scm>
+
     <dependencies>
   
         <dependency>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 03/09: SLING-4042 move all mock projects to mocks/ subdirectory

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit 2e65a195d8d4c6bf9c0bc93e406ffab0c0d17d03
Author: sseifert <ss...@unknown>
AuthorDate: Mon Oct 13 14:32:45 2014 +0000

    SLING-4042 move all mock projects to mocks/ subdirectory
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1631416 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml                    |  2 +-
 src/site/markdown/index.md | 35 ---------------------------
 src/site/markdown/usage.md | 59 ----------------------------------------------
 3 files changed, 1 insertion(+), 95 deletions(-)

diff --git a/pom.xml b/pom.xml
index 708d885..b4060c4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,7 +24,7 @@
         <groupId>org.apache.sling</groupId>
         <artifactId>sling</artifactId>
         <version>22</version>
-        <relativePath>../../parent/pom.xml</relativePath>
+        <relativePath>../../../parent/pom.xml</relativePath>
     </parent>
 
     <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md
deleted file mode 100644
index acf7d98..0000000
--- a/src/site/markdown/index.md
+++ /dev/null
@@ -1,35 +0,0 @@
-## About OSGi Mocks
-
-Mock implementation of selected OSGi APIs.
-
-### Maven Dependency
-
-```xml
-<dependency>
-  <groupId>org.apache.sling</groupId>
-  <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
-  <version>1.0.0-SNAPHOT</version>
-</dependency>
-```
-
-### Documentation
-
-* [Usage](usage.html)
-* [API Documentation](apidocs/)
-* [Changelog](changes-report.html)
-
-### Implemented mock features
-
-The mock implementation supports:
-
-* Instantiating OSGi `Bundle`, `BundleContext` and `ComponentContext` objects and navigate between them.
-* Read and write properties on them.
-* Register OSGi services and get references to service instances
-* Service and bundle listener implementation
-* When adding services to BundleContext OSGi metadata from `/OSGI-INF/<pid>.xml` is read (e.g. for service ranking property)
-* Mock implementation of `LogService` which logs to SLF4J in JUnit context
-
-The following features are *not supported*:
-
-* Activation and deactivation methods of services are not called automatically (but helper methods exist)
-* Dependency injection does not take place automatically (but helper methods exist)
diff --git a/src/site/markdown/usage.md b/src/site/markdown/usage.md
deleted file mode 100644
index c7e8bb8..0000000
--- a/src/site/markdown/usage.md
+++ /dev/null
@@ -1,59 +0,0 @@
-## Usage
-
-### Getting OSGi mock objects
-
-The factory class `MockOsgi` allows to instantiate the different mock implementations.
-
-Example:
-
-```java
-// get bundle context
-BundleContext bundleContext = MockOsgi.newBundleContext();
-
-// get component context
-Dictionary<String,Object> properties = new Hashtable<>();
-properties.put("prop1", "value1");
-BundleContext bundleContext = MockOsgi.newComponentContext(properties);
-```
-
-It is possible to simulate registering of OSGi services (backed by a simple hash map internally):
-
-```java
-// register service
-bundleContext.registerService(MyClass.class, myService, properties);
-
-// get service instance
-ServiceReference ref = bundleContext.getServiceReference(MyClass.class.getName());
-MyClass service = bundleContext.getService(ref);
-```
-
-### Activation and Dependency Injection
-
-It is possible to simulate OSGi service activation, deactivation and dependency injection and the mock implementation
-tries to to its best to execute all as expected for an OSGi environment.
-
-Example:
-
-```java
-// get bundle context
-BundleContext bundleContext = MockOsgi.newBundleContext();
-
-// create service instance manually
-MyService service = new MyService();
-
-// inject dependencies
-MockOsgi.injectServices(service, bundleContext);
-
-// activate service
-MockOsgi.activate(service, props);
-
-// operate with service...
-
-// deactivate service
-MockOsgi.deactivate(service);
-```
-
-Please note: The injectServices, activate and deactivate Methods can only work properly when the SCR XML metadata files
-are preset in the classpath at `/OSGI-INF`. They are generated automatically by the Maven SCR plugin, but might be
-missing if your clean and build the project within your IDE (e.g. Eclipse). In this case you have to compile the
-project again with maven and can run the tests - or use a Maven IDE Integration like m2eclipse.

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 04/09: SLING-4042 add missing package-info files

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit d7c4834484d9eaa740bc80f4e4b30d4222a0723d
Author: sseifert <ss...@unknown>
AuthorDate: Mon Oct 13 15:27:41 2014 +0000

    SLING-4042 add missing package-info files
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1631438 13f79535-47bb-0310-9956-ffa450edef68
---
 .../java/org/apache/sling/testing/mock/osgi/package-info.java            | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/package-info.java b/src/main/java/org/apache/sling/testing/mock/osgi/package-info.java
similarity index 99%
rename from src/test/java/org/apache/sling/testing/mock/osgi/package-info.java
rename to src/main/java/org/apache/sling/testing/mock/osgi/package-info.java
index 9c9ff28..4cf91fe 100644
--- a/src/test/java/org/apache/sling/testing/mock/osgi/package-info.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/package-info.java
@@ -20,4 +20,3 @@
  * Mock implementation of selected OSGi APIs.
  */
 package org.apache.sling.testing.mock.osgi;
-

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 06/09: SLING-4042 add README files

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit 48a1b958526dc09c7080d2e49bf795f9497ce2a4
Author: sseifert <ss...@unknown>
AuthorDate: Thu Oct 16 19:09:39 2014 +0000

    SLING-4042 add README files
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1632415 13f79535-47bb-0310-9956-ffa450edef68
---
 README.txt | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..5382c4f
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,6 @@
+Apache Sling Testing OSGi Mock
+
+Mock implementation of selected OSGi APIs.
+
+Documentation:
+http://sling.apache.org/documentation/development/osgi-mock.html

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 02/09: svn:ignore

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit 3dc3e50185f48e28241a216412c54af7c31141c6
Author: Bertrand Delacretaz <bd...@apache.org>
AuthorDate: Mon Oct 13 13:23:53 2014 +0000

    svn:ignore
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/osgi-mock@1631387 13f79535-47bb-0310-9956-ffa450edef68

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-testing-osgi-mock] 08/09: [maven-release-plugin] prepare release org.apache.sling.testing.osgi-mock-1.0.0

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit d2636f19c5b3ba22f82ace4445abe8d726c74f48
Author: sseifert <ss...@unknown>
AuthorDate: Fri Oct 17 08:17:37 2014 +0000

    [maven-release-plugin] prepare release org.apache.sling.testing.osgi-mock-1.0.0
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1632497 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/pom.xml b/pom.xml
index 4083ee6..d50758c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,7 +28,7 @@
     </parent>
 
     <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
-    <version>1.0.0-SNAPSHOT</version>
+    <version>1.0.0</version>
     <packaging>bundle</packaging>
 
     <name>Apache Sling Testing OSGi Mock</name>
@@ -39,9 +39,9 @@
     </properties>
 
     <scm>
-        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock</connection>
-        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock</developerConnection>
-        <url>http://svn.apache.org/viewvc/sling/trunk/testing/mocks/osgi-mock</url>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/tags/org.apache.sling.testing.osgi-mock-1.0.0</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.testing.osgi-mock-1.0.0</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/tags/org.apache.sling.testing.osgi-mock-1.0.0</url>
     </scm>
 
     <dependencies>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.