Merge pull request #6 from rotty3000/trim-and-excludes

Trim and excludes
diff --git a/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/annotated/AnnotatedImpl.java b/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/annotated/AnnotatedImpl.java
index 62d54d5..463fc05 100644
--- a/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/annotated/AnnotatedImpl.java
+++ b/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/annotated/AnnotatedImpl.java
@@ -14,7 +14,7 @@
 
 package org.apache.aries.cdi.container.internal.annotated;
 
-import static java.util.stream.Collectors.*;
+import static java.util.stream.Collectors.toSet;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.AnnotatedElement;
@@ -68,4 +68,9 @@
 		return _annotatedElement.isAnnotationPresent(annotationType);
 	}
 
+	@Override
+	public String toString() {
+		return _baseType.getTypeName();
+	}
+
 }
diff --git a/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/Discovery.java b/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/Discovery.java
index bd1cb97..96e68ce 100644
--- a/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/Discovery.java
+++ b/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/container/Discovery.java
@@ -14,16 +14,22 @@
 
 package org.apache.aries.cdi.container.internal.container;
 
+import java.io.InputStream;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
+import java.net.URL;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import javax.enterprise.context.ApplicationScoped;
 import javax.enterprise.context.Dependent;
@@ -38,6 +44,13 @@
 import javax.enterprise.inject.spi.AnnotatedType;
 import javax.inject.Inject;
 import javax.inject.Named;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
 
 import org.apache.aries.cdi.container.internal.annotated.AnnotatedTypeImpl;
 import org.apache.aries.cdi.container.internal.model.BeansModel;
@@ -64,15 +77,50 @@
 import org.osgi.service.cdi.reference.BindService;
 import org.osgi.service.cdi.reference.BindServiceReference;
 import org.osgi.service.cdi.runtime.dto.template.ComponentTemplateDTO;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import aQute.lib.exceptions.Exceptions;
 
 public class Discovery {
 
 	private static final List<Type> BIND_TYPES = Arrays.asList(BindService.class, BindBeanServiceObjects.class, BindServiceReference.class);
 
+	static final DocumentBuilderFactory	dbf	= DocumentBuilderFactory.newInstance();
+	static final XPathFactory			xpf	= XPathFactory.newInstance();
+	static final XPathExpression		trimExpression;
+	static final XPathExpression		excludeExpression;
+
+	static {
+		try {
+			dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+			dbf.setXIncludeAware(false);
+			dbf.setExpandEntityReferences(false);
+			XPath xPath = xpf.newXPath();
+			trimExpression = xPath.compile("boolean(/beans/trim)");
+			excludeExpression = xPath.compile("/beans/scan/exclude");
+		} catch (Throwable t) {
+			throw Exceptions.duck(t);
+		}
+	}
+
 	public Discovery(ContainerState containerState) {
 		_containerState = containerState;
 		_beansModel = _containerState.beansModel();
 		_containerTemplate = _containerState.containerDTO().template.components.get(0);
+
+		AtomicBoolean trim = new AtomicBoolean();
+
+		_excludes = new ArrayList<>();
+
+		_beansModel.getBeansXml().stream().map(this::readXMLResource).forEach(doc -> {
+			if (!trim.get()) trim.set(checkTrim(doc));
+			_excludes.addAll(getExcludes(doc));
+		});
+
+		_trim = trim.get();
 	}
 
 	public void discover() {
@@ -81,6 +129,10 @@
 
 			AnnotatedType<?> annotatedType = new AnnotatedTypeImpl<>(osgiBean.getBeanClass());
 
+			if (trimIt(annotatedType) || exclude(annotatedType)) {
+				return;
+			}
+
 			try {
 				String beanName = Annotates.beanName(annotatedType);
 				Class<? extends Annotation> beanScope = Annotates.beanScope(annotatedType);
@@ -154,6 +206,23 @@
 		postProcessComponentScopedBeans();
 	}
 
+	boolean exclude(AnnotatedType<?> annotatedType) {
+		// See https://docs.jboss.org/cdi/spec/2.0/cdi-spec.html#exclude_filters
+		return _excludes.stream().anyMatch(ex -> ex.exclude(annotatedType));
+	}
+
+	boolean trimIt(AnnotatedType<?> annotatedType) {
+		// See https://docs.jboss.org/cdi/spec/2.0/cdi-spec.html#trimmed_bean_archive
+		if (!_trim) return false;
+
+		if (Annotates.hasBeanDefiningAnnotations(annotatedType)) return false;
+
+		// or any scope annotation
+		if (Annotates.beanScope(annotatedType, null) != null) return false;
+
+		return true;
+	}
+
 	<X> boolean isInject(AnnotatedMember<X> annotatedMember) {
 		return (annotatedMember.isAnnotationPresent(Inject.class) && !annotatedMember.isStatic());
 	}
@@ -389,9 +458,177 @@
 		}
 	}
 
