This is an automated email from the ASF dual-hosted git repository. sseifert pushed a commit to branch experimental/serviceFactory_scopePrototype in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git
commit 93f9856b29ce232dfa926b0e4368f7f2cae3217b Author: Stefan Seifert <[email protected]> AuthorDate: Tue Dec 7 15:50:32 2021 +0100 WIP: start implementing support for service scope, and proper implementation of factory service support --- .../sling/testing/mock/osgi/OsgiMetadataUtil.java | 26 ++++++++++ .../testing/mock/osgi/OsgiMetadataUtilTest.java | 9 ++++ .../testing/mock/osgi/OsgiServiceUtilTest.java | 59 +++++++++++---------- ...iceFactory1.java => ScopePrototypeService.java} | 15 +++++- .../ScopePrototypeServiceFactory.java | 60 ++++++++++++++++++++++ 5 files changed, 140 insertions(+), 29 deletions(-) diff --git a/core/src/main/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtil.java b/core/src/main/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtil.java index e094d10..216e022 100644 --- a/core/src/main/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtil.java +++ b/core/src/main/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtil.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; +import java.util.Arrays; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; @@ -47,10 +48,12 @@ import org.apache.commons.collections4.BidiMap; import org.apache.commons.collections4.bidimap.TreeBidiMap; import org.apache.commons.lang3.StringUtils; import org.apache.felix.framework.FilterImpl; +import org.jetbrains.annotations.NotNull; import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; +import org.osgi.service.component.annotations.ServiceScope; import org.reflections.Reflections; import org.reflections.scanners.Scanners; import org.slf4j.Logger; @@ -287,6 +290,22 @@ final class OsgiMetadataUtil { return serviceInterfaces; } + @SuppressWarnings("null") + private static @NotNull ServiceScope getServiceScope(Class clazz, Document metadata) { + String query = getComponentXPathQuery(clazz) + "/service"; + String scopeValue; + NodeList nodes = queryNodes(metadata, query); + if (nodes != null && nodes.getLength() > 0) { + scopeValue = getAttributeValue(nodes.item(0), "scope"); + } + else { + scopeValue = null; + } + return Arrays.stream(ServiceScope.values()) + .filter(serviceScope -> StringUtils.equals(scopeValue, serviceScope.toString())) + .findFirst().orElse(ServiceScope.DEFAULT); + } + private static Map<String, Object> getProperties(Class clazz, Document metadata) { Map<String, Object> props = new HashMap<String, Object>(); String query = getComponentXPathQuery(clazz) + "/property[@name!='' and @value!='']"; @@ -384,6 +403,7 @@ final class OsgiMetadataUtil { private final String name; private final String[] configurationPID; private final Set<String> serviceInterfaces; + private final ServiceScope serviceScope; private final Map<String, Object> properties; private final List<Reference> references; private final String activateMethodName; @@ -395,6 +415,7 @@ final class OsgiMetadataUtil { this.name = OsgiMetadataUtil.getComponentName(clazz, metadataDocument); this.configurationPID = OsgiMetadataUtil.getConfigurationPID(clazz, metadataDocument); this.serviceInterfaces = OsgiMetadataUtil.getServiceInterfaces(clazz, metadataDocument); + this.serviceScope = OsgiMetadataUtil.getServiceScope(clazz, metadataDocument); this.properties = OsgiMetadataUtil.getProperties(clazz, metadataDocument); this.references = OsgiMetadataUtil.getReferences(clazz, metadataDocument); this.activateMethodName = OsgiMetadataUtil.getLifecycleMethodName(clazz, metadataDocument, "activate"); @@ -407,6 +428,7 @@ final class OsgiMetadataUtil { this.name = null; this.configurationPID = null; this.serviceInterfaces = null; + this.serviceScope = ServiceScope.DEFAULT; this.properties = null; this.references = null; this.activateMethodName = null; @@ -438,6 +460,10 @@ final class OsgiMetadataUtil { return serviceInterfaces; } + public @NotNull ServiceScope getServiceScope() { + return serviceScope; + } + public Map<String, Object> getProperties() { return properties; } diff --git a/core/src/test/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtilTest.java b/core/src/test/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtilTest.java index a1d64f7..913bf27 100644 --- a/core/src/test/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtilTest.java +++ b/core/src/test/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtilTest.java @@ -30,10 +30,12 @@ import java.util.Set; import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.OsgiMetadata; import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.Reference; import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.ReferenceCardinality; +import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.ScopePrototypeService; import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.Service3; import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.ServiceInterface2; import org.junit.Test; import org.osgi.framework.Constants; +import org.osgi.service.component.annotations.ServiceScope; public class OsgiMetadataUtilTest { @@ -46,6 +48,7 @@ public class OsgiMetadataUtilTest { Set<String> serviceInterfaces = metadata.getServiceInterfaces(); assertEquals(1, serviceInterfaces.size()); assertTrue(serviceInterfaces.contains("java.lang.Comparable")); + assertEquals(ServiceScope.DEFAULT, metadata.getServiceScope()); Map<String, Object> props = metadata.getProperties(); assertEquals(3, props.size()); @@ -81,6 +84,12 @@ public class OsgiMetadataUtilTest { assertEquals("activate", metadata.getActivateMethodName()); } + @Test + public void testServiceScope() { + OsgiMetadata metadata = OsgiMetadataUtil.getMetadata(ScopePrototypeService.class); + assertEquals(ServiceScope.PROTOTYPE, metadata.getServiceScope()); + } + static class ServiceWithMetadata { // empty class } diff --git a/core/src/test/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtilTest.java b/core/src/test/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtilTest.java index 3e428ce..01208f5 100644 --- a/core/src/test/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtilTest.java +++ b/core/src/test/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtilTest.java @@ -21,6 +21,7 @@ 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.assertNotSame; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; @@ -32,13 +33,15 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.ScopePrototypeService; +import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.ScopePrototypeServiceFactory; +import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.ScopePrototypeServiceFactory.ScopePrototpyeInstance; import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.Service1; import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.Service2; import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.Service3; import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.Service3OsgiR6; import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.Service4; import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.Service5; -import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.ServiceFactory1; import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.ServiceInterface1; import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.ServiceInterface2; import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.ServiceInterface3; @@ -48,10 +51,8 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; -import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceFactory; -import org.osgi.framework.ServiceRegistration; +import org.osgi.framework.ServiceReference; import com.google.common.collect.ImmutableMap; @@ -210,34 +211,38 @@ public class OsgiServiceUtilTest { } @Test - public void testServiceFactoryViaScr() { - ServiceFactory1 serviceFactory1 = new ServiceFactory1(); + public void testScopePrototypeService() { + MockOsgi.registerInjectActivateService(ScopePrototypeService.class, bundleContext); - MockOsgi.injectServices(serviceFactory1, bundleContext); - MockOsgi.activate(serviceFactory1, bundleContext, (Dictionary<String, Object>) null); - bundleContext.registerService(ServiceFactory1.class.getName(), serviceFactory1, null); + ServiceReference<ScopePrototypeService> ref = bundleContext.getServiceReference(ScopePrototypeService.class); + assertNotNull(ref); - assertSame(serviceFactory1, bundleContext.getService( - bundleContext.getServiceReference(ServiceFactory1.class.getName()))); + ScopePrototypeService instance1 = bundleContext.getService(ref); + assertNotNull(instance1); + + ScopePrototypeService instance2 = bundleContext.getService(ref); + assertNotNull(instance2); + + assertNotSame(instance1, instance2); + assertTrue(instance2.getInstanceId() > instance1.getInstanceId()); } @Test - public void testServiceFactoryViaManualRegistration() { - final ServiceFactory1 serviceFactory1 = new ServiceFactory1(); - - bundleContext.registerService(ServiceFactory1.class.getName(), new ServiceFactory() { - @Override - public Object getService(Bundle bundle, ServiceRegistration registration) { - return serviceFactory1; - } - @Override - public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) { - // nothing to do - } - }, null); - - assertSame(serviceFactory1, bundleContext.getService( - bundleContext.getServiceReference(ServiceFactory1.class.getName()))); + @SuppressWarnings("unchecked") + public void testScopePrototypeServiceFactory() { + MockOsgi.registerInjectActivateService(ScopePrototypeServiceFactory.class, bundleContext); + + ServiceReference<ScopePrototpyeInstance> ref = (ServiceReference)bundleContext.getServiceReference(ScopePrototypeServiceFactory.class); + assertNotNull(ref); + + ScopePrototpyeInstance instance1 = bundleContext.getService(ref); + assertNotNull(instance1); + + ScopePrototpyeInstance instance2 = bundleContext.getService(ref); + assertNotNull(instance2); + + assertNotSame(instance1, instance2); + assertTrue(instance2.getInstanceId() > instance1.getInstanceId()); } } diff --git a/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/ServiceFactory1.java b/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/ScopePrototypeService.java similarity index 67% rename from test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/ServiceFactory1.java rename to test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/ScopePrototypeService.java index 3fcbef7..199ed3a 100644 --- a/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/ServiceFactory1.java +++ b/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/ScopePrototypeService.java @@ -18,9 +18,20 @@ */ package org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil; +import java.util.concurrent.atomic.AtomicLong; + import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ServiceScope; + +@Component(service = ScopePrototypeService.class, scope = ServiceScope.PROTOTYPE) +public class ScopePrototypeService { + + private static final AtomicLong INSTANCE_COUNTER = new AtomicLong(); + + private final long instanceId = INSTANCE_COUNTER.incrementAndGet(); -@Component(service = ServiceFactory1.class, servicefactory = true) -public class ServiceFactory1 { + public long getInstanceId() { + return instanceId; + } } diff --git a/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/ScopePrototypeServiceFactory.java b/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/ScopePrototypeServiceFactory.java new file mode 100644 index 0000000..31744f1 --- /dev/null +++ b/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/ScopePrototypeServiceFactory.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.testsvc.osgiserviceutil; + +import java.util.concurrent.atomic.AtomicLong; + +import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.ScopePrototypeServiceFactory.ScopePrototpyeInstance; +import org.osgi.framework.Bundle; +import org.osgi.framework.ServiceFactory; +import org.osgi.framework.ServiceRegistration; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ServiceScope; + +@Component(service = ScopePrototypeServiceFactory.class, scope = ServiceScope.PROTOTYPE) +public class ScopePrototypeServiceFactory implements ServiceFactory<ScopePrototpyeInstance> { + + private static final AtomicLong INSTANCE_COUNTER = new AtomicLong(); + + @Override + public ScopePrototpyeInstance getService(Bundle bundle, ServiceRegistration<ScopePrototpyeInstance> registration) { + return new ScopePrototpyeInstance(INSTANCE_COUNTER.incrementAndGet()); + } + + @Override + public void ungetService(Bundle bundle, ServiceRegistration<ScopePrototpyeInstance> registration, + ScopePrototpyeInstance service) { + // nothing to do + } + + public static class ScopePrototpyeInstance { + + private final long instanceId; + + private ScopePrototpyeInstance(long instanceId) { + this.instanceId = instanceId; + } + + public long getInstanceId() { + return instanceId; + } + + } + +}
