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.2.0 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git
commit dc9866e557685680ee107ead6b7cb8b5665247e8 Author: Stefan Seifert <[email protected]> AuthorDate: Thu Feb 19 15:28:14 2015 +0000 SLING-4439 add support for unregistering services and prepare dynamic service reference handling git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1660911 13f79535-47bb-0310-9956-ffa450edef68 --- .../sling/testing/mock/osgi/MockBundleContext.java | 32 ++++++++++-- .../testing/mock/osgi/MockServiceRegistration.java | 34 +++++++++++-- .../sling/testing/mock/osgi/OsgiMetadataUtil.java | 19 ++++++-- .../sling/testing/mock/osgi/OsgiServiceUtil.java | 6 +-- .../mock/osgi/ReferenceViolationException.java | 31 ++++++++++++ .../testing/mock/osgi/MockBundleContextTest.java | 57 ++++++++++++++-------- 6 files changed, 146 insertions(+), 33 deletions(-) diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockBundleContext.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockBundleContext.java index cbaa13d..37e6fd6 100644 --- a/src/main/java/org/apache/sling/testing/mock/osgi/MockBundleContext.java +++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockBundleContext.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.Dictionary; import java.util.List; import java.util.Set; +import java.util.SortedSet; import java.util.TreeSet; import org.apache.commons.lang3.StringUtils; @@ -44,7 +45,7 @@ import org.osgi.framework.ServiceRegistration; class MockBundleContext implements BundleContext { private final MockBundle bundle; - private final List<MockServiceRegistration> registeredServices = new ArrayList<MockServiceRegistration>(); + private final SortedSet<MockServiceRegistration> registeredServices = new TreeSet<MockServiceRegistration>(); private final List<ServiceListener> serviceListeners = new ArrayList<ServiceListener>(); private final List<BundleListener> bundleListeners = new ArrayList<BundleListener>(); @@ -77,12 +78,37 @@ class MockBundleContext implements BundleContext { @SuppressWarnings("unchecked") @Override public ServiceRegistration registerService(final String[] clazzes, final Object service, final Dictionary properties) { - MockServiceRegistration registration = new MockServiceRegistration(this.bundle, clazzes, service, properties); + MockServiceRegistration registration = new MockServiceRegistration(this.bundle, clazzes, service, properties, this); + handleRefsUpdateOnRegister(registration); this.registeredServices.add(registration); notifyServiceListeners(ServiceEvent.REGISTERED, registration.getReference()); return registration; } - + + /** + * Check for already registered services that may be affected by the service registration - either + * adding by additional optional references, or creating a conflict in the dependencies. + * @param registration + */ + private void handleRefsUpdateOnRegister(MockServiceRegistration registration) { + // TODO: implement handling + } + + void unregisterService(MockServiceRegistration registration) { + this.registeredServices.remove(registration); + handleRefsUpdateOnUnregister(registration); + notifyServiceListeners(ServiceEvent.UNREGISTERING, registration.getReference()); + } + + /** + * Check for already registered services that may be affected by the service unregistration - either + * adding by removing optional references, or creating a conflict in the dependencies. + * @param registration + */ + private void handleRefsUpdateOnUnregister(MockServiceRegistration registration) { + // TODO: implement handling + } + @Override public ServiceReference getServiceReference(final String clazz) { ServiceReference[] serviceRefs = getServiceReferences(clazz, null); diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceRegistration.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceRegistration.java index f212b49..c9c13dd 100644 --- a/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceRegistration.java +++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceRegistration.java @@ -35,22 +35,26 @@ import com.google.common.collect.ImmutableList; /** * Mock {@link ServiceRegistration} implementation. */ -class MockServiceRegistration implements ServiceRegistration { +class MockServiceRegistration implements ServiceRegistration, Comparable<MockServiceRegistration> { private static volatile long serviceCounter; + private final Long serviceId; private final Set<String> clazzes; private final Object service; private Dictionary<String, Object> properties; private final ServiceReference serviceReference; + private final MockBundleContext bundleContext; public MockServiceRegistration(final Bundle bundle, final String[] clazzes, final Object service, - final Dictionary<String, Object> properties) { + final Dictionary<String, Object> properties, MockBundleContext bundleContext) { + this.serviceId = ++serviceCounter; this.clazzes = new HashSet<String>(ImmutableList.copyOf(clazzes)); this.service = service; this.properties = properties != null ? properties : new Hashtable<String,Object>(); - this.properties.put(Constants.SERVICE_ID, ++serviceCounter); + this.properties.put(Constants.SERVICE_ID, this.serviceId); this.serviceReference = new MockServiceReference(bundle, this); + this.bundleContext = bundleContext; readOsgiMetadata(); } @@ -67,7 +71,7 @@ class MockServiceRegistration implements ServiceRegistration { @Override public void unregister() { - // do nothing for now + bundleContext.unregisterService(this); } Dictionary<String, Object> getProperties() { @@ -78,10 +82,32 @@ class MockServiceRegistration implements ServiceRegistration { // ignore filter for now return this.clazzes.contains(clazz); } + + Set<String> getClasses() { + return clazzes; + } Object getService() { return this.service; } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof MockServiceRegistration)) { + return false; + } + return serviceId.equals(((MockServiceRegistration)obj).serviceId); + } + + @Override + public int hashCode() { + return serviceId.hashCode(); + } + + @Override + public int compareTo(MockServiceRegistration obj) { + return serviceId.compareTo(obj.serviceId); + } /** * Try to read OSGI-metadata from /OSGI-INF and read all implemented 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 index 7cf7cfb..b64cd39 100644 --- a/src/main/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtil.java +++ b/src/main/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtil.java @@ -207,7 +207,7 @@ final class OsgiMetadataUtil { if (nodes != null) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); - references.add(new Reference(node)); + references.add(new Reference(clazz, node)); } } return references; @@ -253,6 +253,7 @@ final class OsgiMetadataUtil { static class OsgiMetadata { + private final Class<?> clazz; private final Set<String> serviceInterfaces; private final Map<String, Object> properties; private final List<Reference> references; @@ -260,7 +261,8 @@ final class OsgiMetadataUtil { private final String deactivateMethodName; private final String modifiedMethodName; - private OsgiMetadata(Class clazz, Document metadataDocument) { + private OsgiMetadata(Class<?> clazz, Document metadataDocument) { + this.clazz = clazz; this.serviceInterfaces = OsgiMetadataUtil.getServiceInterfaces(clazz, metadataDocument); this.properties = OsgiMetadataUtil.getProperties(clazz, metadataDocument); this.references = OsgiMetadataUtil.getReferences(clazz, metadataDocument); @@ -270,6 +272,7 @@ final class OsgiMetadataUtil { } private OsgiMetadata() { + this.clazz = null; this.serviceInterfaces = null; this.properties = null; this.references = null; @@ -278,6 +281,10 @@ final class OsgiMetadataUtil { this.modifiedMethodName = null; } + public Class<?> getServiceClass() { + return clazz; + } + public Set<String> getServiceInterfaces() { return serviceInterfaces; } @@ -306,13 +313,15 @@ final class OsgiMetadataUtil { static class Reference { + private final Class<?> clazz; private final String name; private final String interfaceType; private final ReferenceCardinality cardinality; private final String bind; private final String unbind; - private Reference(Node node) { + private Reference(Class<?> clazz, Node node) { + this.clazz = clazz; this.name = getAttributeValue(node, "name"); this.interfaceType = getAttributeValue(node, "interface"); this.cardinality = toCardinality(getAttributeValue(node, "cardinality")); @@ -320,6 +329,10 @@ final class OsgiMetadataUtil { this.unbind = getAttributeValue(node, "unbind"); } + public Class<?> getServiceClass() { + return clazz; + } + private ReferenceCardinality toCardinality(String value) { for (ReferenceCardinality item : ReferenceCardinality.values()) { if (StringUtils.equals(item.getCardinalityString(), value)) { diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java b/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java index b340b29..306a967 100644 --- a/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java +++ b/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java @@ -299,14 +299,14 @@ final class OsgiServiceUtil { boolean isOptional = (reference.getCardinality() == ReferenceCardinality.OPTIONAL_UNARY || reference .getCardinality() == ReferenceCardinality.OPTIONAL_MULTIPLE); if (!isOptional) { - throw new RuntimeException("Unable to inject mandatory reference '" + reference.getName() + "' for class " + targetClass.getName()); + throw new ReferenceViolationException("Unable to inject mandatory reference '" + reference.getName() + "' for class " + targetClass.getName()); } } // multiple references found? check if reference is not multiple if (matchingServices.size() > 1 && (reference.getCardinality() == ReferenceCardinality.MANDATORY_UNARY || reference.getCardinality() == ReferenceCardinality.OPTIONAL_UNARY)) { - throw new RuntimeException("Multiple matches found for unary reference '" + reference.getName() + "' for class "+ targetClass.getName()); + throw new ReferenceViolationException("Multiple matches found for unary reference '" + reference.getName() + "' for class "+ targetClass.getName()); } // try to invoke bind method @@ -350,7 +350,7 @@ final class OsgiServiceUtil { throw new RuntimeException("Bind method with name " + bindMethodName + " not found " + "for reference '" + reference.getName() + "' for class {}" + targetClass.getName()); } - + private static List<ServiceInfo> getMatchingServices(Class<?> type, BundleContext bundleContext) { List<ServiceInfo> matchingServices = new ArrayList<ServiceInfo>(); try { diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/ReferenceViolationException.java b/src/main/java/org/apache/sling/testing/mock/osgi/ReferenceViolationException.java new file mode 100644 index 0000000..4bfa0f2 --- /dev/null +++ b/src/main/java/org/apache/sling/testing/mock/osgi/ReferenceViolationException.java @@ -0,0 +1,31 @@ +/* + * 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; + +/** + * Is thrown when a OSGi reference injection fails due to violated constraints. + */ +public final class ReferenceViolationException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public ReferenceViolationException(String message) { + super(message); + } + +} diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextTest.java index 6eef138..a6a6258 100644 --- a/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextTest.java +++ b/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextTest.java @@ -21,6 +21,7 @@ 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.assertNull; import static org.junit.Assert.assertSame; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; @@ -50,12 +51,12 @@ public class MockBundleContextTest { @Before public void setUp() { - this.bundleContext = MockOsgi.newBundleContext(); + bundleContext = MockOsgi.newBundleContext(); } @Test public void testBundle() { - assertNotNull(this.bundleContext.getBundle()); + assertNotNull(bundleContext.getBundle()); } @Test @@ -64,48 +65,64 @@ public class MockBundleContextTest { String clazz1 = String.class.getName(); Object service1 = new Object(); Dictionary properties1 = getServiceProperties(null); - ServiceRegistration reg1 = this.bundleContext.registerService(clazz1, service1, properties1); + ServiceRegistration reg1 = 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); + ServiceRegistration reg2 = 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); + ServiceRegistration reg3 = bundleContext.registerService(clazz3, service3, properties3); // test get service references - ServiceReference refString = this.bundleContext.getServiceReference(String.class.getName()); + ServiceReference refString = bundleContext.getServiceReference(String.class.getName()); assertSame(reg1.getReference(), refString); - ServiceReference refInteger = this.bundleContext.getServiceReference(Integer.class.getName()); + ServiceReference refInteger = bundleContext.getServiceReference(Integer.class.getName()); assertSame(reg3.getReference(), refInteger); - ServiceReference[] refsString = this.bundleContext.getServiceReferences(String.class.getName(), null); + ServiceReference[] refsString = 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); + ServiceReference[] refsInteger = 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); + ServiceReference[] allRefsString = 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)); + assertSame(service1, bundleContext.getService(refsString[0])); + assertSame(service2, bundleContext.getService(refsString[1])); + assertSame(service3, bundleContext.getService(refInteger)); // unget does nothing - this.bundleContext.ungetService(refsString[0]); - this.bundleContext.ungetService(refsString[1]); - this.bundleContext.ungetService(refInteger); + bundleContext.ungetService(refsString[0]); + bundleContext.ungetService(refsString[1]); + bundleContext.ungetService(refInteger); } + + @Test + public void testServiceUnregistration() { + // prepare test services + String clazz1 = String.class.getName(); + Object service1 = new Object(); + Dictionary properties1 = getServiceProperties(null); + ServiceRegistration reg1 = bundleContext.registerService(clazz1, service1, properties1); + + assertNotNull(bundleContext.getServiceReference(clazz1)); + + reg1.unregister(); + + assertNull(bundleContext.getServiceReference(clazz1)); + } + private Dictionary getServiceProperties(final Long serviceRanking) { Dictionary<String, Object> props = new Hashtable<String, Object>(); @@ -117,7 +134,7 @@ public class MockBundleContextTest { @Test public void testGetBundles() throws Exception { - assertEquals(0, this.bundleContext.getBundles().length); + assertEquals(0, bundleContext.getBundles().length); } @Test @@ -128,7 +145,7 @@ public class MockBundleContextTest { // prepare test services String clazz1 = String.class.getName(); Object service1 = new Object(); - this.bundleContext.registerService(clazz1, service1, null); + bundleContext.registerService(clazz1, service1, null); verify(serviceListener).serviceChanged(any(ServiceEvent.class)); @@ -152,8 +169,8 @@ public class MockBundleContextTest { 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); + bundleContext.addFrameworkListener(null); + bundleContext.removeFrameworkListener(null); } } -- To stop receiving notification emails like this one, please contact "[email protected]" <[email protected]>.