+	boolean checkTrim(Document document) {
+		try {
+			return Boolean.class.cast(trimExpression.evaluate(document, XPathConstants.BOOLEAN));
+		} catch (XPathExpressionException e) {
+			throw Exceptions.duck(e);
+		}
+	}
+
+	List<Exclude> getExcludes(Document document) {
+		try {
+			List<Exclude> excludes = new ArrayList<>();
+
+			NodeList excludeNodes = NodeList.class.cast(excludeExpression.evaluate(document, XPathConstants.NODESET));
+
+			for (int i = 0; i < excludeNodes.getLength(); i++) {
+				Element excludeElement = (Element)excludeNodes.item(i);
+
+				excludes.add(new Exclude(excludeElement));
+			}
+
+			return excludes;
+		}
+		catch (Exception e) {
+			throw Exceptions.duck(e);
+		}
+	}
+
+	Document readXMLResource(URL resource) {
+		try {
+			DocumentBuilder db = dbf.newDocumentBuilder();
+			try (InputStream is = resource.openStream()) {
+				return db.parse(is);
+			} catch (Throwable t) {
+				return db.newDocument();
+			}
+		}
+		catch (Exception e) {
+			throw Exceptions.duck(e);
+		}
+	}
+
 	private final BeansModel _beansModel;
 	private final Set<OSGiBean> _componentScoped = new HashSet<>();
 	private final ComponentTemplateDTO _containerTemplate;
 	private final ContainerState _containerState;
+	private final boolean _trim;
+	private final List<Exclude> _excludes;
+
+	enum Match {
+		CLASSNAME, PACKAGE_NAME, PACKAGE_PREFIX
+	}
+
+	class Exclude {
+
+		private final String name;
+		private final Match match;
+		private final List<String> ifClassAvailableS = new ArrayList<>();
+		private final List<String> ifClassesNotAvailableS = new ArrayList<>();
+		private final Map<String, String> ifSystemPropertyS = new HashMap<>();
+
+		public Exclude(Element excludeElement) {
+			String glob = excludeElement.getAttribute("name");
+
+			if (glob.endsWith(".**")) {
+				match = Match.PACKAGE_PREFIX;
+				name = glob.substring(0, glob.length() - 3);
+			}
+			else if (glob.endsWith(".*")) {
+				match = Match.PACKAGE_NAME;
+				name = glob.substring(0, glob.length() - 2);
+			}
+			else {
+				match = Match.CLASSNAME;
+				name = glob;
+			}
+
+			NodeList ifClassAvailableNodes = excludeElement.getElementsByTagName("if-class-available");
+
+			for (int iCAIdx = 0; iCAIdx < ifClassAvailableNodes.getLength(); iCAIdx++) {
+				Element ifClassAvailableElement = (Element)ifClassAvailableNodes.item(iCAIdx);
+
+				Attr nameAttribute = ifClassAvailableElement.getAttributeNode("name");
+
+				ifClassAvailableS.add(nameAttribute.getValue());
+			}
+
+			NodeList ifClassNotAvailableNodes = excludeElement.getElementsByTagName("if-class-not-available");
+
+			for (int iCNAIdx = 0; iCNAIdx < ifClassNotAvailableNodes.getLength(); iCNAIdx++) {
+				Element ifClassNotAvailableElement = (Element)ifClassNotAvailableNodes.item(iCNAIdx);
+
+				Attr nameAttribute = ifClassNotAvailableElement.getAttributeNode("name");
+
+				ifClassesNotAvailableS.add(nameAttribute.getValue());
+			}
+
+			NodeList ifSystemPropertyNodes = excludeElement.getElementsByTagName("if-system-property");
+
+			for (int iCNAIdx = 0; iCNAIdx < ifSystemPropertyNodes.getLength(); iCNAIdx++) {
+				Element ifSystemPropertyElement = (Element)ifSystemPropertyNodes.item(iCNAIdx);
+
+				String value = "";
+
+				if (ifSystemPropertyElement.hasAttribute("value")) {
+					value = ifSystemPropertyElement.getAttributeNode("value").getValue();
+				}
+
+				Attr nameAttribute = ifSystemPropertyElement.getAttributeNode("name");
+
+				ifSystemPropertyS.put(nameAttribute.getValue(), value);
+			}
+		}
+
+		public boolean exclude(AnnotatedType<?> annotatedType) {
+			String className = annotatedType.getJavaClass().getName();
+			String packageName = annotatedType.getJavaClass().getPackage().getName();
+
+			boolean matches = false;
+			switch (match) {
+				case CLASSNAME: {
+					matches = className.equals(name);
+					break;
+				}
+				case PACKAGE_NAME: {
+					matches = packageName.equals(name);
+					break;
+				}
+				case PACKAGE_PREFIX: {
+					matches = packageName.startsWith(name);
+				}
+			}
+
+			if (matches &&
+				ifClassAvailableS.stream().allMatch(this::classIsAvailable) &&
+				ifClassesNotAvailableS.stream().allMatch(this::classIsNotAvailable) &&
+				ifSystemPropertyS.entrySet().stream().allMatch(this::isPropertySet)) {
+
+				return true;
+			}
+
+			return false;
+		}
+
+		boolean classIsNotAvailable(String className) {
+			return !classIsAvailable(className);
+		}
+
+		boolean classIsAvailable(String className) {
+			try {
+				Class.forName(className, false, _containerState.classLoader());
+				return true;
+			}
+			catch (ClassNotFoundException cnfe) {
+				return false;
+			}
+		}
+
+		boolean isPropertySet(Entry<String, String> entry) {
+			if (entry.getValue().isEmpty()) {
+				return _containerState.bundleContext().getProperty(entry.getKey()) != null;
+			}
+			else {
+				return entry.getValue().equals(_containerState.bundleContext().getProperty(entry.getKey()));
+			}
+		}
+
+		@Override
+		public String toString() {
+			return name + ":" + match;
+		}
+
+	}
 
 }
