Add support for dynamic reference properties
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
index 7c07578..4d22717 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockOsgi.java
@@ -145,7 +145,20 @@
* @return true if all dependencies could be injected, false if the service has no dependencies.
*/
public static boolean injectServices(Object target, BundleContext bundleContext) {
- return OsgiServiceUtil.injectServices(target, bundleContext);
+ return MockOsgi.injectServices(target, bundleContext, (Map<String, Object>)null);
+ }
+
+ /**
+ * 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.
+ * @param properties Service properties (used to resolve dynamic reference properties)
+ * @return true if all dependencies could be injected, false if the service has no dependencies.
+ */
+ public static boolean injectServices(Object target, BundleContext bundleContext, Map<String, Object> properties) {
+ return OsgiServiceUtil.injectServices(target, bundleContext, properties);
}
/**
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 1fca7a5..1e0b8d3 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
@@ -470,20 +470,20 @@
static class Reference {
- private final Class<?> clazz;
- private final String name;
- private final String interfaceType;
- private final ReferenceCardinality cardinality;
- private final ReferencePolicy policy;
- private final ReferencePolicyOption policyOption;
- private final String bind;
- private final String unbind;
- private final String field;
- private final FieldCollectionType fieldCollectionType;
- private final String target;
- private final Filter targetFilter;
+ protected final Class<?> clazz;
+ protected final String name;
+ protected final String interfaceType;
+ protected final ReferenceCardinality cardinality;
+ protected final ReferencePolicy policy;
+ protected final ReferencePolicyOption policyOption;
+ protected final String bind;
+ protected final String unbind;
+ protected final String field;
+ protected final FieldCollectionType fieldCollectionType;
+ protected String target;
+ protected Filter targetFilter;
- private Reference(Class<?> clazz, Node node) {
+ protected Reference(Class<?> clazz, Node node) {
this.clazz = clazz;
this.name = getAttributeValue(node, "name");
this.interfaceType = getAttributeValue(node, "interface");
@@ -507,6 +507,21 @@
}
}
+ protected Reference(Reference reference) {
+ this.clazz = reference.clazz;
+ this.name = reference.name;
+ this.interfaceType = reference.interfaceType;
+ this.cardinality = reference.cardinality;
+ this.policy = reference.policy;
+ this.policyOption = reference.policyOption;
+ this.bind = reference.bind;
+ this.unbind = reference.unbind;
+ this.field = reference.field;
+ this.fieldCollectionType = reference.fieldCollectionType;
+ this.target = reference.target;
+ this.targetFilter = reference.targetFilter;
+ }
+
public Class<?> getServiceClass() {
return clazz;
}
@@ -614,6 +629,22 @@
}
+ static class DynamicReference extends Reference {
+ public DynamicReference(Reference reference, String target) {
+ super(reference);
+ this.target = target;
+ if (StringUtils.isNotEmpty(this.target)) {
+ try {
+ this.targetFilter = new FilterImpl(this.target);
+ } catch (InvalidSyntaxException ex) {
+ throw new RuntimeException("Invalid target filter in reference '" + this.name + "' of class " + clazz.getName(), ex);
+ }
+ }
+ else {
+ this.targetFilter = null;
+ }
+ }
+ }
/**
* Options for {@link Reference#cardinality()} property.
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 b3fd20c..488b4fe 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
@@ -31,6 +31,7 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.felix.scr.impl.inject.Annotations;
+import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.DynamicReference;
import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.FieldCollectionType;
import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.OsgiMetadata;
import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.Reference;
@@ -369,9 +370,10 @@
* multiple references.
* @param target Service instance
* @param bundleContext Bundle context from which services are fetched to inject.
+ * @param properties Services properties (used to resolve dynamic reference properties)
* @return true if all dependencies could be injected, false if the service has no dependencies.
*/
- public static boolean injectServices(Object target, BundleContext bundleContext) {
+ public static boolean injectServices(Object target, BundleContext bundleContext, Map<String, Object> properties) {
// collect all declared reference annotations on class and field level
Class<?> targetClass = target.getClass();
@@ -387,6 +389,13 @@
// try to inject services
for (Reference reference : references) {
+ if (properties != null) {
+ // Look for a target override
+ Object o = properties.get(reference.getName() + ".target");
+ if (o != null && o instanceof String) {
+ reference = new DynamicReference(reference,(String)o);
+ }
+ }
injectServiceReference(reference, target, bundleContext);
}
return true;
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImpl.java b/src/main/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImpl.java
index acb96e7..ae9d0b2 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImpl.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImpl.java
@@ -150,7 +150,7 @@
* @return Registered service instance
*/
public final <T> T registerInjectActivateService(final T service, final Map<String, Object> properties) {
- MockOsgi.injectServices(service, bundleContext());
+ MockOsgi.injectServices(service, bundleContext(), properties);
MockOsgi.activate(service, bundleContext(), properties);
registerService(null, service, properties);
return service;
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 d1f57fc..db6c8d4 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.
*/
-@org.osgi.annotation.versioning.Version("3.3")
+@org.osgi.annotation.versioning.Version("3.4")
package org.apache.sling.testing.mock.osgi;