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 68de5d4e00c22c66636341be4f80dd14159d7b78 Author: Stefan Seifert <[email protected]> AuthorDate: Thu Feb 19 11:00:05 2015 +0000 SLING-4435 OSGi Mock: Cache reading of OSGi SCR Metadata files git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1660841 13f79535-47bb-0310-9956-ffa450edef68 --- .../testing/mock/osgi/MockServiceRegistration.java | 10 +- .../sling/testing/mock/osgi/OsgiMetadataUtil.java | 121 +++++++++++++++++---- .../sling/testing/mock/osgi/OsgiServiceUtil.java | 22 ++-- .../sling/testing/mock/osgi/package-info.java | 2 +- .../testing/mock/osgi/OsgiMetadataUtilTest.java | 23 ++-- 5 files changed, 128 insertions(+), 50 deletions(-) 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 1dc564b..f212b49 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 @@ -24,11 +24,11 @@ import java.util.Hashtable; import java.util.Map; import java.util.Set; +import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.OsgiMetadata; 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; @@ -89,16 +89,16 @@ class MockServiceRegistration implements ServiceRegistration { */ private void readOsgiMetadata() { Class<?> serviceClass = service.getClass(); - Document doc = OsgiMetadataUtil.getMetadata(serviceClass); - if (doc == null) { + OsgiMetadata metadata = OsgiMetadataUtil.getMetadata(serviceClass); + if (metadata == null) { return; } // add service interfaces from OSGi metadata - clazzes.addAll(OsgiMetadataUtil.getServiceInterfaces(serviceClass, doc)); + clazzes.addAll(metadata.getServiceInterfaces()); // add properties from OSGi metadata - Map<String, Object> props = OsgiMetadataUtil.getProperties(serviceClass, doc); + Map<String, Object> props = metadata.getProperties(); 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 index 41fc4b5..7cf7cfb 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 @@ -27,6 +27,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ExecutionException; import javax.xml.namespace.NamespaceContext; import javax.xml.parsers.DocumentBuilder; @@ -46,6 +47,9 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; @@ -68,6 +72,25 @@ final class OsgiMetadataUtil { static { NAMESPACES.put("scr", "http://www.osgi.org/xmlns/scr/v1.1.0"); } + + private static final OsgiMetadata NULL_METADATA = new OsgiMetadata(); + + /* + * The OSGI metadata XML files do not change during the unit test runs because static part of classpath. + * So we can cache the parsing step if we need them multiple times. + */ + private static final LoadingCache<Class, OsgiMetadata> METADATA_CACHE = CacheBuilder.newBuilder().build(new CacheLoader<Class, OsgiMetadata>() { + @Override + public OsgiMetadata load(Class clazz) throws Exception { + Document metadataDocument = OsgiMetadataUtil.getMetadataDocument(clazz); + if (metadataDocument == null) { + return NULL_METADATA; + } + else { + return new OsgiMetadata(clazz, metadataDocument); + } + } + }); private OsgiMetadataUtil() { // static methods only @@ -95,12 +118,27 @@ final class OsgiMetadataUtil { } /** - * Try to read OSGI-metadata from /OSGI-INF and read all implemented - * interfaces and service properties + * Try to read OSGI-metadata from /OSGI-INF and read all implemented interfaces and service properties. + * The metadata is cached after initial read, so it's no problem to call this method multiple time for the same class. * @param clazz OSGi service implementation class - * @return Metadata document or null + * @return Metadata object or null if no metadata present in classpath */ - public static Document getMetadata(Class clazz) { + public static OsgiMetadata getMetadata(Class clazz) { + try { + OsgiMetadata metadata = METADATA_CACHE.get(clazz); + if (metadata == NULL_METADATA) { + return null; + } + else { + return metadata; + } + } + catch (ExecutionException ex) { + throw new RuntimeException("Error loading OSGi metadata from loader cache.", ex); + } + } + + private static Document getMetadataDocument(Class clazz) { String metadataPath = getMetadataPath(clazz); InputStream metadataStream = clazz.getResourceAsStream(metadataPath); if (metadataStream == null) { @@ -126,7 +164,7 @@ final class OsgiMetadataUtil { } } - public static Set<String> getServiceInterfaces(Class clazz, Document metadata) { + private static Set<String> getServiceInterfaces(Class clazz, Document metadata) { Set<String> serviceInterfaces = new HashSet<String>(); String query = "/components/component[@name='" + clazz.getName() + "']/service/provide[@interface!='']"; NodeList nodes = queryNodes(metadata, query); @@ -142,7 +180,7 @@ final class OsgiMetadataUtil { return serviceInterfaces; } - public static Map<String, Object> getProperties(Class clazz, Document metadata) { + private static Map<String, Object> getProperties(Class clazz, Document metadata) { Map<String, Object> props = new HashMap<String, Object>(); String query = "/components/component[@name='" + clazz.getName() + "']/property[@name!='' and @value!='']"; NodeList nodes = queryNodes(metadata, query); @@ -162,7 +200,7 @@ final class OsgiMetadataUtil { return props; } - public static List<Reference> getReferences(Class clazz, Document metadata) { + private static List<Reference> getReferences(Class clazz, Document metadata) { List<Reference> references = new ArrayList<Reference>(); String query = "/components/component[@name='" + clazz.getName() + "']/reference[@name!='']"; NodeList nodes = queryNodes(metadata, query); @@ -175,18 +213,6 @@ final class OsgiMetadataUtil { return references; } - public static String getActivateMethodName(Class clazz, Document metadata) { - return getLifecycleMethodName(clazz, metadata, "activate"); - } - - public static String getDeactivateMethodName(Class clazz, Document metadata) { - return getLifecycleMethodName(clazz, metadata, "deactivate"); - } - - public static String getModifiedMethodName(Class clazz, Document metadata) { - return getLifecycleMethodName(clazz, metadata, "modified"); - } - private static String getLifecycleMethodName(Class clazz, Document metadata, String methodName) { String query = "/components/component[@name='" + clazz.getName() + "']"; Node node = queryNode(metadata, query); @@ -225,7 +251,60 @@ final class OsgiMetadataUtil { } } - public static class Reference { + static class OsgiMetadata { + + private final Set<String> serviceInterfaces; + private final Map<String, Object> properties; + private final List<Reference> references; + private final String activateMethodName; + private final String deactivateMethodName; + private final String modifiedMethodName; + + private OsgiMetadata(Class clazz, Document metadataDocument) { + this.serviceInterfaces = OsgiMetadataUtil.getServiceInterfaces(clazz, metadataDocument); + this.properties = OsgiMetadataUtil.getProperties(clazz, metadataDocument); + this.references = OsgiMetadataUtil.getReferences(clazz, metadataDocument); + this.activateMethodName = OsgiMetadataUtil.getLifecycleMethodName(clazz, metadataDocument, "activate"); + this.deactivateMethodName = OsgiMetadataUtil.getLifecycleMethodName(clazz, metadataDocument, "deactivate"); + this.modifiedMethodName = OsgiMetadataUtil.getLifecycleMethodName(clazz, metadataDocument, "modified"); + } + + private OsgiMetadata() { + this.serviceInterfaces = null; + this.properties = null; + this.references = null; + this.activateMethodName = null; + this.deactivateMethodName = null; + this.modifiedMethodName = null; + } + + public Set<String> getServiceInterfaces() { + return serviceInterfaces; + } + + public Map<String, Object> getProperties() { + return properties; + } + + public List<Reference> getReferences() { + return references; + } + + public String getActivateMethodName() { + return activateMethodName; + } + + public String getDeactivateMethodName() { + return deactivateMethodName; + } + + public String getModifiedMethodName() { + return modifiedMethodName; + } + + } + + static class Reference { private final String name; private final String interfaceType; @@ -233,7 +312,7 @@ final class OsgiMetadataUtil { private final String bind; private final String unbind; - public Reference(Node node) { + private Reference(Node node) { this.name = getAttributeValue(node, "name"); this.interfaceType = getAttributeValue(node, "interface"); this.cardinality = toCardinality(getAttributeValue(node, "cardinality")); 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 7606d65..b340b29 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 @@ -29,12 +29,12 @@ import java.util.Map; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.OsgiMetadata; 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.w3c.dom.Document; /** * Helper methods to inject dependencies and activate services. @@ -56,15 +56,15 @@ final class OsgiServiceUtil { Class<?> targetClass = target.getClass(); // get method name for activation/deactivation from osgi metadata - Document metadata = OsgiMetadataUtil.getMetadata(targetClass); - if (metadata==null) { + OsgiMetadata metadata = OsgiMetadataUtil.getMetadata(targetClass); + if (metadata == null) { throw new NoScrMetadataException(targetClass); } String methodName; if (activate) { - methodName = OsgiMetadataUtil.getActivateMethodName(targetClass, metadata); + methodName = metadata.getActivateMethodName(); } else { - methodName = OsgiMetadataUtil.getDeactivateMethodName(targetClass, metadata); + methodName = metadata.getDeactivateMethodName(); } if (StringUtils.isEmpty(methodName)) { return false; @@ -156,11 +156,11 @@ final class OsgiServiceUtil { Class<?> targetClass = target.getClass(); // get method name for activation/deactivation from osgi metadata - Document metadata = OsgiMetadataUtil.getMetadata(targetClass); - if (metadata==null) { + OsgiMetadata metadata = OsgiMetadataUtil.getMetadata(targetClass); + if (metadata == null) { throw new NoScrMetadataException(targetClass); } - String methodName = OsgiMetadataUtil.getModifiedMethodName(targetClass, metadata); + String methodName = metadata.getModifiedMethodName(); if (StringUtils.isEmpty(methodName)) { return false; } @@ -264,11 +264,11 @@ final class OsgiServiceUtil { // collect all declared reference annotations on class and field level Class<?> targetClass = target.getClass(); - Document metadata = OsgiMetadataUtil.getMetadata(targetClass); - if (metadata==null) { + OsgiMetadata metadata = OsgiMetadataUtil.getMetadata(targetClass); + if (metadata == null) { throw new NoScrMetadataException(targetClass); } - List<Reference> references = OsgiMetadataUtil.getReferences(targetClass, metadata); + List<Reference> references = metadata.getReferences(); if (references.isEmpty()) { return false; } diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/package-info.java b/src/main/java/org/apache/sling/testing/mock/osgi/package-info.java index 14b8744..6a6de3f 100644 --- a/src/main/java/org/apache/sling/testing/mock/osgi/package-info.java +++ b/src/main/java/org/apache/sling/testing/mock/osgi/package-info.java @@ -19,5 +19,5 @@ /** * Mock implementation of selected OSGi APIs. */ [email protected]("1.1") [email protected]("2.0") package org.apache.sling.testing.mock.osgi; 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 index 280f955..9db1197 100644 --- a/src/test/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtilTest.java +++ b/src/test/java/org/apache/sling/testing/mock/osgi/OsgiMetadataUtilTest.java @@ -26,24 +26,24 @@ import java.util.Map; import java.util.Set; import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.OsgiMetadata; 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); + OsgiMetadata metadata = OsgiMetadataUtil.getMetadata(ServiceWithMetadata.class); - Set<String> serviceInterfaces = OsgiMetadataUtil.getServiceInterfaces(ServiceWithMetadata.class, doc); + Set<String> serviceInterfaces = metadata.getServiceInterfaces(); 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); + Map<String, Object> props = metadata.getProperties(); assertEquals(3, props.size()); assertEquals(5000, props.get("service.ranking")); assertEquals("The Apache Software Foundation", props.get("service.vendor")); @@ -52,19 +52,19 @@ public class OsgiMetadataUtilTest { @Test public void testNoMetadata() { - Document doc = OsgiMetadataUtil.getMetadata(ServiceWithoutMetadata.class); + OsgiMetadata metadata = OsgiMetadataUtil.getMetadata(ServiceWithoutMetadata.class); - Set<String> serviceInterfaces = OsgiMetadataUtil.getServiceInterfaces(ServiceWithoutMetadata.class, doc); + Set<String> serviceInterfaces = metadata.getServiceInterfaces(); assertEquals(0, serviceInterfaces.size()); - Map<String, Object> props = OsgiMetadataUtil.getProperties(ServiceWithoutMetadata.class, doc); + Map<String, Object> props = metadata.getProperties(); assertEquals(0, props.size()); } @Test public void testReferences() { - Document doc = OsgiMetadataUtil.getMetadata(OsgiServiceUtilTest.Service3.class); - List<Reference> references = OsgiMetadataUtil.getReferences(OsgiServiceUtilTest.Service3.class, doc); + OsgiMetadata metadata = OsgiMetadataUtil.getMetadata(OsgiServiceUtilTest.Service3.class); + List<Reference> references = metadata.getReferences(); assertEquals(3, references.size()); Reference ref1 = references.get(0); @@ -77,9 +77,8 @@ public class OsgiMetadataUtilTest { @Test public void testActivateMethodName() { - Document doc = OsgiMetadataUtil.getMetadata(OsgiServiceUtilTest.Service3.class); - String methodName = OsgiMetadataUtil.getActivateMethodName(OsgiServiceUtilTest.Service3.class, doc); - assertEquals("activate", methodName); + OsgiMetadata metadata = OsgiMetadataUtil.getMetadata(OsgiServiceUtilTest.Service3.class); + assertEquals("activate", metadata.getActivateMethodName()); } static class ServiceWithMetadata { -- To stop receiving notification emails like this one, please contact "[email protected]" <[email protected]>.