diff --git a/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Annotates.java b/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Annotates.java
index 93da73a..9239d4a 100644
--- a/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Annotates.java
+++ b/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Annotates.java
@@ -23,6 +23,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
@@ -30,8 +31,14 @@
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
+import javax.decorator.Decorator;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.ConversationScoped;
 import javax.enterprise.context.Dependent;
 import javax.enterprise.context.NormalScope;
+import javax.enterprise.context.RequestScoped;
+import javax.enterprise.context.SessionScoped;
+import javax.enterprise.inject.Stereotype;
 import javax.enterprise.inject.spi.Annotated;
 import javax.enterprise.inject.spi.AnnotatedField;
 import javax.enterprise.inject.spi.AnnotatedMember;
@@ -47,6 +54,7 @@
 import javax.inject.Named;
 import javax.inject.Qualifier;
 import javax.inject.Scope;
+import javax.interceptor.Interceptor;
 
 import org.osgi.service.cdi.ServiceScope;
 import org.osgi.service.cdi.annotations.Service;
@@ -58,6 +66,16 @@
 		// no instances
 	}
 
+	private static final Predicate<Annotation> isBeanDefining = annotation ->
+		ApplicationScoped.class.isAssignableFrom(annotation.annotationType()) ||
+		ConversationScoped.class.isAssignableFrom(annotation.annotationType()) ||
+		Decorator.class.isAssignableFrom(annotation.annotationType()) ||
+		Dependent.class.isAssignableFrom(annotation.annotationType()) ||
+		Interceptor.class.isAssignableFrom(annotation.annotationType()) ||
+		RequestScoped.class.isAssignableFrom(annotation.annotationType()) ||
+		SessionScoped.class.isAssignableFrom(annotation.annotationType()) ||
+		Stereotype.class.isAssignableFrom(annotation.annotationType());
+
 	private static final Predicate<Annotation> isQualifier = annotation ->
 		!annotation.annotationType().equals(Qualifier.class) &&
 		annotation.annotationType().isAnnotationPresent(Qualifier.class);
@@ -132,7 +150,11 @@
 	}
 
 	public static Set<Annotation> qualifiers(Annotated annotated) {
-		return collect(annotated.getAnnotations()).stream().filter(isQualifier).collect(Collectors.toSet());
+		return collect(annotated, isQualifier);
+	}
+
+	public static Set<Annotation> collect(Annotated annotated, Predicate<Annotation> predicate) {
+		return collect(annotated.getAnnotations()).stream().filter(predicate).collect(Collectors.toSet());
 	}
 
 	private static List<Annotation> collect(Collection<Annotation> annotations) {
@@ -303,9 +325,23 @@
 	}
 
 	public static Class<? extends Annotation> beanScope(Annotated annotated) {
+		return beanScope(annotated, Dependent.class);
+	}
+
+	public static Class<? extends Annotation> beanScope(Annotated annotated, Class<? extends Annotation> defaultValue) {
 		Class<? extends Annotation> scope = collect(annotated.getAnnotations()).stream().filter(isScope).map(Annotation::annotationType).findFirst().orElse(null);
 
-		return (scope == null) ? Dependent.class : scope;
+		return (scope == null) ? defaultValue : scope;
+	}
+
+	public static boolean hasBeanDefiningAnnotations(AnnotatedType<?> annotatedType) {
+		Set<Annotation> beanDefiningAnnotations = new HashSet<>();
+
+		beanDefiningAnnotations.addAll(collect(annotatedType, isBeanDefining));
+		beanDefiningAnnotations.addAll(annotatedType.getFields().stream().flatMap(field -> collect(field, isBeanDefining).stream()).collect(Collectors.toSet()));
+		beanDefiningAnnotations.addAll(annotatedType.getMethods().stream().flatMap(method -> collect(method, isBeanDefining).stream()).collect(Collectors.toSet()));
+
+		return !beanDefiningAnnotations.isEmpty();
 	}
 
 }
\ No newline at end of file
diff --git a/cdi-itests/base-itest.bndrun b/cdi-itests/base-itest.bndrun
index cbf4ddb..a82ea48 100644
--- a/cdi-itests/base-itest.bndrun
+++ b/cdi-itests/base-itest.bndrun
@@ -20,7 +20,9 @@
 	logback.configurationFile=file:${.}/logback.xml,\
 	org.osgi.service.http.port=0,\
 	osgi.console=,\
-	tck.config.test.javaconfig.converter.stringvalues=foo
+	tck.config.test.javaconfig.converter.stringvalues=foo,\
+	test.property.a=blah,\
+	test.property.b=
 
 -resolve.effective: resolve, active
 
diff --git a/cdi-itests/bnd.bnd b/cdi-itests/bnd.bnd
index d574c45..1c801b6 100644
--- a/cdi-itests/bnd.bnd
+++ b/cdi-itests/bnd.bnd
@@ -58,7 +58,11 @@
 	tb12.jar,\
 	tb13.jar,\
 	tb14.jar,\
-	tb16.jar
+	tb16.jar,\
+	tb17.jar,\
+	tb18.jar,\
+	tb19.jar,\
+	tb20.jar
 
 # Don't forget that we had to coax the `maven-jar-plugin` NOT to include the `sub-bundle` packages in
 # the root bundle:
diff --git a/cdi-itests/bnd/tb17.bnd b/cdi-itests/bnd/tb17.bnd
new file mode 100644
index 0000000..cd800e9
--- /dev/null
+++ b/cdi-itests/bnd/tb17.bnd
@@ -0,0 +1,14 @@
+#    Licensed 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.
+
+Export-Package: ${p}.tb17.*;-split-package:=first
+-includeresource: META-INF/beans.xml=bnd/tb17.xml
\ No newline at end of file
diff --git a/cdi-itests/bnd/tb17.xml b/cdi-itests/bnd/tb17.xml
new file mode 100644
index 0000000..0602e2a
--- /dev/null
+++ b/cdi-itests/bnd/tb17.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+/**
+ * Licensed 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.
+ */
+-->
+
+<beans
+	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="
+		http://xmlns.jcp.org/xml/ns/javaee
+		http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
+	bean-discovery-mode="all" version="2.0">
+
+	<trim/>
+</beans>
\ No newline at end of file
diff --git a/cdi-itests/bnd/tb18.bnd b/cdi-itests/bnd/tb18.bnd
new file mode 100644
index 0000000..1c2e6c2
--- /dev/null
+++ b/cdi-itests/bnd/tb18.bnd
@@ -0,0 +1,15 @@
+#    Licensed 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.
+
+Export-Package: ${p}.tb18.*;-split-package:=first
+-includeresource: META-INF/beans.xml=bnd/tb18.xml
+-cdiannotations: *;discover=all
\ No newline at end of file
diff --git a/cdi-itests/bnd/tb18.xml b/cdi-itests/bnd/tb18.xml
new file mode 100644
index 0000000..d9f0a3f
--- /dev/null
+++ b/cdi-itests/bnd/tb18.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+/**
+ * Licensed 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.
+ */
+-->
+
+<beans
+	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="
+		http://xmlns.jcp.org/xml/ns/javaee
+		http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
+	bean-discovery-mode="all" version="2.0">
+
+	<scan>
+		<exclude name="org.apache.aries.cdi.test.tb18.B" />
+
+		<exclude name="org.apache.aries.cdi.test.tb18.pA.**" />
+
+		<exclude name="org.apache.aries.cdi.test.tb18.pB.*" />
+	</scan>
+</beans>
\ No newline at end of file
diff --git a/cdi-itests/bnd/tb19.bnd b/cdi-itests/bnd/tb19.bnd
new file mode 100644
index 0000000..aa9f63a
--- /dev/null
+++ b/cdi-itests/bnd/tb19.bnd
@@ -0,0 +1,15 @@
+#    Licensed 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.
+
+Export-Package: ${p}.tb19.*;-split-package:=first
+-includeresource: META-INF/beans.xml=bnd/tb19.xml
+-cdiannotations: *;discover=all
\ No newline at end of file
diff --git a/cdi-itests/bnd/tb19.xml b/cdi-itests/bnd/tb19.xml
new file mode 100644
index 0000000..ab2a051
--- /dev/null
+++ b/cdi-itests/bnd/tb19.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+/**
+ * Licensed 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.
+ */
+-->
+
+<beans
+	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="
+		http://xmlns.jcp.org/xml/ns/javaee
+		http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
+	bean-discovery-mode="all" version="2.0">
+
+	<scan>
+		<exclude name="org.apache.aries.cdi.test.tb19.A">
+			<if-class-not-available name="com.foo.Bar"/>
+		</exclude>
+		<exclude name="org.apache.aries.cdi.test.tb19.B">
+			<if-class-not-available name="com.foo.Bar"/>
+		</exclude>
+		<exclude name="org.apache.aries.cdi.test.tb19.C">
+			<if-class-available name="org.osgi.service.cdi.annotations.Service"/>
+		</exclude>
+	</scan>
+</beans>
\ No newline at end of file
diff --git a/cdi-itests/bnd/tb20.bnd b/cdi-itests/bnd/tb20.bnd
new file mode 100644
index 0000000..67ec8e3
--- /dev/null
+++ b/cdi-itests/bnd/tb20.bnd
@@ -0,0 +1,15 @@
+#    Licensed 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.
+
+Export-Package: ${p}.tb20.*;-split-package:=first
+-includeresource: META-INF/beans.xml=bnd/tb20.xml
+-cdiannotations: *;discover=all
\ No newline at end of file
diff --git a/cdi-itests/bnd/tb20.xml b/cdi-itests/bnd/tb20.xml
new file mode 100644
index 0000000..4653be4
--- /dev/null
+++ b/cdi-itests/bnd/tb20.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+/**
+ * Licensed 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.
+ */
+-->
+
+<beans
+	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="
+		http://xmlns.jcp.org/xml/ns/javaee
+		http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
+	bean-discovery-mode="all" version="2.0">
+
+	<scan>
+		<exclude name="org.apache.aries.cdi.test.tb20.A">
+			<if-system-property name="test.property.a" value="blah" />
+		</exclude>
+
+		<exclude name="org.apache.aries.cdi.test.tb20.B">
+			<if-system-property name="test.property.b" />
+		</exclude>
+
+		<exclude name="org.apache.aries.cdi.test.tb20.C">
+			<if-system-property name="test.property.c" value="bar" />
+		</exclude>
+	</scan>
+</beans>
\ No newline at end of file
diff --git a/cdi-itests/pom.xml b/cdi-itests/pom.xml
index 9697bb8..9534981 100644
--- a/cdi-itests/pom.xml
+++ b/cdi-itests/pom.xml
@@ -81,6 +81,10 @@
 		</dependency>
 		<dependency>
 			<groupId>org.apache.geronimo.specs</groupId>
+			<artifactId>geronimo-interceptor_1.2_spec</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.geronimo.specs</groupId>
 			<artifactId>geronimo-jcdi_2.0_spec</artifactId>
 		</dependency>
 		<dependency>
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/cases/ExcludeTests.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/cases/ExcludeTests.java
new file mode 100644
index 0000000..6e73fa1
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/cases/ExcludeTests.java
@@ -0,0 +1,112 @@
+/**
+ * Licensed 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.aries.cdi.test.cases;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.service.cdi.runtime.CDIComponentRuntime;
+import org.osgi.service.cdi.runtime.dto.ContainerDTO;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class ExcludeTests extends AbstractTestCase {
+
+	@BeforeClass
+	public static void beforeClass() throws Exception {
+		runtimeTracker = new ServiceTracker<>(
+				bundleContext, CDIComponentRuntime.class, null);
+		runtimeTracker.open();
+	}
+
+	@AfterClass
+	public static void afterClass() throws Exception {
+		runtimeTracker.close();
+	}
+
+	@Override
+	@Before
+	public void setUp() throws Exception {
+		cdiRuntime = runtimeTracker.waitForService(timeout);
+	}
+
+	@Override
+	@After
+	public void tearDown() throws Exception {
+	}
+
+	@Test
+	public void testExclude_ByName() throws Exception {
+		Bundle tb2Bundle = installBundle("tb18.jar", false);
+
+		tb2Bundle.start();
+
+		try {
+			ContainerDTO containerDTO = getContainerDTO(cdiRuntime, tb2Bundle);
+			assertNotNull(containerDTO);
+
+			assertEquals(1, containerDTO.template.components.size());
+
+			assertEquals(3, containerDTO.template.components.get(0).beans.size());
+		}
+		finally {
+			tb2Bundle.uninstall();
+		}
+	}
+
+	@Test
+	public void testExclude_IfClassAvailable() throws Exception {
+		Bundle tb2Bundle = installBundle("tb19.jar", false);
+
+		tb2Bundle.start();
+
+		try {
+			ContainerDTO containerDTO = getContainerDTO(cdiRuntime, tb2Bundle);
+			assertNotNull(containerDTO);
+
+			assertEquals(1, containerDTO.template.components.size());
+
+			assertEquals(1, containerDTO.template.components.get(0).beans.size());
+		}
+		finally {
+			tb2Bundle.uninstall();
+		}
+	}
+
+	@Test
+	public void testExclude_IfSystemProperty() throws Exception {
+		Bundle tb2Bundle = installBundle("tb20.jar", false);
+
+		tb2Bundle.start();
+
+		try {
+			ContainerDTO containerDTO = getContainerDTO(cdiRuntime, tb2Bundle);
+			assertNotNull(containerDTO);
+
+			assertEquals(1, containerDTO.template.components.size());
+
+			assertEquals(2, containerDTO.template.components.get(0).beans.size());
+		}
+		finally {
+			tb2Bundle.uninstall();
+		}
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/cases/TrimTests.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/cases/TrimTests.java
new file mode 100644
index 0000000..0a054b4
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/cases/TrimTests.java
@@ -0,0 +1,76 @@
+/**
+ * Licensed 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.aries.cdi.test.cases;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.service.cdi.runtime.CDIComponentRuntime;
+import org.osgi.service.cdi.runtime.dto.ContainerDTO;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class TrimTests extends AbstractTestCase {
+
+	@BeforeClass
+	public static void beforeClass() throws Exception {
+		runtimeTracker = new ServiceTracker<>(
+				bundleContext, CDIComponentRuntime.class, null);
+		runtimeTracker.open();
+	}
+
+	@AfterClass
+	public static void afterClass() throws Exception {
+		runtimeTracker.close();
+	}
+
+	@Override
+	@Before
+	public void setUp() throws Exception {
+		cdiRuntime = runtimeTracker.waitForService(timeout);
+	}
+
+	@Override
+	@After
+	public void tearDown() throws Exception {
+	}
+
+	@Test
+	public void testTrimmed() throws Exception {
+		Bundle tb2Bundle = installBundle("tb17.jar", false);
+
+		tb2Bundle.start();
+
+		try {
+			ContainerDTO containerDTO = getContainerDTO(cdiRuntime, tb2Bundle);
+			assertNotNull(containerDTO);
+
+			assertEquals(5, containerDTO.template.components.get(0).beans.size());
+
+			assertEquals(2, containerDTO.template.components.size());
+
+			assertEquals(2, containerDTO.template.components.get(1).beans.size());
+		}
+		finally {
+			tb2Bundle.uninstall();
+		}
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/A.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/A.java
new file mode 100644
index 0000000..463d105
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/A.java
@@ -0,0 +1,19 @@
+package org.apache.aries.cdi.test.tb17;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+import org.osgi.service.cdi.annotations.Service;
+
+@Service
+public class A implements Pojo {
+
+	@Override
+	public String foo(String fooInput) {
+		return "A" + fooInput;
+	}
+
+	@Override
+	public int getCount() {
+		return 1;
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/B.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/B.java
new file mode 100644
index 0000000..0dd89e6
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/B.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed 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.aries.cdi.test.tb17;
+
+import javax.enterprise.context.Dependent;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+import org.osgi.service.cdi.annotations.Service;
+
+@Dependent
+@Service
+public class B implements Pojo {
+
+	@Override
+	public String foo(String fooInput) {
+		return "B" + fooInput;
+	}
+
+	@Override
+	public int getCount() {
+		return 1;
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/C.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/C.java
new file mode 100644
index 0000000..2b267c3
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/C.java
@@ -0,0 +1,21 @@
+package org.apache.aries.cdi.test.tb17;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+import org.osgi.service.cdi.annotations.Service;
+import org.osgi.service.cdi.annotations.SingleComponent;
+
+@Service
+@SingleComponent
+public class C implements Pojo {
+
+	@Override
+	public String foo(String fooInput) {
+		return "C" + fooInput;
+	}
+
+	@Override
+	public int getCount() {
+		return 1;
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/D.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/D.java
new file mode 100644
index 0000000..1193d22
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/D.java
@@ -0,0 +1,19 @@
+package org.apache.aries.cdi.test.tb17;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+import org.osgi.service.cdi.annotations.ComponentScoped;
+
+@ComponentScoped
+public class D implements Pojo {
+
+	@Override
+	public String foo(String fooInput) {
+		return "D" + fooInput;
+	}
+
+	@Override
+	public int getCount() {
+		return 1;
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/E.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/E.java
new file mode 100644
index 0000000..b378b98
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/E.java
@@ -0,0 +1,20 @@
+package org.apache.aries.cdi.test.tb17;
+
+import javax.enterprise.context.ApplicationScoped;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+
+@ApplicationScoped
+public class E implements Pojo {
+
+	@Override
+	public String foo(String fooInput) {
+		return "E" + fooInput;
+	}
+
+	@Override
+	public int getCount() {
+		return 1;
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/F.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/F.java
new file mode 100644
index 0000000..f331996
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/F.java
@@ -0,0 +1,25 @@
+package org.apache.aries.cdi.test.tb17;
+
+import javax.decorator.Decorator;
+import javax.decorator.Delegate;
+import javax.inject.Inject;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+import org.osgi.service.cdi.annotations.Reference;
+
+@Decorator
+public class F implements Pojo {
+
+	@Inject @Delegate @Reference Pojo pojo;
+
+	@Override
+	public String foo(String fooInput) {
+		return "F" + pojo.foo(fooInput);
+	}
+
+	@Override
+	public int getCount() {
+		return pojo.getCount();
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/G.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/G.java
new file mode 100644
index 0000000..6488d05
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/G.java
@@ -0,0 +1,20 @@
+package org.apache.aries.cdi.test.tb17;
+
+import javax.enterprise.context.ConversationScoped;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+
+@ConversationScoped
+public class G implements Pojo {
+
+	@Override
+	public String foo(String fooInput) {
+		return "G" + fooInput;
+	}
+
+	@Override
+	public int getCount() {
+		return 0;
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/H.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/H.java
new file mode 100644
index 0000000..d3d6f1e
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/H.java
@@ -0,0 +1,27 @@
+package org.apache.aries.cdi.test.tb17;
+
+import javax.inject.Inject;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+import org.osgi.service.log.Logger;
+
+@Interceptor
+public class H {
+
+	@Inject Logger log;
+	@Inject Pojo pojo;
+
+	@AroundInvoke
+	public Object authorize(InvocationContext ic) throws Exception {
+		if (pojo.getCount() > 0) {
+			log.debug("Pojo Count {}", pojo.getCount());
+		}
+		else {
+			log.debug("Pojo has no count");
+		}
+		return ic.proceed();
+	}
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/package-info.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/package-info.java
new file mode 100644
index 0000000..2558a7e
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb17/package-info.java
@@ -0,0 +1,16 @@
+/**
+ * Licensed 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.osgi.service.cdi.annotations.Beans
+package org.apache.aries.cdi.test.tb17;
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/A.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/A.java
new file mode 100644
index 0000000..89dad56
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/A.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed 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.aries.cdi.test.tb18;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+import org.osgi.service.cdi.annotations.Service;
+
+@Service
+public class A implements Pojo {
+
+	@Override
+	public String foo(String input) {
+		return "A" + input;
+	}
+
+	@Override
+	public int getCount() {
+		return 0;
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/B.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/B.java
new file mode 100644
index 0000000..33e8aec
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/B.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed 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.aries.cdi.test.tb18;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+import org.osgi.service.cdi.annotations.Service;
+
+@Service
+public class B implements Pojo {
+
+	@Override
+	public String foo(String input) {
+		return "B" + input;
+	}
+
+	@Override
+	public int getCount() {
+		return 0;
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/pA/C.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/pA/C.java
new file mode 100644
index 0000000..5aeb4f9
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/pA/C.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed 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.aries.cdi.test.tb18.pA;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+import org.osgi.service.cdi.annotations.Service;
+
+@Service
+public class C implements Pojo {
+
+	@Override
+	public String foo(String input) {
+		return "A" + input;
+	}
+
+	@Override
+	public int getCount() {
+		return 0;
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/pA/D.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/pA/D.java
new file mode 100644
index 0000000..5496a17
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/pA/D.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed 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.aries.cdi.test.tb18.pA;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+import org.osgi.service.cdi.annotations.Service;
+
+@Service
+public class D implements Pojo {
+
+	@Override
+	public String foo(String input) {
+		return "A" + input;
+	}
+
+	@Override
+	public int getCount() {
+		return 0;
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/pA/pAA/E.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/pA/pAA/E.java
new file mode 100644
index 0000000..25c1777
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/pA/pAA/E.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed 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.aries.cdi.test.tb18.pA.pAA;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+import org.osgi.service.cdi.annotations.Service;
+
+@Service
+public class E implements Pojo {
+
+	@Override
+	public String foo(String input) {
+		return "A" + input;
+	}
+
+	@Override
+	public int getCount() {
+		return 0;
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/pA/pAA/F.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/pA/pAA/F.java
new file mode 100644
index 0000000..f8d4d27
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/pA/pAA/F.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed 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.aries.cdi.test.tb18.pA.pAA;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+import org.osgi.service.cdi.annotations.Service;
+
+@Service
+public class F implements Pojo {
+
+	@Override
+	public String foo(String input) {
+		return "A" + input;
+	}
+
+	@Override
+	public int getCount() {
+		return 0;
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/pB/C.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/pB/C.java
new file mode 100644
index 0000000..598a0d8
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/pB/C.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed 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.aries.cdi.test.tb18.pB;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+import org.osgi.service.cdi.annotations.Service;
+
+@Service
+public class C implements Pojo {
+
+	@Override
+	public String foo(String input) {
+		return "A" + input;
+	}
+
+	@Override
+	public int getCount() {
+		return 0;
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/pB/D.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/pB/D.java
new file mode 100644
index 0000000..ca071a9
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/pB/D.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed 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.aries.cdi.test.tb18.pB;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+import org.osgi.service.cdi.annotations.Service;
+
+@Service
+public class D implements Pojo {
+
+	@Override
+	public String foo(String input) {
+		return "A" + input;
+	}
+
+	@Override
+	public int getCount() {
+		return 0;
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/pB/pBB/E.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/pB/pBB/E.java
new file mode 100644
index 0000000..d6b82cd
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/pB/pBB/E.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed 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.aries.cdi.test.tb18.pB.pBB;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+import org.osgi.service.cdi.annotations.Service;
+
+@Service
+public class E implements Pojo {
+
+	@Override
+	public String foo(String input) {
+		return "A" + input;
+	}
+
+	@Override
+	public int getCount() {
+		return 0;
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/pB/pBB/F.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/pB/pBB/F.java
new file mode 100644
index 0000000..1622925
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb18/pB/pBB/F.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed 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.aries.cdi.test.tb18.pB.pBB;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+import org.osgi.service.cdi.annotations.Service;
+
+@Service
+public class F implements Pojo {
+
+	@Override
+	public String foo(String input) {
+		return "A" + input;
+	}
+
+	@Override
+	public int getCount() {
+		return 0;
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb19/A.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb19/A.java
new file mode 100644
index 0000000..fa75bbe
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb19/A.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed 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.aries.cdi.test.tb19;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+import org.osgi.service.cdi.annotations.Service;
+
+@Service
+public class A implements Pojo {
+
+	@Override
+	public String foo(String input) {
+		return "A" + input;
+	}
+
+	@Override
+	public int getCount() {
+		return 0;
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb19/B.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb19/B.java
new file mode 100644
index 0000000..71af86b
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb19/B.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed 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.aries.cdi.test.tb19;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+import org.osgi.service.cdi.annotations.Service;
+
+@Service
+public class B implements Pojo {
+
+	@Override
+	public String foo(String input) {
+		return "B" + input;
+	}
+
+	@Override
+	public int getCount() {
+		return 0;
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb19/C.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb19/C.java
new file mode 100644
index 0000000..91236f6
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb19/C.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed 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.aries.cdi.test.tb19;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+import org.osgi.service.cdi.annotations.Service;
+
+@Service
+public class C implements Pojo {
+
+	@Override
+	public String foo(String input) {
+		return "B" + input;
+	}
+
+	@Override
+	public int getCount() {
+		return 0;
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb19/D.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb19/D.java
new file mode 100644
index 0000000..11106ee
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb19/D.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed 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.aries.cdi.test.tb19;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+import org.osgi.service.cdi.annotations.Service;
+
+@Service
+public class D implements Pojo {
+
+	@Override
+	public String foo(String input) {
+		return "B" + input;
+	}
+
+	@Override
+	public int getCount() {
+		return 0;
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb20/A.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb20/A.java
new file mode 100644
index 0000000..2dd932e
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb20/A.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed 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.aries.cdi.test.tb20;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+import org.osgi.service.cdi.annotations.Service;
+
+@Service
+public class A implements Pojo {
+
+	@Override
+	public String foo(String input) {
+		return "A" + input;
+	}
+
+	@Override
+	public int getCount() {
+		return 0;
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb20/B.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb20/B.java
new file mode 100644
index 0000000..af260a7
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb20/B.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed 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.aries.cdi.test.tb20;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+import org.osgi.service.cdi.annotations.Service;
+
+@Service
+public class B implements Pojo {
+
+	@Override
+	public String foo(String input) {
+		return "B" + input;
+	}
+
+	@Override
+	public int getCount() {
+		return 0;
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb20/C.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb20/C.java
new file mode 100644
index 0000000..8cf6bfd
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb20/C.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed 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.aries.cdi.test.tb20;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+import org.osgi.service.cdi.annotations.Service;
+
+@Service
+public class C implements Pojo {
+
+	@Override
+	public String foo(String input) {
+		return "B" + input;
+	}
+
+	@Override
+	public int getCount() {
+		return 0;
+	}
+
+}
diff --git a/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb20/D.java b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb20/D.java
new file mode 100644
index 0000000..f9bdd20
--- /dev/null
+++ b/cdi-itests/src/main/java/org/apache/aries/cdi/test/tb20/D.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed 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.aries.cdi.test.tb20;
+
+import org.apache.aries.cdi.test.interfaces.Pojo;
+import org.osgi.service.cdi.annotations.Service;
+
+@Service
+public class D implements Pojo {
+
+	@Override
+	public String foo(String input) {
+		return "B" + input;
+	}
+
+	@Override
+	public int getCount() {
+		return 0;
+	}
+
+}